Checkpoint: Ajout de la configuration des champs obligatoires pour le score LLM
Nouvelle fonctionnalité permettant de configurer quels champs sont obligatoires ou optionnels pour atteindre un score de reconnaissance de 100%. Modifications: - Nouvelle table llmFieldsConfig dans la base de données - Routes tRPC pour gérer la configuration (getAll, updateField) - Interface utilisateur dans la page Paramètres avec tableau et cases à cocher - Modification du code d'extraction pour générer dynamiquement l'instruction de score - Initialisation automatique des champs par défaut (supplierName, invoiceNumber, invoiceDate, totalAmount obligatoires) - Tests unitaires pour valider la fonctionnalité L'utilisateur peut maintenant personnaliser quels champs doivent être détectés pour qu'une facture atteigne 100% de score.
This commit is contained in:
@@ -7,4 +7,5 @@ export const ENV = {
|
||||
isProduction: process.env.NODE_ENV === "production",
|
||||
forgeApiUrl: process.env.BUILT_IN_FORGE_API_URL ?? "",
|
||||
forgeApiKey: process.env.BUILT_IN_FORGE_API_KEY ?? "",
|
||||
mistralApiKey: process.env.MISTRAL_API_KEY ?? "",
|
||||
};
|
||||
|
||||
@@ -209,17 +209,32 @@ const normalizeToolChoice = (
|
||||
return toolChoice;
|
||||
};
|
||||
|
||||
const resolveApiUrl = () =>
|
||||
ENV.forgeApiUrl && ENV.forgeApiUrl.trim().length > 0
|
||||
const resolveApiUrl = () => {
|
||||
// If MISTRAL_API_KEY is set, use Mistral API directly
|
||||
if (ENV.mistralApiKey && ENV.mistralApiKey.trim().length > 0) {
|
||||
return "https://api.mistral.ai/v1/chat/completions";
|
||||
}
|
||||
|
||||
// Otherwise use Manus Forge API
|
||||
return ENV.forgeApiUrl && ENV.forgeApiUrl.trim().length > 0
|
||||
? `${ENV.forgeApiUrl.replace(/\/$/, "")}/v1/chat/completions`
|
||||
: "https://forge.manus.im/v1/chat/completions";
|
||||
};
|
||||
|
||||
const assertApiKey = () => {
|
||||
if (!ENV.forgeApiKey) {
|
||||
throw new Error("OPENAI_API_KEY is not configured");
|
||||
if (!ENV.mistralApiKey && !ENV.forgeApiKey) {
|
||||
throw new Error("MISTRAL_API_KEY or OPENAI_API_KEY is not configured");
|
||||
}
|
||||
};
|
||||
|
||||
const getApiKey = () => {
|
||||
// Prioritize MISTRAL_API_KEY if set
|
||||
if (ENV.mistralApiKey && ENV.mistralApiKey.trim().length > 0) {
|
||||
return ENV.mistralApiKey;
|
||||
}
|
||||
return ENV.forgeApiKey;
|
||||
};
|
||||
|
||||
const normalizeResponseFormat = ({
|
||||
responseFormat,
|
||||
response_format,
|
||||
@@ -279,8 +294,13 @@ export async function invokeLLM(params: InvokeParams): Promise<InvokeResult> {
|
||||
response_format,
|
||||
} = params;
|
||||
|
||||
// Use mistral-large-latest when MISTRAL_API_KEY is set, otherwise use gemini
|
||||
const model = ENV.mistralApiKey && ENV.mistralApiKey.trim().length > 0
|
||||
? "mistral-large-latest"
|
||||
: "gemini-2.5-flash";
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
model: "gemini-2.5-flash",
|
||||
model,
|
||||
messages: messages.map(normalizeMessage),
|
||||
};
|
||||
|
||||
@@ -297,8 +317,12 @@ export async function invokeLLM(params: InvokeParams): Promise<InvokeResult> {
|
||||
}
|
||||
|
||||
payload.max_tokens = 32768
|
||||
payload.thinking = {
|
||||
"budget_tokens": 128
|
||||
|
||||
// Only add thinking parameter for Gemini models
|
||||
if (!(ENV.mistralApiKey && ENV.mistralApiKey.trim().length > 0)) {
|
||||
payload.thinking = {
|
||||
"budget_tokens": 128
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedResponseFormat = normalizeResponseFormat({
|
||||
@@ -316,7 +340,7 @@ export async function invokeLLM(params: InvokeParams): Promise<InvokeResult> {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
authorization: `Bearer ${ENV.forgeApiKey}`,
|
||||
authorization: `Bearer ${getApiKey()}`,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user