Skip to main content
Glama

SRT Translation MCP Server

by omd0
ai-model-integration.ts20.2 kB
/** * AI Model Integration for SRT Chunking Functions * Provides unified interface for Claude, GPT, and other AI models with Todo tool support */ import { SRTSubtitle, SRTChunk, ConversationContext } from '../types/srt.js'; import { detectConversations, detectConversationsAdvanced } from '../chunking/conversation-detector.js'; /** * AI Model Types */ export type AIModelType = 'claude' | 'gpt' | 'gemini' | 'generic'; /** * Todo Tool Integration Interface */ export interface TodoToolIntegration { createTodoList(todos: TodoItem[]): Promise<string>; updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean>; getTodoList(): Promise<TodoItem[]>; markTodoComplete(todoId: string): Promise<boolean>; } /** * Todo Item Structure */ export interface TodoItem { id: string; content: string; status: TodoStatus; priority: 'low' | 'medium' | 'high'; category: string; metadata?: Record<string, any>; createdAt: Date; updatedAt: Date; } /** * Todo Status */ export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled'; /** * AI Model Configuration */ export interface AIModelConfig { modelType: AIModelType; supportsTodoTool: boolean; maxContextSize: number; chunkSizeLimit: number; processingStrategy: 'sequential' | 'parallel' | 'batch'; contextOptimization: boolean; } /** * Chunking Integration Options */ export interface ChunkingIntegrationOptions { modelConfig: AIModelConfig; chunkingStrategy: 'conversation-aware' | 'size-based' | 'hybrid'; contextManagement: 'aggressive' | 'conservative' | 'balanced'; todoIntegration: boolean; progressTracking: boolean; } /** * AI Model Integration Manager */ export class AIModelIntegration { private modelConfig: AIModelConfig; private todoIntegration?: TodoToolIntegration; private chunkingOptions: ChunkingIntegrationOptions; constructor(config: AIModelConfig, options: ChunkingIntegrationOptions) { this.modelConfig = config; this.chunkingOptions = options; if (options.todoIntegration && config.supportsTodoTool) { this.todoIntegration = this.createTodoIntegration(config.modelType); } } /** * Create Todo Integration based on model type */ private createTodoIntegration(modelType: AIModelType): TodoToolIntegration { switch (modelType) { case 'claude': return new ClaudeTodoIntegration(); case 'gpt': return new GPTTodoIntegration(); case 'gemini': return new GeminiTodoIntegration(); default: return new GenericTodoIntegration(); } } /** * Process SRT file with AI model integration */ async processSRTWithAI( subtitles: SRTSubtitle[], processingType: 'translation' | 'analysis' | 'conversation-detection' ): Promise<ProcessingResult> { // Create initial todo list for tracking const todoList = await this.createProcessingTodos(processingType); try { // Step 1: Detect conversations with AI-optimized chunking const chunks = await this.detectConversationsWithAI(subtitles); // Step 2: Create processing plan based on chunks const processingPlan = await this.createProcessingPlan(chunks, processingType); // Step 3: Execute processing with progress tracking const results = await this.executeProcessingWithTracking( chunks, processingPlan, todoList ); return { success: true, chunks, processingPlan, results, todoList, metadata: this.generateProcessingMetadata(chunks, results) }; } catch (error) { await this.handleProcessingError(error, todoList); throw error; } } /** * Detect conversations with AI-optimized parameters */ private async detectConversationsWithAI(subtitles: SRTSubtitle[]): Promise<SRTChunk[]> { const options = this.getAIOptimizedChunkingOptions(); return detectConversationsAdvanced(subtitles, { boundaryThreshold: options.boundaryThreshold, maxChunkSize: options.maxChunkSize, minChunkSize: options.minChunkSize, enableSemanticAnalysis: options.enableSemanticAnalysis, enableSpeakerDiarization: options.enableSpeakerDiarization }); } /** * Get AI-optimized chunking options based on model capabilities */ private getAIOptimizedChunkingOptions() { const { modelConfig, chunkingOptions } = this; // Adjust chunking parameters based on model capabilities let maxChunkSize = Math.min(20, modelConfig.chunkSizeLimit); let boundaryThreshold = 0.7; if (modelConfig.maxContextSize < 50000) { maxChunkSize = Math.min(8, modelConfig.chunkSizeLimit); boundaryThreshold = 0.6; // More aggressive chunking for smaller context } if (chunkingOptions.contextManagement === 'aggressive') { maxChunkSize = Math.min(5, modelConfig.chunkSizeLimit); boundaryThreshold = 0.5; } return { boundaryThreshold, maxChunkSize, minChunkSize: 2, enableSemanticAnalysis: true, enableSpeakerDiarization: true }; } /** * Create processing todos for tracking */ private async createProcessingTodos(processingType: string): Promise<TodoItem[]> { if (!this.todoIntegration) return []; const todos: TodoItem[] = [ { id: 'chunk-detection', content: 'Detect conversation chunks in SRT file', status: 'pending', priority: 'high', category: 'processing', createdAt: new Date(), updatedAt: new Date() }, { id: 'chunk-optimization', content: 'Optimize chunks for AI model context limits', status: 'pending', priority: 'high', category: 'optimization', createdAt: new Date(), updatedAt: new Date() }, { id: 'processing-execution', content: `Execute ${processingType} on detected chunks`, status: 'pending', priority: 'medium', category: 'execution', createdAt: new Date(), updatedAt: new Date() }, { id: 'result-validation', content: 'Validate processing results', status: 'pending', priority: 'medium', category: 'validation', createdAt: new Date(), updatedAt: new Date() } ]; return todos; } /** * Create processing plan based on chunks */ private async createProcessingPlan( chunks: SRTChunk[], processingType: string ): Promise<ProcessingPlan> { const plan: ProcessingPlan = { totalChunks: chunks.length, processingStrategy: this.modelConfig.processingStrategy, chunks: chunks.map((chunk, index) => ({ chunkId: chunk.id, index, priority: this.calculateChunkPriority(chunk), estimatedContextSize: this.calculateChunkContextSize(chunk), processingSteps: this.generateProcessingSteps(chunk, processingType) })), estimatedDuration: this.estimateProcessingDuration(chunks), contextOptimization: this.modelConfig.contextOptimization }; return plan; } /** * Execute processing with progress tracking */ private async executeProcessingWithTracking( chunks: SRTChunk[], plan: ProcessingPlan, todoList: TodoItem[] ): Promise<ProcessingResults> { const results: ProcessingResults = { processedChunks: [], errors: [], warnings: [], totalProcessingTime: 0, contextUsage: [] }; const startTime = Date.now(); // Update todo status await this.updateTodoStatus('chunk-detection', 'completed'); await this.updateTodoStatus('chunk-optimization', 'in_progress'); // Process chunks based on strategy switch (plan.processingStrategy) { case 'sequential': await this.processSequentially(chunks, plan, results, todoList); break; case 'parallel': await this.processInParallel(chunks, plan, results, todoList); break; case 'batch': await this.processInBatches(chunks, plan, results, todoList); break; } results.totalProcessingTime = Date.now() - startTime; // Update final todo status await this.updateTodoStatus('processing-execution', 'completed'); await this.updateTodoStatus('result-validation', 'completed'); return results; } /** * Process chunks sequentially */ private async processSequentially( chunks: SRTChunk[], plan: ProcessingPlan, results: ProcessingResults, todoList: TodoItem[] ): Promise<void> { for (const chunk of chunks) { try { const chunkResult = await this.processChunk(chunk); results.processedChunks.push(chunkResult); results.contextUsage.push({ chunkId: chunk.id, contextSize: this.calculateChunkContextSize(chunk), processingTime: chunkResult.processingTime }); } catch (error) { results.errors.push({ chunkId: chunk.id, error: error instanceof Error ? error.message : 'Unknown error' }); } } } /** * Process chunks in parallel (with context limits) */ private async processInParallel( chunks: SRTChunk[], plan: ProcessingPlan, results: ProcessingResults, todoList: TodoItem[] ): Promise<void> { const batchSize = this.calculateOptimalBatchSize(chunks); const batches = this.createBatches(chunks, batchSize); for (const batch of batches) { const batchPromises = batch.map(chunk => this.processChunk(chunk)); const batchResults = await Promise.allSettled(batchPromises); batchResults.forEach((result, index) => { if (result.status === 'fulfilled') { results.processedChunks.push(result.value); } else { results.errors.push({ chunkId: batch[index].id, error: result.reason instanceof Error ? result.reason.message : 'Unknown error' }); } }); } } /** * Process chunks in batches */ private async processInBatches( chunks: SRTChunk[], plan: ProcessingPlan, results: ProcessingResults, todoList: TodoItem[] ): Promise<void> { const batchSize = this.calculateOptimalBatchSize(chunks); const batches = this.createBatches(chunks, batchSize); for (const batch of batches) { const batchResult = await this.processBatch(batch); results.processedChunks.push(...batchResult.processedChunks); results.errors.push(...batchResult.errors); } } /** * Process individual chunk */ private async processChunk(chunk: SRTChunk): Promise<ChunkProcessingResult> { const startTime = Date.now(); // Simulate processing (replace with actual AI model calls) const result = await this.simulateChunkProcessing(chunk); return { chunkId: chunk.id, result, processingTime: Date.now() - startTime, contextSize: this.calculateChunkContextSize(chunk) }; } /** * Simulate chunk processing (replace with actual AI model integration) */ private async simulateChunkProcessing(chunk: SRTChunk): Promise<any> { // This would be replaced with actual AI model calls return { processed: true, chunkId: chunk.id, timestamp: new Date().toISOString() }; } /** * Calculate chunk priority */ private calculateChunkPriority(chunk: SRTChunk): 'low' | 'medium' | 'high' { const subtitleCount = chunk.subtitles.length; const hasSpeaker = !!chunk.context?.speaker; const isQuestion = chunk.subtitles.some(s => s.text.includes('?')); if (isQuestion || hasSpeaker) return 'high'; if (subtitleCount > 10) return 'medium'; return 'low'; } /** * Calculate chunk context size */ private calculateChunkContextSize(chunk: SRTChunk): number { let size = 0; // Base metadata size size += JSON.stringify(chunk).length; // Add subtitle text size for (const subtitle of chunk.subtitles) { size += (subtitle.text || '').length; } return size; } /** * Generate processing steps for chunk */ private generateProcessingSteps(chunk: SRTChunk, processingType: string): string[] { const steps = ['Validate chunk structure']; switch (processingType) { case 'translation': steps.push('Detect source language', 'Apply translation model', 'Validate translation quality'); break; case 'analysis': steps.push('Analyze content type', 'Extract key information', 'Generate analysis report'); break; case 'conversation-detection': steps.push('Analyze conversation boundaries', 'Detect speaker changes', 'Validate chunk coherence'); break; } return steps; } /** * Estimate processing duration */ private estimateProcessingDuration(chunks: SRTChunk[]): number { const baseTimePerChunk = 1000; // 1 second base const contextFactor = this.modelConfig.maxContextSize < 50000 ? 1.5 : 1.0; const strategyFactor = this.modelConfig.processingStrategy === 'sequential' ? 1.0 : 0.7; return chunks.length * baseTimePerChunk * contextFactor * strategyFactor; } /** * Calculate optimal batch size */ private calculateOptimalBatchSize(chunks: SRTChunk[]): number { const maxContext = this.modelConfig.maxContextSize; const avgChunkSize = chunks.reduce((sum, chunk) => sum + this.calculateChunkContextSize(chunk), 0) / chunks.length; return Math.max(1, Math.floor(maxContext / (avgChunkSize * 2))); } /** * Create batches from chunks */ private createBatches(chunks: SRTChunk[], batchSize: number): SRTChunk[][] { const batches: SRTChunk[][] = []; for (let i = 0; i < chunks.length; i += batchSize) { batches.push(chunks.slice(i, i + batchSize)); } return batches; } /** * Process batch of chunks */ private async processBatch(chunks: SRTChunk[]): Promise<BatchProcessingResult> { const results: ChunkProcessingResult[] = []; const errors: ProcessingError[] = []; for (const chunk of chunks) { try { const result = await this.processChunk(chunk); results.push(result); } catch (error) { errors.push({ chunkId: chunk.id, error: error instanceof Error ? error.message : 'Unknown error' }); } } return { processedChunks: results, errors }; } /** * Update todo status */ private async updateTodoStatus(todoId: string, status: TodoStatus): Promise<void> { if (this.todoIntegration) { await this.todoIntegration.updateTodoStatus(todoId, status); } } /** * Handle processing errors */ private async handleProcessingError(error: any, todoList: TodoItem[]): Promise<void> { // Mark relevant todos as failed for (const todo of todoList) { if (todo.status === 'in_progress') { await this.updateTodoStatus(todo.id, 'cancelled'); } } } /** * Generate processing metadata */ private generateProcessingMetadata(chunks: SRTChunk[], results: ProcessingResults): ProcessingMetadata { return { totalChunks: chunks.length, processedChunks: results.processedChunks.length, errorCount: results.errors.length, warningCount: results.warnings.length, totalProcessingTime: results.totalProcessingTime, averageChunkSize: chunks.reduce((sum, chunk) => sum + this.calculateChunkContextSize(chunk), 0) / chunks.length, contextEfficiency: this.calculateContextEfficiency(chunks, results), modelCapabilities: this.modelConfig }; } /** * Calculate context efficiency */ private calculateContextEfficiency(chunks: SRTChunk[], results: ProcessingResults): number { const totalContextUsed = results.contextUsage.reduce((sum, usage) => sum + usage.contextSize, 0); const maxPossibleContext = chunks.length * this.modelConfig.maxContextSize; return totalContextUsed / maxPossibleContext; } } /** * Processing Result Types */ export interface ProcessingResult { success: boolean; chunks: SRTChunk[]; processingPlan: ProcessingPlan; results: ProcessingResults; todoList: TodoItem[]; metadata: ProcessingMetadata; } export interface ProcessingPlan { totalChunks: number; processingStrategy: 'sequential' | 'parallel' | 'batch'; chunks: ChunkPlan[]; estimatedDuration: number; contextOptimization: boolean; } export interface ChunkPlan { chunkId: string; index: number; priority: 'low' | 'medium' | 'high'; estimatedContextSize: number; processingSteps: string[]; } export interface ProcessingResults { processedChunks: ChunkProcessingResult[]; errors: ProcessingError[]; warnings: ProcessingWarning[]; totalProcessingTime: number; contextUsage: ContextUsage[]; } export interface ChunkProcessingResult { chunkId: string; result: any; processingTime: number; contextSize: number; } export interface ProcessingError { chunkId: string; error: string; } export interface ProcessingWarning { chunkId: string; warning: string; } export interface ContextUsage { chunkId: string; contextSize: number; processingTime: number; } export interface ProcessingMetadata { totalChunks: number; processedChunks: number; errorCount: number; warningCount: number; totalProcessingTime: number; averageChunkSize: number; contextEfficiency: number; modelCapabilities: AIModelConfig; } export interface BatchProcessingResult { processedChunks: ChunkProcessingResult[]; errors: ProcessingError[]; } /** * Model-specific Todo Integrations */ class ClaudeTodoIntegration implements TodoToolIntegration { async createTodoList(todos: TodoItem[]): Promise<string> { // Claude-specific todo creation return `Created ${todos.length} todos for Claude processing`; } async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> { // Claude-specific status update return true; } async getTodoList(): Promise<TodoItem[]> { // Claude-specific todo retrieval return []; } async markTodoComplete(todoId: string): Promise<boolean> { return this.updateTodoStatus(todoId, 'completed'); } } class GPTTodoIntegration implements TodoToolIntegration { async createTodoList(todos: TodoItem[]): Promise<string> { // GPT-specific todo creation return `Created ${todos.length} todos for GPT processing`; } async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> { // GPT-specific status update return true; } async getTodoList(): Promise<TodoItem[]> { // GPT-specific todo retrieval return []; } async markTodoComplete(todoId: string): Promise<boolean> { return this.updateTodoStatus(todoId, 'completed'); } } class GeminiTodoIntegration implements TodoToolIntegration { async createTodoList(todos: TodoItem[]): Promise<string> { // Gemini-specific todo creation return `Created ${todos.length} todos for Gemini processing`; } async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> { // Gemini-specific status update return true; } async getTodoList(): Promise<TodoItem[]> { // Gemini-specific todo retrieval return []; } async markTodoComplete(todoId: string): Promise<boolean> { return this.updateTodoStatus(todoId, 'completed'); } } class GenericTodoIntegration implements TodoToolIntegration { async createTodoList(todos: TodoItem[]): Promise<string> { // Generic todo creation return `Created ${todos.length} todos for generic processing`; } async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> { // Generic status update return true; } async getTodoList(): Promise<TodoItem[]> { // Generic todo retrieval return []; } async markTodoComplete(todoId: string): Promise<boolean> { return this.updateTodoStatus(todoId, 'completed'); } }

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/omd0/srt-mcp'

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