detect_conversations
Analyzes SRT subtitle files to detect conversations, identify languages, and create optimized chunks for translation workflow. Returns metadata for efficient processing of subtitle content.
Instructions
π CHUNK-BASED TRANSLATION WORKFLOW INSTRUCTIONS π
π OVERVIEW: This tool analyzes SRT files and creates intelligent chunks for efficient translation. It returns METADATA ONLY - use get_next_chunk() and translate_srt() for actual content.
π WHAT IT DOES:
SMART INPUT: Auto-detects file paths vs SRT content
Creates small chunks (1-3 subtitles each) optimized for AI processing
Detects languages (Arabic, English, Spanish, French) per chunk
Identifies speakers and conversation boundaries
Provides translation priority rankings (high/medium/low)
Stores chunks in memory to avoid context limits
Creates individual TODO tasks for tracking progress
π WHAT IT RETURNS (SMALL RESPONSE):
chunkCount: Total number of chunks created
totalDuration: File duration in milliseconds
languageDistribution: Language counts (e.g., {"ar": 45, "en": 12})
previewChunk: Preview of first chunk metadata only
sessionId: For retrieving chunks later
message: Instructions for next steps
todos: Individual tasks for each chunk
π― RECOMMENDED WORKFLOW:
Call detect_conversations with storeInMemory=true
Review metadata to understand file structure (SMALL RESPONSE)
Use get_next_chunk to process chunks one by one
Use translate_srt() for actual translation
Track progress with todo_management
π‘ EXAMPLES:
File Path Input: {"content": "/path/to/file.srt", "storeInMemory": true, "createTodos": true}
SRT Content Input: {"content": "1\n00:00:02,000 --> 00:00:07,000\nHello world", "storeInMemory": true}
β οΈ IMPORTANT:
This returns METADATA ONLY - no actual text content
Response is SMALL to avoid context overflow
Use get_next_chunk() to retrieve individual chunks
Use translate_srt() for actual translation
Store chunks in memory for large files to avoid context limits
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | SRT file content OR file path to analyze (auto-detected) | |
| createTodos | No | Create individual TODO tasks for each chunk (default: false) | |
| sessionId | No | Session ID for memory storage (optional, auto-generated if not provided) | |
| storeInMemory | No | Store chunks in memory to avoid context limits (default: false) |
Implementation Reference
- src/mcp/server.ts:455-616 (handler)Main MCP tool handler for 'detect_conversations'. Parses SRT input (file path or content), uses detectConversationsAdvanced to chunk subtitles into small conversation units (1-3 subtitles), generates metadata (chunk count, languages, speakers), optionally stores chunks in memory with sessionId and creates TODOs. Returns compact metadata only to avoid context limits.private async handleDetectConversations(args: any) { const { content: inputContent, storeInMemory = false, sessionId, createTodos = false } = args; // Smart input detection: check if content is a file path or SRT content let content = inputContent; let srtContent = content; // Smart file detection: check if content is a file path or SRT content let isFilePath = false; // Check if content looks like a file path if (content.endsWith('.srt')) { // Try as absolute path first if (content.startsWith('/') && existsSync(content)) { isFilePath = true; } // Try as relative path from current directory else if (existsSync(content)) { isFilePath = true; } // Try as relative path from project root else if (existsSync(join(process.cwd(), content))) { const fullPath = join(process.cwd(), content); content = fullPath; isFilePath = true; } } if (isFilePath) { try { srtContent = readFileSync(content, 'utf8'); console.log(`π Reading SRT file from path: ${content}`); } catch (error) { throw new Error(`Failed to read file ${content}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } else { // Check if content looks like SRT format (has subtitle blocks) if (content.trim().length === 0) { throw new Error('Empty content provided'); } // If it's just a filename without path, try to find it if (content.endsWith('.srt') && !content.includes('/')) { const possiblePaths = [ content, join(process.cwd(), content), join(process.cwd(), 'examples', content), join(process.cwd(), 'samples', content) ]; for (const path of possiblePaths) { if (existsSync(path)) { try { srtContent = readFileSync(path, 'utf8'); console.log(`π Found SRT file at: ${path}`); break; } catch (error) { continue; } } } if (!srtContent) { throw new Error(`File not found: ${content}. Searched in: ${possiblePaths.join(', ')}`); } } else { console.log(`π Processing SRT content directly (${content.length} characters)`); srtContent = content; } } const parseResult = parseSRTFile(srtContent); if (!parseResult.success || !parseResult.file) { const errorDetails = parseResult.errors?.map(e => `${e.type}: ${e.message}`).join(', ') || 'Unknown parsing error'; throw new Error(`Failed to parse SRT file: ${errorDetails}`); } // Use advanced conversation detection with MUCH SMALLER chunks for AI processing const chunks = detectConversationsAdvanced(parseResult.file.subtitles, { boundaryThreshold: 0.1, // Very low threshold for maximum chunks minChunkSize: 1, // Allow single subtitle chunks maxChunkSize: 3, // VERY small max chunk size (1-3 subtitles) enableSpeakerDiarization: true, enableSemanticAnalysis: true, }); // Create metadata for AI const chunkMetadata = chunks.map((chunk, index) => { const firstSubtitle = chunk.subtitles[0]; const lastSubtitle = chunk.subtitles[chunk.subtitles.length - 1]; const languageInfo = this.detectLanguage(chunk); return { id: chunk.id, startIndex: chunk.startIndex, endIndex: chunk.endIndex, startTime: firstSubtitle.startTime, endTime: lastSubtitle.endTime, duration: (lastSubtitle.endTime as unknown as number) - (firstSubtitle.startTime as unknown as number), subtitleCount: chunk.subtitles.length, speaker: chunk.context?.speaker || 'Unknown', languageInfo: languageInfo, translationPriority: 'medium', contentType: 'dialogue', topicKeywords: [], complexity: 'medium', }; }); // Return only metadata about chunks, not the actual chunk data const result = { content: [ { type: 'text', text: JSON.stringify({ chunkCount: chunks.length, totalDuration: parseResult.file.subtitles.reduce((total, sub) => total + ((sub.endTime as unknown as number) - (sub.startTime as unknown as number)), 0), languageDistribution: this.analyzeLanguageDistribution(chunks), speakerDistribution: this.analyzeSpeakerDistribution(chunks), // Return only first chunk metadata as preview, not all chunks previewChunk: chunkMetadata.length > 0 ? chunkMetadata[0] : null, message: `Detected ${chunks.length} chunks. Use get_next_chunk to retrieve individual chunks.`, validationStatus: { isValid: chunks.length > 0, errors: [], warnings: [], } }, null, 2), }, ], }; // Store chunks in memory if requested if (storeInMemory) { const actualSessionId = sessionId || `srt-session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; this.chunkMemory.set(actualSessionId, chunks); this.chunkIndex.set(actualSessionId, 0); // Add session info to response const responseData = JSON.parse(result.content[0].text); responseData.sessionId = actualSessionId; result.content[0].text = JSON.stringify(responseData, null, 2); } // Create TODO tasks if requested if (createTodos) { const todos = await this.todoManager.createSRTProcessingTodos( 'srt_file', chunks.length, 'translation' ); // Add todos info to response const responseData = JSON.parse(result.content[0].text); responseData.todos = todos; result.content[0].text = JSON.stringify(responseData, null, 2); } return result; }
- src/mcp/server.ts:122-193 (registration)MCP tool registration in the server's ListToolsRequestHandler. Defines name 'detect_conversations', detailed description with workflow instructions, and input schema supporting file paths/content, memory storage, todos.{ name: 'detect_conversations', description: `π CHUNK-BASED TRANSLATION WORKFLOW INSTRUCTIONS π π OVERVIEW: This tool analyzes SRT files and creates intelligent chunks for efficient translation. It returns METADATA ONLY - use get_next_chunk() and translate_srt() for actual content. π WHAT IT DOES: - SMART INPUT: Auto-detects file paths vs SRT content - Creates small chunks (1-3 subtitles each) optimized for AI processing - Detects languages (Arabic, English, Spanish, French) per chunk - Identifies speakers and conversation boundaries - Provides translation priority rankings (high/medium/low) - Stores chunks in memory to avoid context limits - Creates individual TODO tasks for tracking progress π WHAT IT RETURNS (SMALL RESPONSE): - chunkCount: Total number of chunks created - totalDuration: File duration in milliseconds - languageDistribution: Language counts (e.g., {"ar": 45, "en": 12}) - previewChunk: Preview of first chunk metadata only - sessionId: For retrieving chunks later - message: Instructions for next steps - todos: Individual tasks for each chunk π― RECOMMENDED WORKFLOW: 1. Call detect_conversations with storeInMemory=true 2. Review metadata to understand file structure (SMALL RESPONSE) 3. Use get_next_chunk to process chunks one by one 4. Use translate_srt() for actual translation 5. Track progress with todo_management π‘ EXAMPLES: File Path Input: {"content": "/path/to/file.srt", "storeInMemory": true, "createTodos": true} SRT Content Input: {"content": "1\\n00:00:02,000 --> 00:00:07,000\\nHello world", "storeInMemory": true} β οΈ IMPORTANT: - This returns METADATA ONLY - no actual text content - Response is SMALL to avoid context overflow - Use get_next_chunk() to retrieve individual chunks - Use translate_srt() for actual translation - Store chunks in memory for large files to avoid context limits`, inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'SRT file content OR file path to analyze (auto-detected)', }, storeInMemory: { type: 'boolean', description: 'Store chunks in memory to avoid context limits (default: false)', default: false, }, sessionId: { type: 'string', description: 'Session ID for memory storage (optional, auto-generated if not provided)', }, createTodos: { type: 'boolean', description: 'Create individual TODO tasks for each chunk (default: false)', default: false, }, }, required: ['content'], }, },
- src/mcp/server.ts:169-191 (schema)Input schema for detect_conversations tool, defining parameters for SRT content/path, optional memory storage with sessionId, and TODO creation.inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'SRT file content OR file path to analyze (auto-detected)', }, storeInMemory: { type: 'boolean', description: 'Store chunks in memory to avoid context limits (default: false)', default: false, }, sessionId: { type: 'string', description: 'Session ID for memory storage (optional, auto-generated if not provided)', }, createTodos: { type: 'boolean', description: 'Create individual TODO tasks for each chunk (default: false)', default: false, }, }, required: ['content'],
- Core helper function detectConversationsAdvanced that implements advanced conversation boundary detection using timing gaps, speaker changes, semantic similarity, and topic shifts. Called by the MCP handler to generate small chunks optimized for AI processing.export function detectConversationsAdvanced( subtitles: SRTSubtitle[], options: { boundaryThreshold?: number; maxChunkSize?: number; minChunkSize?: number; enableSemanticAnalysis?: boolean; enableSpeakerDiarization?: boolean; } = {} ): SRTChunk[] { const { boundaryThreshold = 0.7, maxChunkSize = 20, minChunkSize = 2, enableSemanticAnalysis = true, enableSpeakerDiarization = true } = options; // First pass: Basic boundary detection with custom threshold const initialChunks = detectBasicBoundariesWithThreshold(subtitles, boundaryThreshold); let processedChunks = initialChunks; // Second pass: Semantic analysis (optional) if (enableSemanticAnalysis) { processedChunks = applySemanticAnalysis(processedChunks); } // Third pass: Speaker diarization (optional) if (enableSpeakerDiarization) { processedChunks = applySpeakerDiarization(processedChunks); } // Fourth pass: Size optimization processedChunks = optimizeChunkSizesWithLimits(processedChunks, maxChunkSize, minChunkSize); return processedChunks; }