564 lines
16 KiB
Plaintext
564 lines
16 KiB
Plaintext
// AI Service Manager - Unified coordinator for all AI services
|
||
|
||
import {
|
||
AIServiceConfig,
|
||
AIProvider,
|
||
AIResponse,
|
||
AIServiceError,
|
||
UsageStatistics,
|
||
CacheOptions
|
||
} from '../types/ai-types.uts'
|
||
|
||
import { AITranslationService } from './AITranslationService.uts'
|
||
import { AIContentAnalysisService } from './AIContentAnalysisService.uts'
|
||
import { AIChatService } from './AIChatService.uts'
|
||
import { AIRecommendationService } from './AIRecommendationService.uts'
|
||
import { ContentProcessingPipeline } from './ContentProcessingPipeline.uts'
|
||
|
||
// 服务状态枚举
|
||
type ServiceStatus = 'initializing' | 'ready' | 'busy' | 'error' | 'maintenance'
|
||
|
||
// 服务健康状态
|
||
type ServiceHealth = {
|
||
status: ServiceStatus
|
||
lastChecked: number
|
||
responseTime: number
|
||
errorRate: number
|
||
uptime: number
|
||
version: string
|
||
capabilities: string[]
|
||
}
|
||
|
||
// 负载均衡策略
|
||
type LoadBalanceStrategy = 'round_robin' | 'least_connections' | 'weighted' | 'random'
|
||
|
||
// 服务监控配置
|
||
type MonitoringConfig = {
|
||
healthCheckInterval: number // 健康检查间隔(毫秒)
|
||
maxErrorRate: number // 最大错误率
|
||
maxResponseTime: number // 最大响应时间(毫秒)
|
||
alertThresholds: {
|
||
errorRate: number
|
||
responseTime: number
|
||
dailyCost: number
|
||
}
|
||
}
|
||
|
||
// 成本控制配置
|
||
type CostControlConfig = {
|
||
dailyLimit: number // 每日成本限制(USD)
|
||
monthlyLimit: number // 每月成本限制(USD)
|
||
perRequestLimit: number // 单次请求成本限制(USD)
|
||
alertThresholds: {
|
||
daily: number // 每日预警阈值
|
||
monthly: number // 每月预警阈值
|
||
}
|
||
}
|
||
|
||
// 管理器统计
|
||
type ManagerStats = {
|
||
totalRequests: number
|
||
successfulRequests: number
|
||
failedRequests: number
|
||
totalCost: number
|
||
avgResponseTime: number
|
||
servicesHealth: Record<string, ServiceHealth>
|
||
dailyUsage: UsageStatistics[]
|
||
costBreakdown: Record<AIProvider, number>
|
||
lastReset: number
|
||
}
|
||
|
||
/**
|
||
* AI服务管理器
|
||
* 统一管理所有AI服务,提供负载均衡、监控、成本控制等功能
|
||
*/
|
||
export class AIServiceManager {
|
||
private config: AIServiceConfig
|
||
private monitoringConfig: MonitoringConfig
|
||
private costControlConfig: CostControlConfig
|
||
private cacheOptions: CacheOptions
|
||
|
||
// 服务实例
|
||
private translationService: AITranslationService
|
||
private analysisService: AIContentAnalysisService
|
||
private chatService: AIChatService
|
||
private recommendationService: AIRecommendationService
|
||
private processingPipeline: ContentProcessingPipeline
|
||
|
||
// 状态管理
|
||
private servicesHealth: Map<string, ServiceHealth> = new Map()
|
||
private loadBalanceState: Map<AIProvider, number> = new Map()
|
||
private stats: ManagerStats
|
||
private healthCheckInterval: any
|
||
private isInitialized: boolean = false
|
||
|
||
constructor(
|
||
config: AIServiceConfig,
|
||
monitoringConfig: Partial<MonitoringConfig> = {},
|
||
costControlConfig: Partial<CostControlConfig> = {},
|
||
cacheOptions: Partial<CacheOptions> = {}
|
||
) {
|
||
this.config = config
|
||
this.monitoringConfig = this.createDefaultMonitoringConfig(monitoringConfig)
|
||
this.costControlConfig = this.createDefaultCostControlConfig(costControlConfig)
|
||
this.cacheOptions = this.createDefaultCacheOptions(cacheOptions)
|
||
this.stats = this.initializeStats()
|
||
|
||
this.initializeServices()
|
||
}
|
||
|
||
/**
|
||
* 初始化所有服务
|
||
*/
|
||
async initialize(): Promise<AIResponse<boolean>> {
|
||
try {
|
||
console.log('Initializing AI Service Manager...')
|
||
|
||
// 初始化各个服务
|
||
this.translationService = new AITranslationService(this.config, this.cacheOptions)
|
||
this.analysisService = new AIContentAnalysisService(this.config)
|
||
this.chatService = new AIChatService(this.config)
|
||
this.recommendationService = new AIRecommendationService(this.config)
|
||
this.processingPipeline = new ContentProcessingPipeline(this.config)
|
||
|
||
// 初始化服务健康状态
|
||
await this.initializeHealthStatus()
|
||
|
||
// 启动健康检查
|
||
this.startHealthMonitoring()
|
||
|
||
// 初始化负载均衡状态
|
||
this.initializeLoadBalancing()
|
||
|
||
this.isInitialized = true
|
||
console.log('AI Service Manager initialized successfully')
|
||
|
||
return { success: true, data: true }
|
||
|
||
} catch (error) {
|
||
console.error('Failed to initialize AI Service Manager:', error)
|
||
return {
|
||
success: false,
|
||
error: error.message || 'Initialization failed'
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取翻译服务
|
||
*/
|
||
getTranslationService(): AITranslationService {
|
||
this.ensureInitialized()
|
||
return this.translationService
|
||
}
|
||
|
||
/**
|
||
* 获取内容分析服务
|
||
*/
|
||
getAnalysisService(): AIContentAnalysisService {
|
||
this.ensureInitialized()
|
||
return this.analysisService
|
||
}
|
||
|
||
/**
|
||
* 获取聊天服务
|
||
*/
|
||
getChatService(): AIChatService {
|
||
this.ensureInitialized()
|
||
return this.chatService
|
||
}
|
||
|
||
/**
|
||
* 获取推荐服务
|
||
*/
|
||
getRecommendationService(): AIRecommendationService {
|
||
this.ensureInitialized()
|
||
return this.recommendationService
|
||
}
|
||
|
||
/**
|
||
* 获取内容处理管道
|
||
*/
|
||
getProcessingPipeline(): ContentProcessingPipeline {
|
||
this.ensureInitialized()
|
||
return this.processingPipeline
|
||
}
|
||
|
||
/**
|
||
* 选择最佳提供商
|
||
* @param serviceType 服务类型
|
||
*/
|
||
selectBestProvider(serviceType: string = 'general'): AIProvider {
|
||
const availableProviders = this.getAvailableProviders()
|
||
|
||
if (availableProviders.length === 0) {
|
||
return 'openai' // 默认提供商
|
||
}
|
||
|
||
// 基于健康状态和负载均衡策略选择
|
||
return this.applyLoadBalancing(availableProviders, serviceType)
|
||
}
|
||
|
||
/**
|
||
* 检查成本限制
|
||
* @param estimatedCost 预估成本
|
||
*/
|
||
checkCostLimits(estimatedCost: number): boolean {
|
||
const now = new Date()
|
||
const today = now.toISOString().split('T')[0]
|
||
const currentMonth = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}`
|
||
|
||
// 检查每日限制
|
||
const dailyCost = this.getDailyCost(today)
|
||
if (dailyCost + estimatedCost > this.costControlConfig.dailyLimit) {
|
||
console.warn(`Daily cost limit exceeded: ${dailyCost + estimatedCost} > ${this.costControlConfig.dailyLimit}`)
|
||
return false
|
||
}
|
||
|
||
// 检查每月限制
|
||
const monthlyCost = this.getMonthlyCost(currentMonth)
|
||
if (monthlyCost + estimatedCost > this.costControlConfig.monthlyLimit) {
|
||
console.warn(`Monthly cost limit exceeded: ${monthlyCost + estimatedCost} > ${this.costControlConfig.monthlyLimit}`)
|
||
return false
|
||
}
|
||
|
||
// 检查单次请求限制
|
||
if (estimatedCost > this.costControlConfig.perRequestLimit) {
|
||
console.warn(`Per-request cost limit exceeded: ${estimatedCost} > ${this.costControlConfig.perRequestLimit}`)
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
/**
|
||
* 记录使用统计
|
||
* @param provider 提供商
|
||
* @param serviceType 服务类型
|
||
* @param stats 统计信息
|
||
*/
|
||
recordUsage(provider: AIProvider, serviceType: string, stats: Partial<UsageStatistics>): void {
|
||
this.stats.totalRequests++
|
||
|
||
if (stats.requestsCount && stats.requestsCount > 0) {
|
||
this.stats.successfulRequests++
|
||
} else {
|
||
this.stats.failedRequests++
|
||
}
|
||
|
||
this.stats.totalCost += stats.costUSD || 0
|
||
this.stats.costBreakdown[provider] = (this.stats.costBreakdown[provider] || 0) + (stats.costUSD || 0)
|
||
|
||
if (stats.avgResponseTimeMs) {
|
||
this.stats.avgResponseTime = (
|
||
this.stats.avgResponseTime * (this.stats.totalRequests - 1) + stats.avgResponseTimeMs
|
||
) / this.stats.totalRequests
|
||
}
|
||
|
||
// 记录每日使用情况
|
||
const today = new Date().toISOString().split('T')[0]
|
||
const hour = new Date().getHours()
|
||
|
||
const dailyStats: UsageStatistics = {
|
||
provider,
|
||
serviceType,
|
||
tokensUsed: stats.tokensUsed || 0,
|
||
requestsCount: stats.requestsCount || 0,
|
||
costUSD: stats.costUSD || 0,
|
||
successCount: stats.successCount || 0,
|
||
errorCount: stats.errorCount || 0,
|
||
avgResponseTimeMs: stats.avgResponseTimeMs || 0,
|
||
date: today,
|
||
hour
|
||
}
|
||
|
||
this.stats.dailyUsage.push(dailyStats)
|
||
|
||
// 保持最近30天的数据
|
||
const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
|
||
this.stats.dailyUsage = this.stats.dailyUsage.filter(usage => usage.date >= cutoffDate)
|
||
}
|
||
|
||
/**
|
||
* 获取服务健康状态
|
||
*/
|
||
getServicesHealth(): Record<string, ServiceHealth> {
|
||
const health: Record<string, ServiceHealth> = {}
|
||
for (const [serviceName, serviceHealth] of this.servicesHealth.entries()) {
|
||
health[serviceName] = { ...serviceHealth }
|
||
}
|
||
return health
|
||
}
|
||
|
||
/**
|
||
* 获取管理器统计
|
||
*/
|
||
getManagerStatistics(): ManagerStats {
|
||
return {
|
||
...this.stats,
|
||
servicesHealth: this.getServicesHealth()
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 重置统计数据
|
||
*/
|
||
resetStatistics(): void {
|
||
this.stats = this.initializeStats()
|
||
}
|
||
|
||
/**
|
||
* 停止所有服务
|
||
*/
|
||
async shutdown(): Promise<void> {
|
||
console.log('Shutting down AI Service Manager...')
|
||
|
||
// 停止健康检查
|
||
if (this.healthCheckInterval) {
|
||
clearInterval(this.healthCheckInterval)
|
||
}
|
||
|
||
// 清理缓存
|
||
if (this.translationService) {
|
||
this.translationService.clearCache()
|
||
}
|
||
|
||
this.isInitialized = false
|
||
console.log('AI Service Manager shut down completed')
|
||
}
|
||
|
||
// Private methods
|
||
|
||
private initializeServices(): void {
|
||
// 初始化负载均衡状态
|
||
const providers: AIProvider[] = ['openai', 'google', 'baidu', 'custom']
|
||
providers.forEach(provider => {
|
||
this.loadBalanceState.set(provider, 0)
|
||
})
|
||
}
|
||
|
||
private async initializeHealthStatus(): Promise<void> {
|
||
const services = ['translation', 'analysis', 'chat', 'recommendation', 'pipeline']
|
||
|
||
for (const serviceName of services) {
|
||
const health: ServiceHealth = {
|
||
status: 'ready',
|
||
lastChecked: Date.now(),
|
||
responseTime: 0,
|
||
errorRate: 0,
|
||
uptime: Date.now(),
|
||
version: '1.0.0',
|
||
capabilities: this.getServiceCapabilities(serviceName)
|
||
}
|
||
|
||
this.servicesHealth.set(serviceName, health)
|
||
}
|
||
}
|
||
|
||
private getServiceCapabilities(serviceName: string): string[] {
|
||
const capabilities: Record<string, string[]> = {
|
||
translation: ['text_translation', 'language_detection', 'batch_translation'],
|
||
analysis: ['sentiment_analysis', 'entity_extraction', 'content_classification', 'quality_assessment'],
|
||
chat: ['conversation', 'multilingual_support', 'context_awareness'],
|
||
recommendation: ['personalized_recommendations', 'trending_content', 'similarity_matching'],
|
||
pipeline: ['automated_processing', 'batch_processing', 'workflow_management']
|
||
}
|
||
|
||
return capabilities[serviceName] || []
|
||
}
|
||
|
||
private startHealthMonitoring(): void {
|
||
this.healthCheckInterval = setInterval(() => {
|
||
this.performHealthCheck()
|
||
}, this.monitoringConfig.healthCheckInterval)
|
||
}
|
||
|
||
private async performHealthCheck(): Promise<void> {
|
||
for (const [serviceName, health] of this.servicesHealth.entries()) {
|
||
try {
|
||
const startTime = Date.now()
|
||
|
||
// 执行简单的健康检查
|
||
await this.checkServiceHealth(serviceName)
|
||
|
||
const responseTime = Date.now() - startTime
|
||
|
||
// 更新健康状态
|
||
health.lastChecked = Date.now()
|
||
health.responseTime = responseTime
|
||
health.status = responseTime > this.monitoringConfig.maxResponseTime ? 'error' : 'ready'
|
||
|
||
// 检查错误率
|
||
if (health.errorRate > this.monitoringConfig.maxErrorRate) {
|
||
health.status = 'error'
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error(`Health check failed for ${serviceName}:`, error)
|
||
this.servicesHealth.get(serviceName)!.status = 'error'
|
||
}
|
||
}
|
||
}
|
||
|
||
private async checkServiceHealth(serviceName: string): Promise<void> {
|
||
// 简单的健康检查实现
|
||
switch (serviceName) {
|
||
case 'translation':
|
||
// 可以测试一个简单的翻译
|
||
break
|
||
case 'analysis':
|
||
// 可以测试一个简单的分析
|
||
break
|
||
case 'chat':
|
||
// 可以检查会话状态
|
||
break
|
||
case 'recommendation':
|
||
// 可以检查推荐算法状态
|
||
break
|
||
case 'pipeline':
|
||
// 可以检查处理管道状态
|
||
break
|
||
}
|
||
|
||
// 模拟健康检查延迟
|
||
await this.delay(Math.random() * 100 + 50)
|
||
}
|
||
|
||
private initializeLoadBalancing(): void {
|
||
const providers = this.getAvailableProviders()
|
||
providers.forEach(provider => {
|
||
this.loadBalanceState.set(provider, 0)
|
||
})
|
||
}
|
||
|
||
private getAvailableProviders(): AIProvider[] {
|
||
const providers: AIProvider[] = []
|
||
|
||
if (this.config.openai?.apiKey) providers.push('openai')
|
||
if (this.config.google?.apiKey) providers.push('google')
|
||
if (this.config.baidu?.apiKey) providers.push('baidu')
|
||
|
||
return providers
|
||
}
|
||
|
||
private applyLoadBalancing(providers: AIProvider[], serviceType: string): AIProvider {
|
||
// 过滤健康的提供商
|
||
const healthyProviders = providers.filter(provider => {
|
||
const serviceName = this.getServiceNameForProvider(provider, serviceType)
|
||
const health = this.servicesHealth.get(serviceName)
|
||
return health && health.status === 'ready'
|
||
})
|
||
|
||
if (healthyProviders.length === 0) {
|
||
return providers[0] // 回退到第一个可用提供商
|
||
}
|
||
|
||
// 轮询策略
|
||
const providerCounts = healthyProviders.map(provider => ({
|
||
provider,
|
||
count: this.loadBalanceState.get(provider) || 0
|
||
}))
|
||
|
||
// 选择使用次数最少的提供商
|
||
const selectedProvider = providerCounts.reduce((min, current) =>
|
||
current.count < min.count ? current : min
|
||
).provider
|
||
|
||
// 更新计数
|
||
this.loadBalanceState.set(selectedProvider, (this.loadBalanceState.get(selectedProvider) || 0) + 1)
|
||
|
||
return selectedProvider
|
||
}
|
||
|
||
private getServiceNameForProvider(provider: AIProvider, serviceType: string): string {
|
||
// 根据提供商和服务类型映射到内部服务名称
|
||
const serviceMap: Record<string, string> = {
|
||
'translation': 'translation',
|
||
'analysis': 'analysis',
|
||
'chat': 'chat',
|
||
'recommendation': 'recommendation'
|
||
}
|
||
|
||
return serviceMap[serviceType] || 'translation'
|
||
}
|
||
|
||
private getDailyCost(date: string): number {
|
||
return this.stats.dailyUsage
|
||
.filter(usage => usage.date === date)
|
||
.reduce((total, usage) => total + usage.costUSD, 0)
|
||
}
|
||
|
||
private getMonthlyCost(month: string): number {
|
||
return this.stats.dailyUsage
|
||
.filter(usage => usage.date.startsWith(month))
|
||
.reduce((total, usage) => total + usage.costUSD, 0)
|
||
}
|
||
|
||
private ensureInitialized(): void {
|
||
if (!this.isInitialized) {
|
||
throw new Error('AI Service Manager not initialized. Call initialize() first.')
|
||
}
|
||
}
|
||
|
||
private createDefaultMonitoringConfig(overrides: Partial<MonitoringConfig>): MonitoringConfig {
|
||
return {
|
||
healthCheckInterval: 60000, // 1分钟
|
||
maxErrorRate: 0.1, // 10%
|
||
maxResponseTime: 5000, // 5秒
|
||
alertThresholds: {
|
||
errorRate: 0.05, // 5%
|
||
responseTime: 3000, // 3秒
|
||
dailyCost: 100 // $100
|
||
},
|
||
...overrides
|
||
}
|
||
}
|
||
|
||
private createDefaultCostControlConfig(overrides: Partial<CostControlConfig>): CostControlConfig {
|
||
return {
|
||
dailyLimit: 200, // $200
|
||
monthlyLimit: 5000, // $5000
|
||
perRequestLimit: 10, // $10
|
||
alertThresholds: {
|
||
daily: 150, // $150
|
||
monthly: 4000 // $4000
|
||
},
|
||
...overrides
|
||
}
|
||
}
|
||
|
||
private createDefaultCacheOptions(overrides: Partial<CacheOptions>): CacheOptions {
|
||
return {
|
||
enabled: true,
|
||
ttlHours: 24,
|
||
maxSize: 10000,
|
||
strategy: 'lru',
|
||
...overrides
|
||
}
|
||
}
|
||
|
||
private initializeStats(): ManagerStats {
|
||
const providers: AIProvider[] = ['openai', 'google', 'baidu', 'custom']
|
||
const costBreakdown: Record<AIProvider, number> = {} as Record<AIProvider, number>
|
||
providers.forEach(provider => {
|
||
costBreakdown[provider] = 0
|
||
})
|
||
|
||
return {
|
||
totalRequests: 0,
|
||
successfulRequests: 0,
|
||
failedRequests: 0,
|
||
totalCost: 0,
|
||
avgResponseTime: 0,
|
||
servicesHealth: {},
|
||
dailyUsage: [],
|
||
costBreakdown,
|
||
lastReset: Date.now()
|
||
}
|
||
}
|
||
|
||
private async delay(ms: number): Promise<void> {
|
||
return new Promise(resolve => setTimeout(resolve, ms))
|
||
}
|
||
}
|