Initial commit of akmon project
This commit is contained in:
563
uni_modules/ak-ai-news/services/AIServiceManager.uts
Normal file
563
uni_modules/ak-ai-news/services/AIServiceManager.uts
Normal file
@@ -0,0 +1,563 @@
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user