mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 09:50:15 +01:00
* 👁️ feat: Add Azure Mistral OCR strategy and endpoint integration This commit introduces a new OCR strategy named 'azure_mistral_ocr', allowing the use of a Mistral OCR endpoint deployed on Azure. The configuration, schemas, and file upload strategies have been updated to support this integration, enabling seamless OCR processing via Azure-hosted Mistral services. * 🗑️ chore: Clean up .gitignore by removing commented-out uncommon directory name * chore: remove unused vars * refactor: Move createAxiosInstance to packages/api/utils and update imports - Removed the createAxiosInstance function from the config module and relocated it to a new utils module for better organization. - Updated import paths in relevant files to reflect the new location of createAxiosInstance. - Added tests for createAxiosInstance to ensure proper functionality and proxy configuration handling. * chore: move axios helpers to packages/api - Added logAxiosError function to @librechat/api for centralized error logging. - Updated imports across various files to use the new logAxiosError function. - Removed the old axios.js utility file as it is no longer needed. * chore: Update Jest moduleNameMapper for improved path resolution - Added a new mapping for '~/' to resolve module paths in Jest configuration, enhancing import handling for the project. * feat: Implement Mistral OCR API integration in TS * chore: Update MistralOCR tests based on new imports * fix: Enhance MistralOCR configuration handling and tests - Introduced helper functions for resolving configuration values from environment variables or hardcoded settings. - Updated the uploadMistralOCR and uploadAzureMistralOCR functions to utilize the new configuration resolution logic. - Improved test cases to ensure correct behavior when mixing environment variables and hardcoded values. - Mocked file upload and signed URL responses in tests to validate functionality without external dependencies. * feat: Enhance MistralOCR functionality with improved configuration and error handling - Introduced helper functions for loading authentication configuration and resolving values from environment variables. - Updated uploadMistralOCR and uploadAzureMistralOCR functions to utilize the new configuration logic. - Added utility functions for processing OCR results and creating error messages. - Improved document type determination and result aggregation for better OCR processing. * refactor: Reorganize OCR type imports in Mistral CRUD file - Moved OCRResult, OCRResultPage, and OCRImage imports to a more logical grouping for better readability and maintainability. * feat: Add file exports to API and create files index * chore: Update OCR types for enhanced structure and clarity - Redesigned OCRImage interface to include mandatory fields and improved naming conventions. - Added PageDimensions interface for better representation of page metrics. - Updated OCRResultPage to include dimensions and mandatory images array. - Refined OCRResult to include document annotation and usage information. * refactor: use TS counterpart of uploadOCR methods * ci: Update MistralOCR tests to reflect new OCR result structure * chore: Bump version of @librechat/api to 1.2.3 in package.json and package-lock.json * chore: Update CONFIG_VERSION to 1.2.8 * chore: remove unused sendEvent function from config module (now imported from '@librechat/api') * chore: remove MistralOCR service files and tests (now in '@librechat/api') * ci: update logger import in ModelService tests to use @librechat/data-schemas --------- Co-authored-by: arthurolivierfortin <arthurolivier.fortin@gmail.com>
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import axios from 'axios';
|
|
import { createAxiosInstance } from './axios';
|
|
|
|
jest.mock('axios', () => ({
|
|
interceptors: {
|
|
request: { use: jest.fn(), eject: jest.fn() },
|
|
response: { use: jest.fn(), eject: jest.fn() },
|
|
},
|
|
create: jest.fn().mockReturnValue({
|
|
defaults: {
|
|
proxy: null,
|
|
},
|
|
get: jest.fn().mockResolvedValue({ data: {} }),
|
|
post: jest.fn().mockResolvedValue({ data: {} }),
|
|
put: jest.fn().mockResolvedValue({ data: {} }),
|
|
delete: jest.fn().mockResolvedValue({ data: {} }),
|
|
}),
|
|
get: jest.fn().mockResolvedValue({ data: {} }),
|
|
post: jest.fn().mockResolvedValue({ data: {} }),
|
|
put: jest.fn().mockResolvedValue({ data: {} }),
|
|
delete: jest.fn().mockResolvedValue({ data: {} }),
|
|
reset: jest.fn().mockImplementation(function (this: {
|
|
get: jest.Mock;
|
|
post: jest.Mock;
|
|
put: jest.Mock;
|
|
delete: jest.Mock;
|
|
create: jest.Mock;
|
|
}) {
|
|
this.get.mockClear();
|
|
this.post.mockClear();
|
|
this.put.mockClear();
|
|
this.delete.mockClear();
|
|
this.create.mockClear();
|
|
}),
|
|
}));
|
|
|
|
describe('createAxiosInstance', () => {
|
|
const originalEnv = process.env;
|
|
|
|
beforeEach(() => {
|
|
// Reset mocks
|
|
jest.clearAllMocks();
|
|
// Create a clean copy of process.env
|
|
process.env = { ...originalEnv };
|
|
// Default: no proxy
|
|
delete process.env.proxy;
|
|
});
|
|
|
|
afterAll(() => {
|
|
// Restore original process.env
|
|
process.env = originalEnv;
|
|
});
|
|
|
|
test('creates an axios instance without proxy when no proxy env is set', () => {
|
|
const instance = createAxiosInstance();
|
|
|
|
expect(axios.create).toHaveBeenCalledTimes(1);
|
|
expect(instance.defaults.proxy).toBeNull();
|
|
});
|
|
|
|
test('configures proxy correctly with hostname and protocol', () => {
|
|
process.env.proxy = 'http://example.com';
|
|
|
|
const instance = createAxiosInstance();
|
|
|
|
expect(axios.create).toHaveBeenCalledTimes(1);
|
|
expect(instance.defaults.proxy).toEqual({
|
|
host: 'example.com',
|
|
protocol: 'http',
|
|
});
|
|
});
|
|
|
|
test('configures proxy correctly with hostname, protocol and port', () => {
|
|
process.env.proxy = 'https://proxy.example.com:8080';
|
|
|
|
const instance = createAxiosInstance();
|
|
|
|
expect(axios.create).toHaveBeenCalledTimes(1);
|
|
expect(instance.defaults.proxy).toEqual({
|
|
host: 'proxy.example.com',
|
|
protocol: 'https',
|
|
port: 8080,
|
|
});
|
|
});
|
|
|
|
test('handles proxy URLs with authentication', () => {
|
|
process.env.proxy = 'http://user:pass@proxy.example.com:3128';
|
|
|
|
const instance = createAxiosInstance();
|
|
|
|
expect(axios.create).toHaveBeenCalledTimes(1);
|
|
expect(instance.defaults.proxy).toEqual({
|
|
host: 'proxy.example.com',
|
|
protocol: 'http',
|
|
port: 3128,
|
|
// Note: The current implementation doesn't handle auth - if needed, add this functionality
|
|
});
|
|
});
|
|
|
|
test('throws error when proxy URL is invalid', () => {
|
|
process.env.proxy = 'invalid-url';
|
|
|
|
expect(() => createAxiosInstance()).toThrow('Invalid proxy URL');
|
|
expect(axios.create).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
// If you want to test the actual URL parsing more thoroughly
|
|
test('handles edge case proxy URLs correctly', () => {
|
|
// IPv6 address
|
|
process.env.proxy = 'http://[::1]:8080';
|
|
|
|
let instance = createAxiosInstance();
|
|
|
|
expect(instance.defaults.proxy).toEqual({
|
|
host: '::1',
|
|
protocol: 'http',
|
|
port: 8080,
|
|
});
|
|
|
|
// URL with path (which should be ignored for proxy config)
|
|
process.env.proxy = 'http://proxy.example.com:8080/some/path';
|
|
|
|
instance = createAxiosInstance();
|
|
|
|
expect(instance.defaults.proxy).toEqual({
|
|
host: 'proxy.example.com',
|
|
protocol: 'http',
|
|
port: 8080,
|
|
});
|
|
});
|
|
});
|