translation-service.ts•7.85 kB
/**
* Translation service interface and implementations
*/
import { TranslationRequest, TranslationResult, ConversationContext } from '../types/srt.js';
import { preserveStyleTags } from '../utils/style-tags.js';
/**
* Abstract translation service interface
*/
export interface TranslationService {
translate(request: TranslationRequest): Promise<TranslationResult>;
translateBatch(requests: TranslationRequest[]): Promise<TranslationResult[]>;
}
/**
* Mock translation service for development and testing
*/
export class MockTranslationService implements TranslationService {
async translate(request: TranslationRequest): Promise<TranslationResult> {
// Simulate translation delay
await new Promise(resolve => setTimeout(resolve, 100));
// Mock translation - just add language prefix
const translatedText = request.preserveTags
? preserveStyleTags(request.text, `[${request.targetLanguage}] ${request.text}`)
: `[${request.targetLanguage}] ${request.text}`;
return {
translatedText,
confidence: 0.85,
sourceLanguage: request.sourceLanguage || 'auto',
targetLanguage: request.targetLanguage
};
}
async translateBatch(requests: TranslationRequest[]): Promise<TranslationResult[]> {
const results: TranslationResult[] = [];
for (const request of requests) {
const result = await this.translate(request);
results.push(result);
}
return results;
}
}
/**
* Context-aware translation service wrapper
*/
export class ContextAwareTranslationService implements TranslationService {
constructor(private baseService: TranslationService) {}
async translate(request: TranslationRequest): Promise<TranslationResult> {
// Enhance request with context
const enhancedRequest = this.enhanceRequestWithContext(request);
// Translate with context
const result = await this.baseService.translate(enhancedRequest);
// Post-process result to maintain consistency
return this.postProcessResult(result, request);
}
async translateBatch(requests: TranslationRequest[]): Promise<TranslationResult[]> {
// Group requests by conversation context
const groupedRequests = this.groupByConversation(requests);
const results: TranslationResult[] = [];
for (const group of groupedRequests) {
// Translate each group with shared context
const groupResults = await this.translateConversationGroup(group);
results.push(...groupResults);
}
return results;
}
/**
* Enhance translation request with conversation context
*/
private enhanceRequestWithContext(request: TranslationRequest): TranslationRequest {
if (!request.context) {
return request;
}
// Add context to translation request
const contextPrefix = this.buildContextPrefix(request.context);
const enhancedText = contextPrefix + request.text;
return {
...request,
text: enhancedText
};
}
/**
* Build context prefix for translation
*/
private buildContextPrefix(context: ConversationContext): string {
const parts: string[] = [];
if (context.speaker) {
parts.push(`Speaker: ${context.speaker}`);
}
if (context.previousContext) {
parts.push(`Previous: ${context.previousContext}`);
}
if (context.nextContext) {
parts.push(`Next: ${context.nextContext}`);
}
return parts.length > 0 ? `[Context: ${parts.join(' | ')}] ` : '';
}
/**
* Post-process translation result
*/
private postProcessResult(result: TranslationResult, originalRequest: TranslationRequest): TranslationResult {
// Remove context prefix from result
const contextPrefix = this.buildContextPrefix(originalRequest.context || { conversationId: '' });
const cleanText = result.translatedText.replace(contextPrefix, '');
return {
...result,
translatedText: cleanText
};
}
/**
* Group translation requests by conversation
*/
private groupByConversation(requests: TranslationRequest[]): TranslationRequest[][] {
const groups = new Map<string, TranslationRequest[]>();
for (const request of requests) {
const conversationId = request.context?.conversationId || 'default';
if (!groups.has(conversationId)) {
groups.set(conversationId, []);
}
groups.get(conversationId)!.push(request);
}
return Array.from(groups.values());
}
/**
* Translate a group of requests from the same conversation
*/
private async translateConversationGroup(requests: TranslationRequest[]): Promise<TranslationResult[]> {
// Sort by original order if possible
const sortedRequests = requests.sort((a, b) => {
// This would need to be enhanced with proper ordering logic
return 0;
});
const results: TranslationResult[] = [];
for (const request of sortedRequests) {
const result = await this.translate(request);
results.push(result);
}
return results;
}
}
/**
* Chat-based AI translation service that uses the current AI assistant
*/
export class ChatAITranslationService implements TranslationService {
private translationQueue: TranslationRequest[] = [];
private isProcessing = false;
async translate(request: TranslationRequest): Promise<TranslationResult> {
// For now, we'll use a simple approach where the translation is handled
// by the MCP server calling the AI assistant directly
// This is a placeholder that will be replaced by the actual chat integration
console.log(`🤖 AI Translation Request: "${request.text}" (${request.sourceLanguage} → ${request.targetLanguage})`);
// This will be replaced with actual AI chat integration
// For now, return a placeholder that indicates AI translation is needed
return {
translatedText: `[AI_TRANSLATION_NEEDED:${request.text}]`,
confidence: 0.8,
sourceLanguage: request.sourceLanguage || 'auto',
targetLanguage: request.targetLanguage
};
}
async translateBatch(requests: TranslationRequest[]): Promise<TranslationResult[]> {
const results: TranslationResult[] = [];
for (const request of requests) {
const result = await this.translate(request);
results.push(result);
}
return results;
}
}
/**
* Translation service factory
*/
export class TranslationServiceFactory {
static createMockService(): TranslationService {
return new MockTranslationService();
}
static createContextAwareService(baseService: TranslationService): TranslationService {
return new ContextAwareTranslationService(baseService);
}
static createAIService(provider: 'openai' | 'google' | 'azure' | 'deepl', apiKey: string, baseUrl?: string): TranslationService {
// For now, return mock service - external AI services not implemented
return this.createMockService();
}
static createChatAIService(): TranslationService {
return new ChatAITranslationService();
}
static createService(type: 'mock' | 'context-aware' | 'ai' | 'chat-ai' = 'mock', provider?: 'openai' | 'google' | 'azure' | 'deepl', apiKey?: string): TranslationService {
switch (type) {
case 'mock':
return this.createMockService();
case 'context-aware':
return this.createContextAwareService(this.createMockService());
case 'ai':
if (!provider || !apiKey) {
throw new Error('Provider and API key are required for AI translation service');
}
return this.createAIService(provider, apiKey);
case 'chat-ai':
return this.createChatAIService();
default:
throw new Error(`Unknown translation service type: ${type}`);
}
}
}