Not a Plant Fehlermeldung
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { CareInfo, IdentificationResult, Language } from '../../types';
|
||||
import { BackendApiError } from './contracts';
|
||||
|
||||
type OpenAiScanMode = 'primary' | 'review';
|
||||
|
||||
@@ -164,7 +165,8 @@ const buildPrompt = (language: Language, mode: OpenAiScanMode): string => {
|
||||
|
||||
return [
|
||||
`${reviewInstruction}`,
|
||||
`Return strict JSON only in this shape:`,
|
||||
`If the image does not clearly show a plant (e.g. it shows a person, animal, object, or has no identifiable plant), return {"notAPlant":true} and nothing else.`,
|
||||
`Otherwise return strict JSON only in this shape:`,
|
||||
`{"name":"...","botanicalName":"...","confidence":0.0,"description":"...","careInfo":{"waterIntervalDays":7,"light":"...","temp":"..."}}`,
|
||||
`Rules:`,
|
||||
nameLanguageInstruction,
|
||||
@@ -389,10 +391,37 @@ const extractMessageContent = (payload: unknown): string => {
|
||||
return '';
|
||||
};
|
||||
|
||||
const isReasoningModel = (model: string): boolean => {
|
||||
const normalized = model.toLowerCase();
|
||||
return normalized.startsWith('gpt-5') || normalized.startsWith('o1') || normalized.startsWith('o3') || normalized.startsWith('o4');
|
||||
};
|
||||
|
||||
const buildRequestBody = (
|
||||
model: string,
|
||||
messages: Array<Record<string, unknown>>,
|
||||
maxCompletionTokens: number,
|
||||
): Record<string, unknown> => {
|
||||
const body: Record<string, unknown> = {
|
||||
model,
|
||||
response_format: { type: 'json_object' },
|
||||
messages,
|
||||
};
|
||||
|
||||
if (isReasoningModel(model)) {
|
||||
body.reasoning_effort = 'minimal';
|
||||
body.max_completion_tokens = maxCompletionTokens;
|
||||
} else {
|
||||
body.max_tokens = maxCompletionTokens;
|
||||
}
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
const postChatCompletion = async (
|
||||
modelChain: string[],
|
||||
imageUri: string,
|
||||
messages: Array<Record<string, unknown>>,
|
||||
maxCompletionTokens = 600,
|
||||
): Promise<{ payload: Record<string, unknown> | null; modelUsed: string | null; attemptedModels: string[] }> => {
|
||||
const attemptedModels: string[] = [];
|
||||
|
||||
@@ -408,11 +437,7 @@ const postChatCompletion = async (
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${OPENAI_API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
response_format: { type: 'json_object' },
|
||||
messages,
|
||||
}),
|
||||
body: JSON.stringify(buildRequestBody(model, messages, maxCompletionTokens)),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
@@ -470,10 +495,11 @@ export const openAiScanService = {
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: buildPrompt(language, mode) },
|
||||
{ type: 'image_url', image_url: { url: imageUri } },
|
||||
{ type: 'image_url', image_url: { url: imageUri, detail: 'low' } },
|
||||
],
|
||||
},
|
||||
],
|
||||
600,
|
||||
);
|
||||
|
||||
if (!completion.payload) return null;
|
||||
@@ -498,6 +524,10 @@ export const openAiScanService = {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (parsed.notAPlant === true) {
|
||||
throw new BackendApiError('NOT_A_PLANT', 'Image does not contain a plant.', 422);
|
||||
}
|
||||
|
||||
const normalized = normalizeResult(parsed, language);
|
||||
if (!normalized) {
|
||||
console.warn('OpenAI plant scan JSON did not match required schema.', {
|
||||
@@ -533,10 +563,11 @@ export const openAiScanService = {
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: buildHealthPrompt(language, plantContext) },
|
||||
{ type: 'image_url', image_url: { url: imageUri } },
|
||||
{ type: 'image_url', image_url: { url: imageUri, detail: 'low' } },
|
||||
],
|
||||
},
|
||||
],
|
||||
800,
|
||||
);
|
||||
|
||||
if (!completion.payload) return buildFallbackHealthAnalysis(language, plantContext);
|
||||
|
||||
Reference in New Issue
Block a user