1 line
12 KiB
JSON
1 line
12 KiB
JSON
{"repo": "123ww321q/memoplan", "files": {"src/services/aiService.ts": {"551a947251d8a469fe5d25e08c4f9d28dbec1e1c": {"t": 1785746044.4006424, "n": 5403, "h": "c3a20febc6a924da", "c": "// AI 服务层 - 支持 DeepSeek API 和后续扩展\nexport interface AIConfig {\n provider: 'deepseek' | 'openai' | 'custom';\n apiKey: string;\n apiUrl?: string;\n model: string;\n temperature: number;\n maxTokens: number;\n}\n\nexport interface AIRequest {\n content: string;\n action: 'summarize' | 'polish' | 'expand' | 'condense' | 'extract-tasks' | 'organize' | 'custom';\n context?: string;\n customPrompt?: string;\n}\n\nexport interface AIResponse {\n success: boolean;\n content: string;\n error?: string;\n}\n\n// 默认配置\nexport const defaultAIConfig: AIConfig = {\n provider: 'deepseek',\n apiKey: '',\n apiUrl: 'https://api.deepseek.com/v1/chat/completions',\n model: 'deepseek-chat',\n temperature: 0.7,\n maxTokens: 2000,\n};\n\n// AI 提示词模板\nconst promptTemplates: Record<string, string> = {\n summarize: '请对以下内容进行简洁的摘要总结,保留核心要点:\\n\\n{{content}}',\n polish: '请对以下内容进行润色优化,提升表达流畅度和专业性,保持原意不变:\\n\\n{{content}}',\n expand: '请对以下内容进行扩写,增加细节和例子,使内容更丰富完整:\\n\\n{{content}}',\n condense: '请对以下内容进行精简,去除冗余信息,保留核心内容:\\n\\n{{content}}',\n 'extract-tasks': '请从以下内容中提取所有待办事项,以列表形式返回:\\n\\n{{content}}',\n organize: '请对以下内容进行结构化整理,添加合适的标题层级和段落划分:\\n\\n{{content}}',\n};\n\n// AI 服务类\nexport class AIService {\n private config: AIConfig;\n\n constructor(config: Partial<AIConfig> = {}) {\n this.config = { ...defaultAIConfig, ...config };\n }\n\n // 更新配置\n updateConfig(config: Partial<AIConfig>) {\n this.config = { ...this.config, ...config };\n }\n\n // 获取当前配置\n getConfig(): AIConfig {\n return { ...this.config };\n }\n\n // 构建请求消息\n private buildMessages(request: AIRequest) {\n const systemPrompt = '你是一个专业的笔记助手,擅长内容整理、润色和结构化。请根据用户要求处理内容,保持格式清晰。';\n \n let userPrompt = '';\n if (request.action === 'custom' && request.customPrompt) {\n userPrompt = request.customPrompt.replace('{{content}}', request.content);\n } else {\n const template = promptTemplates[request.action] || promptTemplates.organize;\n userPrompt = template.replace('{{content}}', request.content);\n }\n\n if (request.context) {\n userPrompt = `上下文信息:\\n${request.context}\\n\\n${userPrompt}`;\n }\n\n return [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ];\n }\n\n // 发送请求\n async process(request: AIRequest): Promise<AIResponse> {\n if (!this.config.apiKey) {\n return {\n success: false,\n content: '',\n error: '请先配置 API Key',\n };\n }\n\n try {\n const response = await fetch(this.config.apiUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: this.buildMessages(request),\n temperature: this.config.temperature,\n max_tokens: this.config.maxTokens,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`API 请求失败: ${error}`);\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content || '';\n\n return {\n success: true,\n content: content.trim(),\n };\n } catch (error) {\n return {\n success: false,\n content: '',\n error: error instanceof Error ? error.message : '未知错误',\n };\n }\n }\n\n // 流式处理(用于实时显示)\n async *processStream(request: AIRequest): AsyncGenerator<string, void, unknown> {\n if (!this.config.apiKey) {\n throw new Error('请先配置 API Key');\n }\n\n const response = await fetch(this.config.apiUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: this.buildMessages(request),\n temperature: this.config.temperature,\n max_tokens: this.config.maxTokens,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n throw new Error('API 请求失败');\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('无法读取响应');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') return;\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.choices?.[0]?.delta?.content;\n if (content) yield content;\n } catch {\n // 忽略解析错误\n }\n }\n }\n }\n }\n}\n\n// 创建单例\nlet aiServiceInstance: AIService | null = null;\n\nexport function getAIService(): AIService {\n if (!aiServiceInstance) {\n // 尝试从 localStorage 加载配置\n const savedConfig = localStorage.getItem('ai-config');\n const config = savedConfig ? JSON.parse(savedConfig) : {};\n aiServiceInstance = new AIService(config);\n }\n return aiServiceInstance;\n}\n\nexport function resetAIService(config?: Partial<AIConfig>) {\n aiServiceInstance = new AIService(config);\n if (config) {\n localStorage.setItem('ai-config', JSON.stringify(aiServiceInstance.getConfig()));\n }\n}\n\nexport default AIService;\n"}, "ce7e8683b3c6dd6201caed1128f5cdc58c4d8913": {"t": 1785759158.5324392, "n": 5403, "h": "c3a20febc6a924da", "c": "// AI 服务层 - 支持 DeepSeek API 和后续扩展\nexport interface AIConfig {\n provider: 'deepseek' | 'openai' | 'custom';\n apiKey: string;\n apiUrl?: string;\n model: string;\n temperature: number;\n maxTokens: number;\n}\n\nexport interface AIRequest {\n content: string;\n action: 'summarize' | 'polish' | 'expand' | 'condense' | 'extract-tasks' | 'organize' | 'custom';\n context?: string;\n customPrompt?: string;\n}\n\nexport interface AIResponse {\n success: boolean;\n content: string;\n error?: string;\n}\n\n// 默认配置\nexport const defaultAIConfig: AIConfig = {\n provider: 'deepseek',\n apiKey: '',\n apiUrl: 'https://api.deepseek.com/v1/chat/completions',\n model: 'deepseek-chat',\n temperature: 0.7,\n maxTokens: 2000,\n};\n\n// AI 提示词模板\nconst promptTemplates: Record<string, string> = {\n summarize: '请对以下内容进行简洁的摘要总结,保留核心要点:\\n\\n{{content}}',\n polish: '请对以下内容进行润色优化,提升表达流畅度和专业性,保持原意不变:\\n\\n{{content}}',\n expand: '请对以下内容进行扩写,增加细节和例子,使内容更丰富完整:\\n\\n{{content}}',\n condense: '请对以下内容进行精简,去除冗余信息,保留核心内容:\\n\\n{{content}}',\n 'extract-tasks': '请从以下内容中提取所有待办事项,以列表形式返回:\\n\\n{{content}}',\n organize: '请对以下内容进行结构化整理,添加合适的标题层级和段落划分:\\n\\n{{content}}',\n};\n\n// AI 服务类\nexport class AIService {\n private config: AIConfig;\n\n constructor(config: Partial<AIConfig> = {}) {\n this.config = { ...defaultAIConfig, ...config };\n }\n\n // 更新配置\n updateConfig(config: Partial<AIConfig>) {\n this.config = { ...this.config, ...config };\n }\n\n // 获取当前配置\n getConfig(): AIConfig {\n return { ...this.config };\n }\n\n // 构建请求消息\n private buildMessages(request: AIRequest) {\n const systemPrompt = '你是一个专业的笔记助手,擅长内容整理、润色和结构化。请根据用户要求处理内容,保持格式清晰。';\n \n let userPrompt = '';\n if (request.action === 'custom' && request.customPrompt) {\n userPrompt = request.customPrompt.replace('{{content}}', request.content);\n } else {\n const template = promptTemplates[request.action] || promptTemplates.organize;\n userPrompt = template.replace('{{content}}', request.content);\n }\n\n if (request.context) {\n userPrompt = `上下文信息:\\n${request.context}\\n\\n${userPrompt}`;\n }\n\n return [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ];\n }\n\n // 发送请求\n async process(request: AIRequest): Promise<AIResponse> {\n if (!this.config.apiKey) {\n return {\n success: false,\n content: '',\n error: '请先配置 API Key',\n };\n }\n\n try {\n const response = await fetch(this.config.apiUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: this.buildMessages(request),\n temperature: this.config.temperature,\n max_tokens: this.config.maxTokens,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`API 请求失败: ${error}`);\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content || '';\n\n return {\n success: true,\n content: content.trim(),\n };\n } catch (error) {\n return {\n success: false,\n content: '',\n error: error instanceof Error ? error.message : '未知错误',\n };\n }\n }\n\n // 流式处理(用于实时显示)\n async *processStream(request: AIRequest): AsyncGenerator<string, void, unknown> {\n if (!this.config.apiKey) {\n throw new Error('请先配置 API Key');\n }\n\n const response = await fetch(this.config.apiUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n messages: this.buildMessages(request),\n temperature: this.config.temperature,\n max_tokens: this.config.maxTokens,\n stream: true,\n }),\n });\n\n if (!response.ok) {\n throw new Error('API 请求失败');\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('无法读取响应');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') return;\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.choices?.[0]?.delta?.content;\n if (content) yield content;\n } catch {\n // 忽略解析错误\n }\n }\n }\n }\n }\n}\n\n// 创建单例\nlet aiServiceInstance: AIService | null = null;\n\nexport function getAIService(): AIService {\n if (!aiServiceInstance) {\n // 尝试从 localStorage 加载配置\n const savedConfig = localStorage.getItem('ai-config');\n const config = savedConfig ? JSON.parse(savedConfig) : {};\n aiServiceInstance = new AIService(config);\n }\n return aiServiceInstance;\n}\n\nexport function resetAIService(config?: Partial<AIConfig>) {\n aiServiceInstance = new AIService(config);\n if (config) {\n localStorage.setItem('ai-config', JSON.stringify(aiServiceInstance.getConfig()));\n }\n}\n\nexport default AIService;\n"}}}} |