feat: P3c LLM集成层增强 (模型目录 + 用量统计 + getModelInfo)
This commit is contained in:
@@ -11,15 +11,32 @@ export interface ChatOptions {
|
|||||||
max_tokens?: number;
|
max_tokens?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ModelInfo {
|
||||||
|
id: string;
|
||||||
|
provider: string;
|
||||||
|
capabilities: string[];
|
||||||
|
contextWindow: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface AIProvider {
|
interface AIProvider {
|
||||||
name: string;
|
name: string;
|
||||||
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MODEL_CATALOG: Record<string, ModelInfo> = {
|
||||||
|
'general': { id: 'general', provider: 'OpenAI 兼容', capabilities: ['chat', 'code'], contextWindow: 8192 },
|
||||||
|
'openai': { id: 'openai', provider: 'OpenAI 兼容', capabilities: ['chat', 'code'], contextWindow: 8192 },
|
||||||
|
'gpt-3.5': { id: 'gpt-3.5', provider: 'OpenAI', capabilities: ['chat', 'code'], contextWindow: 16384 },
|
||||||
|
'gpt-4': { id: 'gpt-4', provider: 'OpenAI', capabilities: ['chat', 'code', 'vision'], contextWindow: 32768 },
|
||||||
|
'opencode-go': { id: 'opencode-go', provider: 'OpenCode Go', capabilities: ['chat', 'code'], contextWindow: 32768 },
|
||||||
|
'deepseek-v4-flash': { id: 'deepseek-v4-flash', provider: 'OpenCode Go', capabilities: ['chat', 'code'], contextWindow: 32768 },
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AIGatewayService {
|
export class AIGatewayService {
|
||||||
private readonly logger = new Logger(AIGatewayService.name);
|
private readonly logger = new Logger(AIGatewayService.name);
|
||||||
private providers: Map<string, AIProvider> = new Map();
|
private providers: Map<string, AIProvider> = new Map();
|
||||||
|
private usageStats: Record<string, { total: number; success: number; failed: number }> = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.registerProviders();
|
this.registerProviders();
|
||||||
@@ -73,15 +90,20 @@ export class AIGatewayService {
|
|||||||
const providerKey = modelMap[model.toLowerCase()] || (model.includes('/') ? 'openai' : model);
|
const providerKey = modelMap[model.toLowerCase()] || (model.includes('/') ? 'openai' : model);
|
||||||
const provider = this.providers.get(providerKey);
|
const provider = this.providers.get(providerKey);
|
||||||
|
|
||||||
|
if (!this.usageStats[providerKey]) this.usageStats[providerKey] = { total: 0, success: 0, failed: 0 };
|
||||||
|
this.usageStats[providerKey].total++;
|
||||||
|
|
||||||
if (provider) {
|
if (provider) {
|
||||||
try {
|
try {
|
||||||
const reply = await provider.chat(messages, options);
|
const reply = await provider.chat(messages, options);
|
||||||
if (typeof reply !== 'string' || reply.length === 0) {
|
if (typeof reply !== 'string' || reply.length === 0) {
|
||||||
throw new Error(`AI 返回内容为空: ${JSON.stringify(reply)}`);
|
throw new Error(`AI 返回内容为空: ${JSON.stringify(reply)}`);
|
||||||
}
|
}
|
||||||
|
this.usageStats[providerKey].success++;
|
||||||
return reply;
|
return reply;
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.logger.error(`${provider.name} 调用失败: ${err.message}`);
|
this.logger.error(`${provider.name} 调用失败: ${err.message}`);
|
||||||
|
this.usageStats[providerKey].failed++;
|
||||||
return this.fallback(messages);
|
return this.fallback(messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,6 +136,15 @@ export class AIGatewayService {
|
|||||||
return `我是宇之然 AI 助手。关于"${lastMsg.slice(0, 50)}..."的问题,我已收到。当前 AI 沙箱处于模拟模式,请配置 API Key 以获取真实回复。已配置的 API:${names}。`;
|
return `我是宇之然 AI 助手。关于"${lastMsg.slice(0, 50)}..."的问题,我已收到。当前 AI 沙箱处于模拟模式,请配置 API Key 以获取真实回复。已配置的 API:${names}。`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModelInfo(model: string): ModelInfo {
|
||||||
|
const key = model.toLowerCase();
|
||||||
|
return MODEL_CATALOG[key] || { id: model, provider: '未知', capabilities: ['chat'], contextWindow: 4096 };
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsageStats() {
|
||||||
|
return { ...this.usageStats };
|
||||||
|
}
|
||||||
|
|
||||||
getRegisteredProviders(): string[] {
|
getRegisteredProviders(): string[] {
|
||||||
return Array.from(this.providers.keys());
|
return Array.from(this.providers.keys());
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user