ai-model-integration.ts•20.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');
}
}