Skip to main content
Glama
meta-guy-analysis.test.ts18.6 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { readFile } from 'fs/promises'; import { join } from 'path'; import { ImageProcessor } from '../../src/utils/image-processor.js'; import { OpenRouterClient } from '../../src/utils/openrouter-client.js'; import { Logger } from '../../src/utils/logger.js'; describe('Meta Guy Image Analysis Tests', () => { let imageProcessor: ImageProcessor; let mockOpenRouterClient: OpenRouterClient; let metaGuyImageBuffer: Buffer; let metaGuyBase64: string; beforeEach(async () => { // Mock logger to avoid console output during tests vi.mock('../../src/utils/logger.js', () => ({ Logger: { getInstance: vi.fn(() => ({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), })), }, })); // Get singleton instances const logger = Logger.getInstance(); imageProcessor = ImageProcessor.getInstance(); // Load the meta_guy.jpg image for testing try { const imagePath = join(process.cwd(), 'meta_guy.jpg'); metaGuyImageBuffer = await readFile(imagePath); metaGuyBase64 = metaGuyImageBuffer.toString('base64'); console.log(`Loaded meta_guy.jpg: ${metaGuyImageBuffer.length} bytes`); } catch (error) { console.warn('Could not load meta_guy.jpg for testing, using mock data'); // Create a minimal test image buffer if the actual file doesn't exist metaGuyBase64 = '/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAP//////////////////////////////////////////////////////////////////////////////////////wgALCAABAAEBAREA/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPxA='; // Minimal JPEG } // Mock OpenRouter client mockOpenRouterClient = { analyzeImage: vi.fn(), testConnection: vi.fn().mockResolvedValue(true), validateModel: vi.fn().mockResolvedValue(true), } as any; vi.mock('../../src/utils/openrouter-client.js', () => ({ OpenRouterClient: { getInstance: vi.fn(() => mockOpenRouterClient), }, })); }); afterEach(() => { vi.resetAllMocks(); }); describe('Image Processing', () => { it('should process meta_guy.jpg from file path', async () => { // Skip file test if image doesn't exist if (metaGuyImageBuffer.length === 0) { console.log('Skipping file test - meta_guy.jpg not available'); return; } try { const result = await imageProcessor.processImage({ type: 'file', data: 'meta_guy.jpg', }); expect(result).toHaveProperty('data'); expect(result).toHaveProperty('mimeType'); expect(result).toHaveProperty('size'); expect(typeof result.data).toBe('string'); expect(typeof result.size).toBe('number'); expect(result.size).toBeGreaterThan(0); expect(imageProcessor.isValidImageType(result.mimeType)).toBe(true); } catch (error) { // File might not exist in test environment, which is okay console.log('File processing test skipped - file not found in test environment'); } }); it('should process meta_guy.jpg from base64 data', async () => { const result = await imageProcessor.processImage({ type: 'base64', data: metaGuyBase64, mimeType: 'image/jpeg', }); expect(result.data).toBe(metaGuyBase64); expect(result.mimeType).toBe('image/jpeg'); expect(result.size).toBeGreaterThan(0); }); it('should auto-detect MIME type for meta_guy.jpg base64', async () => { const result = await imageProcessor.processImage({ type: 'base64', data: metaGuyBase64, }); expect(result.mimeType).toBe('image/jpeg'); expect(imageProcessor.isValidImageType(result.mimeType)).toBe(true); }); it('should handle data URL format for meta_guy.jpg', async () => { const dataUrl = `data:image/jpeg;base64,${metaGuyBase64}`; const result = await imageProcessor.processImage({ type: 'base64', data: dataUrl, }); expect(result.data).toBe(metaGuyBase64); expect(result.mimeType).toBe('image/jpeg'); }); }); describe('AI Agent Simulation - Image Analysis Scenarios', () => { beforeEach(() => { // Mock successful API responses for different analysis types mockOpenRouterClient.analyzeImage = vi.fn().mockImplementation( async (imageData: string, mimeType: string, prompt: string, options?: any) => { // Simulate different types of analysis based on the prompt if (prompt.includes('detailed') || prompt.includes('comprehensive')) { return { success: true, analysis: JSON.stringify({ description: 'A person sitting in front of a computer setup, appearing to be working or engaged in digital activities. The individual has a focused expression and is surrounded by technology equipment including monitors and peripherals.', objects: ['person', 'computer', 'monitor', 'keyboard', 'desk', 'chair'], people: [{ count: 1, appearance: 'Adult individual with focused expression', activity: 'Working at computer' }], text: ['No visible text'], colors: ['neutral tones', 'black', 'white', 'gray'], setting: 'Indoor office or home workspace', mood: 'Professional, focused, concentrated', technical_elements: ['computer equipment', 'desk setup', 'workspace organization'] }), structuredData: { description: 'A person sitting in front of a computer setup', objects: ['person', 'computer', 'monitor'], setting: 'workspace' }, model: 'test-vision-model', usage: { promptTokens: 85, completionTokens: 156, totalTokens: 241 } }; } else if (prompt.includes('webpage') || prompt.includes('screenshot')) { return { success: true, analysis: JSON.stringify({ page_type: 'desktop_application', layout: 'workspace_setup', interactive_elements: ['computer_interface', 'applications'], accessibility: { score: 0.8, observations: ['clear workspace layout', 'ergonomic setup visible'] }, content_analysis: { primary_focus: 'work/productivity environment', visible_elements: 'technology setup', user_context: 'professional or development work' } }), model: 'test-vision-model', usage: { promptTokens: 92, completionTokens: 134, totalTokens: 226 } }; } else if (prompt.includes('mobile') || prompt.includes('app')) { return { success: true, analysis: JSON.stringify({ platform_detected: 'desktop_environment', mobile_relevance: 'low', ui_patterns: ['traditional_workspace'], ux_heuristics: { ergonomics: 'visible_attention_to_comfort', organization: 'structured_setup', efficiency: 'focused_work_environment' } }), model: 'test-vision-model', usage: { promptTokens: 78, completionTokens: 118, totalTokens: 196 } }; } else { // Default analysis return { success: true, analysis: 'Image shows a person working at a computer setup with various technology equipment visible.', model: 'test-vision-model', usage: { promptTokens: 45, completionTokens: 89, totalTokens: 134 } }; } } ); }); it('should simulate AI agent performing comprehensive image analysis', async () => { const { registerAnalyzeImageTool } = await import('../../src/tools/analyze-image.js'); const mockServer = { setRequestHandler: vi.fn(), }; // Mock config vi.doMock('../../src/config/index.js', () => ({ Config: { getInstance: vi.fn(() => ({ getOpenRouterConfig: vi.fn(() => ({ apiKey: 'test-key', model: 'test-vision-model', })), getServerConfig: vi.fn(() => ({ maxImageSize: 10485760, })), })), }, })); // Mock image processor vi.doMock('../../src/utils/image-processor.js', () => ({ ImageProcessor: { getInstance: vi.fn(() => imageProcessor), }, })); registerAnalyzeImageTool(mockServer); const toolHandler = mockServer.setRequestHandler.mock.calls[0][1]; // Simulate AI agent request for comprehensive analysis const agentRequest = { params: { name: 'analyze_image', arguments: { type: 'base64', data: metaGuyBase64, mimeType: 'image/jpeg', prompt: 'Provide a comprehensive analysis of this image including objects, people, text, colors, setting, mood, and any notable features. Focus on details that would be useful for understanding the context and content.', format: 'json', maxTokens: 2000, temperature: 0.1, }, }, }; const result = await toolHandler(agentRequest); expect(result.isError).toBeUndefined(); expect(result.content[0].type).toBe('text'); const analysis = JSON.parse(result.content[0].text); expect(analysis).toHaveProperty('description'); expect(analysis).toHaveProperty('objects'); expect(analysis).toHaveProperty('people'); expect(analysis).toHaveProperty('colors'); expect(analysis).toHaveProperty('setting'); expect(analysis.objects).toContain('person'); expect(analysis.objects).toContain('computer'); expect(Array.isArray(analysis.people)).toBe(true); }); it('should simulate AI agent analyzing as webpage screenshot', async () => { const { registerAnalyzeWebpageTool } = await import('../../src/tools/analyze-webpage.js'); const mockServer = { setRequestHandler: vi.fn(), }; // Mock dependencies vi.doMock('../../src/config/index.js', () => ({ Config: { getInstance: vi.fn(() => ({ getOpenRouterConfig: vi.fn(() => ({ apiKey: 'test-key', model: 'test-vision-model' })), getServerConfig: vi.fn(() => ({ maxImageSize: 10485760 })), })), }, })); vi.doMock('../../src/utils/image-processor.js', () => ({ ImageProcessor: { getInstance: vi.fn(() => imageProcessor), }, })); registerAnalyzeWebpageTool(mockServer); const toolHandler = mockServer.setRequestHandler.mock.calls[0][1]; const agentRequest = { params: { name: 'analyze_webpage_screenshot', arguments: { type: 'base64', data: metaGuyBase64, mimeType: 'image/jpeg', focusArea: 'layout', includeAccessibility: true, format: 'json', }, }, }; const result = await toolHandler(agentRequest); expect(result.isError).toBeUndefined(); const analysis = JSON.parse(result.content[0].text); expect(analysis).toHaveProperty('page_type'); expect(analysis).toHaveProperty('layout'); expect(analysis).toHaveProperty('accessibility'); }); it('should simulate AI agent analyzing as mobile app screenshot', async () => { const { registerAnalyzeMobileAppTool } = await import('../../src/tools/analyze-mobile-app.js'); const mockServer = { setRequestHandler: vi.fn(), }; // Mock dependencies vi.doMock('../../src/config/index.js', () => ({ Config: { getInstance: vi.fn(() => ({ getOpenRouterConfig: vi.fn(() => ({ apiKey: 'test-key', model: 'test-vision-model' })), getServerConfig: vi.fn(() => ({ maxImageSize: 10485760 })), })), }, })); vi.doMock('../../src/utils/image-processor.js', () => ({ ImageProcessor: { getInstance: vi.fn(() => imageProcessor), }, })); registerAnalyzeMobileAppTool(mockServer); const toolHandler = mockServer.setRequestHandler.mock.calls[0][1]; const agentRequest = { params: { name: 'analyze_mobile_app_screenshot', arguments: { type: 'base64', data: metaGuyBase64, mimeType: 'image/jpeg', platform: 'auto-detect', focusArea: 'user-experience', includeUXHeuristics: true, format: 'json', }, }, }; const result = await toolHandler(agentRequest); expect(result.isError).toBeUndefined(); const analysis = JSON.parse(result.content[0].text); expect(analysis).toHaveProperty('platform_detected'); expect(analysis).toHaveProperty('ux_heuristics'); }); }); describe('Edge Cases and Error Handling with Meta Guy Image', () => { it('should handle corrupted base64 data gracefully', async () => { const { registerAnalyzeImageTool } = await import('../../src/tools/analyze-image.js'); const mockServer = { setRequestHandler: vi.fn(), }; // Mock dependencies vi.doMock('../../src/config/index.js', () => ({ Config: { getInstance: vi.fn(() => ({ getOpenRouterConfig: vi.fn(() => ({ apiKey: 'test-key', model: 'test-vision-model' })), getServerConfig: vi.fn(() => ({ maxImageSize: 10485760 })), })), }, })); vi.doMock('../../src/utils/image-processor.js', () => ({ ImageProcessor: { getInstance: vi.fn(() => ({ processImage: vi.fn().mockRejectedValue(new Error('Invalid base64 data')), isValidImageType: vi.fn(() => true), })), }, })); registerAnalyzeImageTool(mockServer); const toolHandler = mockServer.setRequestHandler.mock.calls[0][1]; const corruptedRequest = { params: { name: 'analyze_image', arguments: { type: 'base64', data: 'invalid_base64_data_!@#$%^&*()', mimeType: 'image/jpeg', }, }, }; const result = await toolHandler(corruptedRequest); expect(result.isError).toBe(true); expect(result.content[0].text).toContain('Error:'); }); it('should handle missing MIME type for base64 input', async () => { // Test that the system can auto-detect MIME type const result = await imageProcessor.processImage({ type: 'base64', data: metaGuyBase64, // mimeType omitted }); expect(result.mimeType).toBe('image/jpeg'); expect(imageProcessor.isValidImageType(result.mimeType)).toBe(true); }); it('should handle unsupported file format', async () => { const { registerAnalyzeImageTool } = await import('../../src/tools/analyze-image.js'); const mockServer = { setRequestHandler: vi.fn(), }; vi.doMock('../../src/config/index.js', () => ({ Config: { getInstance: vi.fn(() => ({ getOpenRouterConfig: vi.fn(() => ({ apiKey: 'test-key', model: 'test-vision-model' })), getServerConfig: vi.fn(() => ({ maxImageSize: 10485760 })), })), }, })); vi.doMock('../../src/utils/image-processor.js', () => ({ ImageProcessor: { getInstance: vi.fn(() => ({ processImage: vi.fn().mockResolvedValue({ data: 'basedata', mimeType: 'application/pdf', // Unsupported format size: 1000, }), isValidImageType: vi.fn(() => false), })), }, })); registerAnalyzeImageTool(mockServer); const toolHandler = mockServer.setRequestHandler.mock.calls[0][1]; const unsupportedRequest = { params: { name: 'analyze_image', arguments: { type: 'base64', data: 'JVBERi0xLjcNCiW...'; // PDF base64 start }, }, }; const result = await toolHandler(unsupportedRequest); expect(result.isError).toBe(true); expect(result.content[0].text).toContain('Unsupported image type'); }); }); describe('Performance and Memory Tests', () => { it('should handle large image analysis without memory leaks', async () => { // Create a larger base64 string (simulating a bigger image) const largeImageData = metaGuyBase64.padEnd(1000000, '0'); // 1MB of data const startTime = Date.now(); const result = await imageProcessor.processImage({ type: 'base64', data: largeImageData, mimeType: 'image/jpeg', }); const endTime = Date.now(); expect(result).toBeDefined(); expect(result.size).toBeGreaterThan(0); expect(endTime - startTime).toBeLessThan(5000); // Should complete within 5 seconds }); it('should process multiple concurrent requests efficiently', async () => { const concurrentRequests = 5; const promises = Array(concurrentRequests).fill(null).map(async (_, index) => { return await imageProcessor.processImage({ type: 'base64', data: metaGuyBase64, mimeType: 'image/jpeg', }); }); const startTime = Date.now(); const results = await Promise.all(promises); const endTime = Date.now(); expect(results).toHaveLength(concurrentRequests); results.forEach(result => { expect(result).toHaveProperty('data'); expect(result).toHaveProperty('mimeType'); expect(result.mimeType).toBe('image/jpeg'); }); expect(endTime - startTime).toBeLessThan(3000); // Should complete within 3 seconds }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JonathanJude/openrouter-image-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server