Skip to main content
Glama

SRT Translation MCP Server

by omd0
todo-tool-integration.ts20.7 kB
/** * Todo Tool Integration for AI Models * Provides unified Todo tool support for Claude, GPT, Gemini, and other models */ import { SRTSubtitle, SRTChunk } from '../types/srt.js'; /** * Todo Tool Interface for AI Models */ export interface TodoToolInterface { createTodoList(todos: TodoItem[]): Promise<TodoListResult>; updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean>; getTodoList(): Promise<TodoItem[]>; markTodoComplete(todoId: string): Promise<boolean>; getTodoById(todoId: string): Promise<TodoItem | null>; deleteTodo(todoId: string): Promise<boolean>; addTodo(todo: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>): Promise<TodoItem>; updateTodo(todoId: string, updates: Partial<TodoItem>): Promise<TodoItem | null>; searchTodos(query: string): Promise<TodoItem[]>; getTodosByCategory(category: string): Promise<TodoItem[]>; getTodosByStatus(status: TodoStatus): Promise<TodoItem[]>; getTodosByPriority(priority: TodoPriority): Promise<TodoItem[]>; getTodoStatistics(): Promise<TodoStatistics>; } /** * Todo Item Structure */ export interface TodoItem { id: string; content: string; status: TodoStatus; priority: TodoPriority; category: string; metadata?: TodoMetadata; createdAt: Date; updatedAt: Date; completedAt?: Date; dueDate?: Date; tags?: string[]; dependencies?: string[]; // IDs of other todos this depends on subtasks?: TodoItem[]; // Nested todos } /** * Todo Status */ export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled' | 'blocked'; /** * Todo Priority */ export type TodoPriority = 'low' | 'medium' | 'high' | 'critical'; /** * Todo Metadata */ export interface TodoMetadata { modelSpecific?: Record<string, any>; processingContext?: ProcessingContext; chunkId?: string; estimatedDuration?: number; actualDuration?: number; retryCount?: number; errorHistory?: TodoError[]; progress?: number; // 0-100 notes?: string[]; } /** * Processing Context */ export interface ProcessingContext { fileId?: string; chunkId?: string; processingType?: string; modelType?: string; contextSize?: number; complexity?: 'low' | 'medium' | 'high'; } /** * Todo Error */ export interface TodoError { timestamp: Date; error: string; context?: string; retryable: boolean; } /** * Todo List Result */ export interface TodoListResult { success: boolean; todoIds: string[]; message: string; warnings?: string[]; } /** * Todo Statistics */ export interface TodoStatistics { total: number; pending: number; inProgress: number; completed: number; cancelled: number; blocked: number; byPriority: Record<TodoPriority, number>; byCategory: Record<string, number>; averageCompletionTime?: number; completionRate?: number; } /** * SRT Processing Todo Categories */ export const SRT_TODO_CATEGORIES = { FILE_ANALYSIS: 'file-analysis', CHUNK_DETECTION: 'chunk-detection', CHUNK_OPTIMIZATION: 'chunk-optimization', TRANSLATION: 'translation', ANALYSIS: 'analysis', VALIDATION: 'validation', QUALITY_CHECK: 'quality-check', EXPORT: 'export', ERROR_HANDLING: 'error-handling' } as const; /** * SRT Processing Todo Templates */ export class SRTTodoTemplates { /** * Create file analysis todos */ static createFileAnalysisTodos(fileName: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Analyze SRT file structure: ${fileName}`, status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.FILE_ANALYSIS, metadata: { processingContext: { fileId: fileName, processingType: 'file-analysis' } } }, { content: 'Validate SRT file format and syntax', status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.FILE_ANALYSIS, metadata: { processingContext: { fileId: fileName, processingType: 'validation' } } }, { content: 'Detect language and content characteristics', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.FILE_ANALYSIS, metadata: { processingContext: { fileId: fileName, processingType: 'language-detection' } } } ]; } /** * Create chunk detection todos */ static createChunkDetectionTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Detect conversation boundaries in ${chunkCount} potential chunks`, status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.CHUNK_DETECTION, metadata: { processingContext: { processingType: 'conversation-detection' } } }, { content: 'Apply semantic analysis to chunk boundaries', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.CHUNK_DETECTION, metadata: { processingContext: { processingType: 'semantic-analysis' } } }, { content: 'Detect speaker changes and diarization', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.CHUNK_DETECTION, metadata: { processingContext: { processingType: 'speaker-diarization' } } } ]; } /** * Create chunk optimization todos */ static createChunkOptimizationTodos(chunkCount: number, modelType: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Optimize ${chunkCount} chunks for ${modelType} context limits`, status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION, metadata: { processingContext: { processingType: 'context-optimization', modelType } } }, { content: 'Calculate optimal chunk sizes and boundaries', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION, metadata: { processingContext: { processingType: 'size-optimization', modelType } } }, { content: 'Validate chunk coherence and speaker consistency', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION, metadata: { processingContext: { processingType: 'coherence-validation', modelType } } } ]; } /** * Create translation todos */ static createTranslationTodos(chunkCount: number, targetLanguage: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Translate ${chunkCount} chunks to ${targetLanguage}`, status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.TRANSLATION, metadata: { processingContext: { processingType: 'translation', complexity: 'high' } } }, { content: 'Maintain speaker consistency across translations', status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.TRANSLATION, metadata: { processingContext: { processingType: 'speaker-consistency', complexity: 'medium' } } }, { content: 'Preserve timing and formatting in translations', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.TRANSLATION, metadata: { processingContext: { processingType: 'formatting-preservation', complexity: 'medium' } } } ]; } /** * Create analysis todos */ static createAnalysisTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Analyze content in ${chunkCount} chunks`, status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.ANALYSIS, metadata: { processingContext: { processingType: 'content-analysis' } } }, { content: 'Extract key themes and topics', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.ANALYSIS, metadata: { processingContext: { processingType: 'theme-extraction' } } }, { content: 'Generate conversation insights and patterns', status: 'pending', priority: 'low', category: SRT_TODO_CATEGORIES.ANALYSIS, metadata: { processingContext: { processingType: 'insight-generation' } } } ]; } /** * Create validation todos */ static createValidationTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] { return [ { content: `Validate processing results for ${chunkCount} chunks`, status: 'pending', priority: 'high', category: SRT_TODO_CATEGORIES.VALIDATION, metadata: { processingContext: { processingType: 'result-validation' } } }, { content: 'Check timing and formatting integrity', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.VALIDATION, metadata: { processingContext: { processingType: 'integrity-check' } } }, { content: 'Verify language detection accuracy', status: 'pending', priority: 'medium', category: SRT_TODO_CATEGORIES.VALIDATION, metadata: { processingContext: { processingType: 'language-validation' } } } ]; } } /** * Universal Todo Tool Implementation */ export class UniversalTodoTool implements TodoToolInterface { private todos: Map<string, TodoItem> = new Map(); private todoCounter = 0; private modelType: string; constructor(modelType: string = 'generic') { this.modelType = modelType; } /** * Create todo list */ async createTodoList(todos: TodoItem[]): Promise<TodoListResult> { const todoIds: string[] = []; const warnings: string[] = []; for (const todo of todos) { try { const createdTodo = await this.addTodo(todo); todoIds.push(createdTodo.id); } catch (error) { warnings.push(`Failed to create todo: ${error instanceof Error ? error.message : 'Unknown error'}`); } } return { success: todoIds.length > 0, todoIds, message: `Created ${todoIds.length} todos for ${this.modelType}`, warnings: warnings.length > 0 ? warnings : undefined }; } /** * Add single todo */ async addTodo(todo: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>): Promise<TodoItem> { const id = `${this.modelType}-todo-${++this.todoCounter}`; const now = new Date(); const newTodo: TodoItem = { ...todo, id, createdAt: now, updatedAt: now }; this.todos.set(id, newTodo); console.log(`[DEBUG] Added todo ${id}, total todos: ${this.todos.size}`); return newTodo; } /** * Update todo status */ async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> { const todo = this.todos.get(todoId); if (!todo) return false; todo.status = status; todo.updatedAt = new Date(); if (status === 'completed') { todo.completedAt = new Date(); } this.todos.set(todoId, todo); return true; } /** * Get todo list */ async getTodoList(): Promise<TodoItem[]> { console.log(`[DEBUG] getTodoList called, todos count: ${this.todos.size}`); const todos = Array.from(this.todos.values()); console.log(`[DEBUG] returning ${todos.length} todos`); return todos; } /** * Mark todo as complete */ async markTodoComplete(todoId: string): Promise<boolean> { return this.updateTodoStatus(todoId, 'completed'); } /** * Get todo by ID */ async getTodoById(todoId: string): Promise<TodoItem | null> { return this.todos.get(todoId) || null; } /** * Delete todo */ async deleteTodo(todoId: string): Promise<boolean> { return this.todos.delete(todoId); } /** * Update todo */ async updateTodo(todoId: string, updates: Partial<TodoItem>): Promise<TodoItem | null> { const todo = this.todos.get(todoId); if (!todo) return null; const updatedTodo = { ...todo, ...updates, id: todoId, // Preserve ID updatedAt: new Date() }; this.todos.set(todoId, updatedTodo); return updatedTodo; } /** * Search todos */ async searchTodos(query: string): Promise<TodoItem[]> { const allTodos = Array.from(this.todos.values()); const searchTerm = query.toLowerCase(); return allTodos.filter(todo => todo.content.toLowerCase().includes(searchTerm) || todo.category.toLowerCase().includes(searchTerm) || (todo.tags && todo.tags.some(tag => tag.toLowerCase().includes(searchTerm))) ); } /** * Get todos by category */ async getTodosByCategory(category: string): Promise<TodoItem[]> { const allTodos = Array.from(this.todos.values()); return allTodos.filter(todo => todo.category === category); } /** * Get todos by status */ async getTodosByStatus(status: TodoStatus): Promise<TodoItem[]> { const allTodos = Array.from(this.todos.values()); return allTodos.filter(todo => todo.status === status); } /** * Get todos by priority */ async getTodosByPriority(priority: TodoPriority): Promise<TodoItem[]> { const allTodos = Array.from(this.todos.values()); return allTodos.filter(todo => todo.priority === priority); } /** * Get todo statistics */ async getTodoStatistics(): Promise<TodoStatistics> { const allTodos = Array.from(this.todos.values()); const stats: TodoStatistics = { total: allTodos.length, pending: allTodos.filter(t => t.status === 'pending').length, inProgress: allTodos.filter(t => t.status === 'in_progress').length, completed: allTodos.filter(t => t.status === 'completed').length, cancelled: allTodos.filter(t => t.status === 'cancelled').length, blocked: allTodos.filter(t => t.status === 'blocked').length, byPriority: { low: allTodos.filter(t => t.priority === 'low').length, medium: allTodos.filter(t => t.priority === 'medium').length, high: allTodos.filter(t => t.priority === 'high').length, critical: allTodos.filter(t => t.priority === 'critical').length }, byCategory: {} }; // Calculate category distribution const categories = [...new Set(allTodos.map(t => t.category))]; categories.forEach(category => { stats.byCategory[category] = allTodos.filter(t => t.category === category).length; }); // Calculate completion rate if (stats.total > 0) { stats.completionRate = stats.completed / stats.total; } // Calculate average completion time for completed todos const completedTodos = allTodos.filter(t => t.status === 'completed' && t.completedAt); if (completedTodos.length > 0) { const totalTime = completedTodos.reduce((sum, todo) => { if (todo.completedAt && todo.createdAt) { return sum + (todo.completedAt.getTime() - todo.createdAt.getTime()); } return sum; }, 0); stats.averageCompletionTime = totalTime / completedTodos.length; } return stats; } } /** * Model-specific Todo Tool Implementations */ export class ClaudeTodoTool extends UniversalTodoTool { constructor() { super('claude'); } async createTodoList(todos: TodoItem[]): Promise<TodoListResult> { // Claude-specific todo creation with reasoning const claudeTodos = todos.map(todo => ({ ...todo, metadata: { ...todo.metadata, modelSpecific: { claudeOptimized: true, reasoningRequired: todo.priority === 'high' || todo.category.includes('analysis'), anthropicFormat: true } } })); return super.createTodoList(claudeTodos); } } export class GPTTodoTool extends UniversalTodoTool { constructor() { super('gpt'); } async createTodoList(todos: TodoItem[]): Promise<TodoListResult> { // GPT-specific todo creation const gptTodos = todos.map(todo => ({ ...todo, metadata: { ...todo.metadata, modelSpecific: { gptOptimized: true, openaiFormat: true, functionCalling: true } } })); return super.createTodoList(gptTodos); } } export class GeminiTodoTool extends UniversalTodoTool { constructor() { super('gemini'); } async createTodoList(todos: TodoItem[]): Promise<TodoListResult> { // Gemini-specific todo creation const geminiTodos = todos.map(todo => ({ ...todo, metadata: { ...todo.metadata, modelSpecific: { geminiOptimized: true, googleFormat: true, multimodalCapable: true } } })); return super.createTodoList(geminiTodos); } } /** * Todo Tool Factory */ export class TodoToolFactory { static createTodoTool(modelType: string): TodoToolInterface { switch (modelType.toLowerCase()) { case 'claude': return new ClaudeTodoTool(); case 'gpt': return new GPTTodoTool(); case 'gemini': return new GeminiTodoTool(); default: return new UniversalTodoTool(modelType); } } } /** * SRT Processing Todo Manager */ export class SRTProcessingTodoManager { private todoTool: TodoToolInterface; private modelType: string; constructor(modelType: string) { this.modelType = modelType; this.todoTool = TodoToolFactory.createTodoTool(modelType); } /** * Create comprehensive SRT processing todos */ async createSRTProcessingTodos( fileName: string, chunkCount: number, processingType: 'translation' | 'analysis' | 'conversation-detection', targetLanguage?: string ): Promise<TodoListResult> { const todos: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] = []; // Add file analysis todos todos.push(...SRTTodoTemplates.createFileAnalysisTodos(fileName)); // Add chunk detection todos todos.push(...SRTTodoTemplates.createChunkDetectionTodos(chunkCount)); // Add chunk optimization todos todos.push(...SRTTodoTemplates.createChunkOptimizationTodos(chunkCount, this.modelType)); // Add processing-specific todos switch (processingType) { case 'translation': if (targetLanguage) { todos.push(...SRTTodoTemplates.createTranslationTodos(chunkCount, targetLanguage)); } break; case 'analysis': todos.push(...SRTTodoTemplates.createAnalysisTodos(chunkCount)); break; case 'conversation-detection': // Already covered by chunk detection todos break; } // Add validation todos todos.push(...SRTTodoTemplates.createValidationTodos(chunkCount)); return this.todoTool.createTodoList(todos as TodoItem[]); } /** * Update processing progress */ async updateProcessingProgress( stage: 'file-analysis' | 'chunk-detection' | 'chunk-optimization' | 'processing' | 'validation', status: TodoStatus ): Promise<void> { const todos = await this.todoTool.getTodoList(); const stageTodos = todos.filter(todo => todo.metadata?.processingContext?.processingType === stage ); for (const todo of stageTodos) { await this.todoTool.updateTodoStatus(todo.id, status); } } /** * Get processing statistics */ async getProcessingStatistics(): Promise<TodoStatistics> { return this.todoTool.getTodoStatistics(); } /** * Get todos by processing stage */ async getTodosByStage(stage: string): Promise<TodoItem[]> { const todos = await this.todoTool.getTodoList(); if (stage === 'all') { return todos; } return todos.filter(todo => todo.metadata?.processingContext?.processingType === stage ); } }

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