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) {
|
if (!res.ok) {
|
||||||
const body = await res.text();
|
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(
|
throw new Error(
|
||||||
`HTTP ${res.status}: ${redactSecrets(body.slice(0, 300), provider.apiToken)}`,
|
`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.",
|
noneFoundTried: "Keine Modelle gefunden – bitte das Modell manuell eingeben.",
|
||||||
noneFoundHint:
|
noneFoundHint:
|
||||||
"Testen Sie die Verbindung, um verfügbare Modelle automatisch zu laden, oder geben Sie das Modell manuell ein.",
|
"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: {
|
providers: {
|
||||||
heading: "KI-Provider",
|
heading: "KI-Provider",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export default {
|
||||||
noneFoundTried: "No models found – please enter the model manually.",
|
noneFoundTried: "No models found – please enter the model manually.",
|
||||||
noneFoundHint:
|
noneFoundHint:
|
||||||
"Test the connection to load available models automatically, or enter the model manually.",
|
"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: {
|
providers: {
|
||||||
heading: "AI providers",
|
heading: "AI providers",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export default {
|
||||||
noneFoundTried: "No se encontraron modelos: introduzca el modelo manualmente.",
|
noneFoundTried: "No se encontraron modelos: introduzca el modelo manualmente.",
|
||||||
noneFoundHint:
|
noneFoundHint:
|
||||||
"Pruebe la conexión para cargar automáticamente los modelos disponibles, o introduzca el modelo manualmente.",
|
"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: {
|
providers: {
|
||||||
heading: "Proveedores de IA",
|
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[];
|
models: string[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
tried: boolean;
|
tried: boolean;
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (v: string) => void;
|
onChange: (v: string) => void;
|
||||||
|
apiType: string;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
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) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
|
|
@ -71,6 +86,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<p className="text-xs text-muted-foreground">{t("admin.modelField.found", { count: models.length })}</p>
|
<p className="text-xs text-muted-foreground">{t("admin.modelField.found", { count: models.length })}</p>
|
||||||
|
{warning}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +99,7 @@ function ModelField({ models, loading, tried, value, onChange }: {
|
||||||
? t("admin.modelField.noneFoundTried")
|
? t("admin.modelField.noneFoundTried")
|
||||||
: t("admin.modelField.noneFoundHint")}
|
: t("admin.modelField.noneFoundHint")}
|
||||||
</p>
|
</p>
|
||||||
|
{warning}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -368,6 +385,7 @@ function ProviderTab() {
|
||||||
models={addModels}
|
models={addModels}
|
||||||
loading={addModelsLoading}
|
loading={addModelsLoading}
|
||||||
tried={addModelsTried}
|
tried={addModelsTried}
|
||||||
|
apiType={addForm.apiType}
|
||||||
value={addForm.model}
|
value={addForm.model}
|
||||||
onChange={(v) => setAddForm(f => ({ ...f, model: v }))}
|
onChange={(v) => setAddForm(f => ({ ...f, model: v }))}
|
||||||
/>
|
/>
|
||||||
|
|
@ -498,6 +516,7 @@ function ProviderTab() {
|
||||||
models={editModels}
|
models={editModels}
|
||||||
loading={editModelsLoading}
|
loading={editModelsLoading}
|
||||||
tried={editModelsTried}
|
tried={editModelsTried}
|
||||||
|
apiType={editForm.apiType}
|
||||||
value={editForm.model}
|
value={editForm.model}
|
||||||
onChange={(v) => setEditForm(f => ({ ...f, model: v }))}
|
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