Improve AI model compatibility warnings and error handling
Add detection for OpenAI models that only support v1/responses and are not compatible with chat completions, providing user-friendly warnings during model selection and clearer error messages upon connection testing or AI analysis execution. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 0d01f99a-ea6a-447d-82fd-311715434a39 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: ac489071-6c6a-4584-9740-76bf6ca16040 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e32d2b99-1721-47dd-833c-98b372f48008/0d01f99a-ea6a-447d-82fd-311715434a39/upEITG1 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
1451ce790f
commit
29853219bc
6 changed files with 32 additions and 1 deletions
|
|
@ -137,6 +137,12 @@ async function callOpenAiCompatible(
|
|||
});
|
||||
if (!res.ok) {
|
||||
const body = await res.text();
|
||||
if (body.includes("v1/responses")) {
|
||||
throw new Error(
|
||||
`Das Modell "${provider.model}" unterstützt nur /v1/responses, nicht /v1/chat/completions. ` +
|
||||
`Bitte wählen Sie ein Chat-kompatibles Modell (z.\u202fB. gpt-4o, gpt-4-turbo, gpt-3.5-turbo).`,
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`HTTP ${res.status}: ${redactSecrets(body.slice(0, 300), provider.apiToken)}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export default {
|
|||
noneFoundTried: "Keine Modelle gefunden – bitte das Modell manuell eingeben.",
|
||||
noneFoundHint:
|
||||
"Testen Sie die Verbindung, um verfügbare Modelle automatisch zu laden, oder geben Sie das Modell manuell ein.",
|
||||
responsesOnlyWarning:
|
||||
"Dieses Modell unterstützt nur /v1/responses, nicht /v1/chat/completions. Die KI-Analyse wird fehlschlagen. Bitte wählen Sie ein Chat-kompatibles Modell (z.\u202fB. gpt-4o, gpt-4-turbo).",
|
||||
},
|
||||
providers: {
|
||||
heading: "KI-Provider",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export default {
|
|||
noneFoundTried: "No models found – please enter the model manually.",
|
||||
noneFoundHint:
|
||||
"Test the connection to load available models automatically, or enter the model manually.",
|
||||
responsesOnlyWarning:
|
||||
"This model only supports /v1/responses, not /v1/chat/completions. AI analysis will fail. Please choose a chat-compatible model (e.g. gpt-4o, gpt-4-turbo).",
|
||||
},
|
||||
providers: {
|
||||
heading: "AI providers",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export default {
|
|||
noneFoundTried: "No se encontraron modelos: introduzca el modelo manualmente.",
|
||||
noneFoundHint:
|
||||
"Pruebe la conexión para cargar automáticamente los modelos disponibles, o introduzca el modelo manualmente.",
|
||||
responsesOnlyWarning:
|
||||
"Este modelo solo admite /v1/responses, no /v1/chat/completions. El análisis de IA fallará. Seleccione un modelo compatible con chat (p.\u202fej. gpt-4o, gpt-4-turbo).",
|
||||
},
|
||||
providers: {
|
||||
heading: "Proveedores de IA",
|
||||
|
|
|
|||
|
|
@ -42,14 +42,29 @@ const PROVIDER_PRESETS: Partial<Record<AiProviderApiType, ProviderPreset[]>> = {
|
|||
],
|
||||
};
|
||||
|
||||
function ModelField({ models, loading, tried, value, onChange }: {
|
||||
const RESPONSES_ONLY_RE = /^o\d/i;
|
||||
|
||||
function isResponsesOnlyModel(model: string, apiType: string): boolean {
|
||||
return apiType === "openai" && RESPONSES_ONLY_RE.test(model.trim());
|
||||
}
|
||||
|
||||
function ModelField({ models, loading, tried, value, onChange, apiType }: {
|
||||
models: string[];
|
||||
loading: boolean;
|
||||
tried: boolean;
|
||||
value: string;
|
||||
onChange: (v: string) => void;
|
||||
apiType: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const warnResponsesOnly = value && isResponsesOnlyModel(value, apiType);
|
||||
|
||||
const warning = warnResponsesOnly ? (
|
||||
<p className="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-2 py-1.5">
|
||||
{t("admin.modelField.responsesOnlyWarning")}
|
||||
</p>
|
||||
) : null;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="grid gap-2">
|
||||
|
|
@ -71,6 +86,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
|
|||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground">{t("admin.modelField.found", { count: models.length })}</p>
|
||||
{warning}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -83,6 +99,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
|
|||
? t("admin.modelField.noneFoundTried")
|
||||
: t("admin.modelField.noneFoundHint")}
|
||||
</p>
|
||||
{warning}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -368,6 +385,7 @@ function ProviderTab() {
|
|||
models={addModels}
|
||||
loading={addModelsLoading}
|
||||
tried={addModelsTried}
|
||||
apiType={addForm.apiType}
|
||||
value={addForm.model}
|
||||
onChange={(v) => setAddForm(f => ({ ...f, model: v }))}
|
||||
/>
|
||||
|
|
@ -498,6 +516,7 @@ function ProviderTab() {
|
|||
models={editModels}
|
||||
loading={editModelsLoading}
|
||||
tried={editModelsTried}
|
||||
apiType={editForm.apiType}
|
||||
value={editForm.model}
|
||||
onChange={(v) => setEditForm(f => ({ ...f, model: v }))}
|
||||
/>
|
||||
|
|
|
|||
BIN
attached_assets/image_1781645514678.png
Normal file
BIN
attached_assets/image_1781645514678.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Loading…
Add table
Reference in a new issue