diff --git a/packages/api/src/files/mistral/crud.spec.ts b/packages/api/src/files/mistral/crud.spec.ts index e80e18358e..686188588b 100644 --- a/packages/api/src/files/mistral/crud.spec.ts +++ b/packages/api/src/files/mistral/crud.spec.ts @@ -44,13 +44,12 @@ jest.mock('~/utils/axios', () => ({ import * as fs from 'fs'; import axios from 'axios'; -import type { Request as ExpressRequest } from 'express'; import type { Readable } from 'stream'; import type { MistralFileUploadResponse, MistralSignedUrlResponse, + ServerRequest, OCRResult, - AppConfig, } from '~/types'; import { logger as mockLogger } from '@librechat/data-schemas'; import { @@ -502,16 +501,15 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - // Use environment variable syntax to ensure loadAuthValues is called - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-medium', + config: { + ocr: { + // Use environment variable syntax to ensure loadAuthValues is called + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-medium', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -521,7 +519,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -604,15 +601,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user456' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-medium', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-medium', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/image.png', @@ -622,7 +618,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -703,15 +698,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${CUSTOM_API_KEY}', - baseURL: '${CUSTOM_BASEURL}', - mistralModel: '${CUSTOM_MODEL}', + config: { + ocr: { + apiKey: '${CUSTOM_API_KEY}', + baseURL: '${CUSTOM_BASEURL}', + mistralModel: '${CUSTOM_MODEL}', + }, }, - } as AppConfig; + } as unknown as ServerRequest; // Set environment variable for model process.env.CUSTOM_MODEL = 'mistral-large'; @@ -724,7 +718,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -795,16 +788,15 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - // Use environment variable syntax to ensure loadAuthValues is called - apiKey: '${INVALID_FORMAT}', // Using valid env var format but with an invalid name - baseURL: '${OCR_BASEURL}', // Using valid env var format - mistralModel: 'mistral-ocr-latest', // Plain string value + config: { + ocr: { + // Use environment variable syntax to ensure loadAuthValues is called + apiKey: '${INVALID_FORMAT}', // Using valid env var format but with an invalid name + baseURL: '${OCR_BASEURL}', // Using valid env var format + mistralModel: 'mistral-ocr-latest', // Plain string value + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -814,7 +806,6 @@ describe('MistralOCR Service', () => { await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -850,14 +841,13 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: 'OCR_API_KEY', - baseURL: 'OCR_BASEURL', + config: { + ocr: { + apiKey: 'OCR_API_KEY', + baseURL: 'OCR_BASEURL', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -868,7 +858,6 @@ describe('MistralOCR Service', () => { await expect( uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }), @@ -936,15 +925,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: 'OCR_API_KEY', - baseURL: 'OCR_BASEURL', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: 'OCR_API_KEY', + baseURL: 'OCR_BASEURL', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -954,7 +942,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1024,16 +1011,15 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - // Direct values that should be used as-is, without variable substitution - apiKey: 'actual-api-key-value', - baseURL: 'https://direct-api-url.mistral.ai/v1', - mistralModel: 'mistral-direct-model', + config: { + ocr: { + // Direct values that should be used as-is, without variable substitution + apiKey: 'actual-api-key-value', + baseURL: 'https://direct-api-url.mistral.ai/v1', + mistralModel: 'mistral-direct-model', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1043,7 +1029,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1138,16 +1123,15 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - // Empty string values - should fall back to defaults - apiKey: '', - baseURL: '', - mistralModel: '', + config: { + ocr: { + // Empty string values - should fall back to defaults + apiKey: '', + baseURL: '', + mistralModel: '', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1157,7 +1141,6 @@ describe('MistralOCR Service', () => { const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1281,15 +1264,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${AZURE_MISTRAL_OCR_API_KEY}', - baseURL: 'https://endpoint.models.ai.azure.com/v1', - mistralModel: 'mistral-ocr-2503', + config: { + ocr: { + apiKey: '${AZURE_MISTRAL_OCR_API_KEY}', + baseURL: 'https://endpoint.models.ai.azure.com/v1', + mistralModel: 'mistral-ocr-2503', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1299,7 +1281,6 @@ describe('MistralOCR Service', () => { await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1365,15 +1346,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user456' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: 'hardcoded-api-key-12345', - baseURL: '${CUSTOM_OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: 'hardcoded-api-key-12345', + baseURL: '${CUSTOM_OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1383,7 +1363,6 @@ describe('MistralOCR Service', () => { await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1489,15 +1468,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1507,7 +1485,6 @@ describe('MistralOCR Service', () => { await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1558,15 +1535,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1577,7 +1553,6 @@ describe('MistralOCR Service', () => { await expect( uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }), @@ -1646,15 +1621,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1665,7 +1639,6 @@ describe('MistralOCR Service', () => { // Should not throw even if delete fails const result = await uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1706,15 +1679,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1725,7 +1697,6 @@ describe('MistralOCR Service', () => { await expect( uploadMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }), @@ -1780,15 +1751,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${OCR_API_KEY}', - baseURL: '${OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: '${OCR_API_KEY}', + baseURL: '${OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/azure-file.pdf', @@ -1798,7 +1768,6 @@ describe('MistralOCR Service', () => { const result = await uploadAzureMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1856,15 +1825,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user123' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: '${AZURE_MISTRAL_OCR_API_KEY}', - baseURL: 'https://endpoint.models.ai.azure.com/v1', - mistralModel: 'mistral-ocr-2503', + config: { + ocr: { + apiKey: '${AZURE_MISTRAL_OCR_API_KEY}', + baseURL: 'https://endpoint.models.ai.azure.com/v1', + mistralModel: 'mistral-ocr-2503', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1874,7 +1842,6 @@ describe('MistralOCR Service', () => { await uploadAzureMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); @@ -1920,15 +1887,14 @@ describe('MistralOCR Service', () => { const req = { user: { id: 'user456' }, - } as unknown as ExpressRequest; - - const appConfig = { - ocr: { - apiKey: 'hardcoded-api-key-12345', - baseURL: '${CUSTOM_OCR_BASEURL}', - mistralModel: 'mistral-ocr-latest', + config: { + ocr: { + apiKey: 'hardcoded-api-key-12345', + baseURL: '${CUSTOM_OCR_BASEURL}', + mistralModel: 'mistral-ocr-latest', + }, }, - } as AppConfig; + } as unknown as ServerRequest; const file = { path: '/tmp/upload/file.pdf', @@ -1938,7 +1904,6 @@ describe('MistralOCR Service', () => { await uploadAzureMistralOCR({ req, - appConfig, file, loadAuthValues: mockLoadAuthValues, }); diff --git a/packages/api/src/files/mistral/crud.ts b/packages/api/src/files/mistral/crud.ts index 5f93895472..30e5ebbf5c 100644 --- a/packages/api/src/files/mistral/crud.ts +++ b/packages/api/src/files/mistral/crud.ts @@ -9,7 +9,6 @@ import { extractVariableName, } from 'librechat-data-provider'; import type { TCustomConfig } from 'librechat-data-provider'; -import type { Request as ServerRequest } from 'express'; import type { AxiosError } from 'axios'; import type { MistralFileUploadResponse, @@ -17,7 +16,7 @@ import type { MistralOCRUploadResult, MistralOCRError, OCRResultPage, - AppConfig, + ServerRequest, OCRResult, OCRImage, } from '~/types'; @@ -43,10 +42,7 @@ interface GoogleServiceAccount { /** Helper type for OCR request context */ interface OCRContext { - req: Pick & { - user?: { id: string }; - }; - appConfig: AppConfig; + req: ServerRequest; file: Express.Multer.File; loadAuthValues: (params: { userId: string; @@ -238,7 +234,8 @@ async function resolveConfigValue( * Loads authentication configuration from OCR config */ async function loadAuthConfig(context: OCRContext): Promise { - const ocrConfig = context.appConfig?.ocr; + const appConfig = context.req.config; + const ocrConfig = appConfig?.ocr; const apiKeyConfig = ocrConfig?.apiKey || ''; const baseURLConfig = ocrConfig?.baseURL || ''; @@ -354,7 +351,6 @@ function createOCRError(error: unknown, baseMessage: string): Error { * @param params - The params object. * @param params.req - The request object from Express. It should have a `user` property with an `id` * representing the user - * @param params.appConfig - Application configuration object * @param params.file - The file object, which is part of the request. The file object should * have a `mimetype` property that tells us the file type * @param params.loadAuthValues - Function to load authentication values @@ -370,7 +366,7 @@ export const uploadMistralOCR = async (context: OCRContext): Promise => { try { const { apiKey, baseURL } = await loadAuthConfig(context); - const model = getModelConfig(context.appConfig?.ocr); + const model = getModelConfig(context.req.config?.ocr); const buffer = fs.readFileSync(context.file.path); const base64 = buffer.toString('base64'); @@ -655,7 +651,7 @@ export const uploadGoogleVertexMistralOCR = async ( ): Promise => { try { const { serviceAccount, accessToken } = await loadGoogleAuthConfig(); - const model = getModelConfig(context.appConfig?.ocr); + const model = getModelConfig(context.req.config?.ocr); const buffer = fs.readFileSync(context.file.path); const base64 = buffer.toString('base64');