From 01c4777691b6db6052e3edcbd12e03b2b4a0c9db Mon Sep 17 00:00:00 2001 From: MyPrototypeWhat Date: Wed, 3 Sep 2025 17:10:41 +0800 Subject: [PATCH] chore: update release notes and version to 1.6.0-beta.6 - Refined performance optimizations for AI services and improved compatibility with various providers. - Enhanced error handling and stability in the ModernAiProvider class. - Updated version in package.json to 1.6.0-beta.6. --- electron-builder.yml | 28 +++------ package.json | 2 +- src/renderer/src/aiCore/index_new.ts | 58 ++++++++++++++----- .../src/aiCore/provider/providerConfig.ts | 12 +++- src/renderer/src/services/ApiService.ts | 2 +- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/electron-builder.yml b/electron-builder.yml index adc22e83f6..dbafecb548 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -121,26 +121,12 @@ afterSign: scripts/notarize.js artifactBuildCompleted: scripts/artifact-build-completed.js releaseInfo: releaseNotes: | - ✨ 重要更新: - - 增强Web搜索功能:重构搜索结果处理和展示逻辑 - - 优化知识库设置:默认关闭知识识别以提升性能 - - 新增Gemini 2.5 Flash Image模型的自动图像生成功能 - - 支持链接OG数据解析和预览展示 - - 增强OCR服务的Linux兼容性 - 🔧 性能优化: - - 重构AI核心架构,采用现代化的AI SDK 5.0 - - 优化消息重试机制,新增"重试失败消息"按钮 - - 改进侧边栏动画效果和用户交互体验 - - 优化Vite构建系统,使用Rolldown引擎提升构建性能 - - 重构参数处理和文件处理模块 - - 优化API key轮转机制 + - 优化AI服务连接方式,提升响应速度和稳定性 + - 改进模型列表获取功能,减少不必要的网络请求 + - 增强各AI服务商的兼容性和连接可靠性 - 🐛 修复问题: - - 修复tabs组件高度不足导致边框样式问题 - - 修复Gemini 2.5 Flash Image模型的图像生成按钮状态 - - 修复ModelScope DeepSeek v3.1思考模式问题 - - 修复PoeLogo在provider UI组件中的渲染问题 - - 修复ASAR集成相关问题 - - 移除加载状态阻塞输入的问题 - - 修复多个UI组件和样式问题 + 🐛 问题修复: + - 修复部分AI服务商连接失败的问题 + - 修复模型配置加载时的潜在错误 + - 提升应用整体稳定性和容错能力 diff --git a/package.json b/package.json index 839c7899d4..1559ff7554 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CherryStudio", - "version": "1.6.0-beta.5", + "version": "1.6.0-beta.6", "private": true, "description": "A powerful AI assistant for producer.", "main": "./out/main/index.js", diff --git a/src/renderer/src/aiCore/index_new.ts b/src/renderer/src/aiCore/index_new.ts index 84b00a1090..071b6102e9 100644 --- a/src/renderer/src/aiCore/index_new.ts +++ b/src/renderer/src/aiCore/index_new.ts @@ -42,18 +42,36 @@ export type ModernAiProviderConfig = AiSdkMiddlewareConfig & { export default class ModernAiProvider { private legacyProvider: LegacyAiProvider - private config: ReturnType + private config?: ReturnType private actualProvider: Provider - private model: Model + private model?: Model private localProvider: Awaited | null = null - constructor(model: Model, provider?: Provider) { - this.actualProvider = provider || getActualProvider(model) - this.legacyProvider = new LegacyAiProvider(this.actualProvider) - this.model = model + // 构造函数重载签名 + constructor(model: Model, provider?: Provider) + constructor(provider: Provider) + constructor(modelOrProvider: Model | Provider, provider?: Provider) + constructor(modelOrProvider: Model | Provider, provider?: Provider) { + if (this.isModel(modelOrProvider)) { + // 传入的是 Model + this.model = modelOrProvider + this.actualProvider = provider || getActualProvider(modelOrProvider) + // 只保存配置,不预先创建executor + this.config = providerToAiSdkConfig(this.actualProvider, modelOrProvider) + } else { + // 传入的是 Provider + this.actualProvider = modelOrProvider + // model为可选,某些操作(如fetchModels)不需要model + } - // 只保存配置,不预先创建executor - this.config = providerToAiSdkConfig(this.actualProvider, model) + this.legacyProvider = new LegacyAiProvider(this.actualProvider) + } + + /** + * 类型守卫函数:通过 provider 属性区分 Model 和 Provider + */ + private isModel(obj: Model | Provider): obj is Model { + return 'provider' in obj && typeof obj.provider === 'string' } public getActualProvider() { @@ -61,6 +79,16 @@ export default class ModernAiProvider { } public async completions(modelId: string, params: StreamTextParams, config: ModernAiProviderConfig) { + // 检查model是否存在 + if (!this.model) { + throw new Error('Model is required for completions. Please use constructor with model parameter.') + } + + // 确保配置存在 + if (!this.config) { + this.config = providerToAiSdkConfig(this.actualProvider, this.model) + } + // 准备特殊配置 await prepareSpecialProviderConfig(this.actualProvider, this.config) @@ -127,7 +155,7 @@ export default class ModernAiProvider { params: StreamTextParams, config: ModernAiProviderConfig & { topicId: string } ): Promise { - const modelId = this.model.id + const modelId = this.model!.id const traceName = `${this.actualProvider.name}.${modelId}.${config.callType}` const traceParams: StartSpanParams = { name: traceName, @@ -211,10 +239,10 @@ export default class ModernAiProvider { params: StreamTextParams, config: ModernAiProviderConfig ): Promise { - const modelId = this.model.id + const modelId = this.model!.id logger.info('Starting modernCompletions', { modelId, - providerId: this.config.providerId, + providerId: this.config!.providerId, topicId: config.topicId, hasOnChunk: !!config.onChunk, hasTools: !!params.tools && Object.keys(params.tools).length > 0, @@ -225,11 +253,11 @@ export default class ModernAiProvider { const plugins = buildPlugins(config) // 用构建好的插件数组创建executor - const executor = createExecutor(this.config.providerId, this.config.options, plugins) + const executor = createExecutor(this.config!.providerId, this.config!.options, plugins) // 创建带有中间件的执行器 if (config.onChunk) { - const accumulate = this.model.supported_text_delta !== false // true and undefined + const accumulate = this.model!.supported_text_delta !== false // true and undefined const adapter = new AiSdkToChunkAdapter(config.onChunk, config.mcpTools, accumulate) const streamResult = await executor.streamText({ @@ -308,7 +336,7 @@ export default class ModernAiProvider { } // 调用新 AI SDK 的图像生成功能 - const executor = createExecutor(this.config.providerId, this.config.options, []) + const executor = createExecutor(this.config!.providerId, this.config!.options, []) const result = await executor.generateImage({ model, ...imageParams @@ -428,7 +456,7 @@ export default class ModernAiProvider { ...(signal && { abortSignal: signal }) } - const executor = createExecutor(this.config.providerId, this.config.options, []) + const executor = createExecutor(this.config!.providerId, this.config!.options, []) const result = await executor.generateImage({ model: this.localProvider?.imageModel(model) as ImageModel, ...aiSdkParams diff --git a/src/renderer/src/aiCore/provider/providerConfig.ts b/src/renderer/src/aiCore/provider/providerConfig.ts index 2a0efb21f0..63d1b6ed54 100644 --- a/src/renderer/src/aiCore/provider/providerConfig.ts +++ b/src/renderer/src/aiCore/provider/providerConfig.ts @@ -131,12 +131,21 @@ export function providerToAiSdkConfig( // 添加额外headers if (actualProvider.extra_headers) { extraOptions.headers = actualProvider.extra_headers + // copy from openaiBaseClient/openaiResponseApiClient + if (aiSdkProviderId === 'openai') { + extraOptions.headers = { + ...extraOptions.headers, + 'HTTP-Referer': 'https://cherry-ai.com', + 'X-Title': 'Cherry Studio', + 'X-Api-Key': baseConfig.apiKey + } + } } // copilot if (actualProvider.id === 'copilot') { extraOptions.headers = { - ...extraOptions.extra_headers, + ...extraOptions.headers, 'editor-version': 'vscode/1.97.2', 'copilot-vision-request': 'true' } @@ -183,7 +192,6 @@ export function providerToAiSdkConfig( } else if (baseConfig.baseURL.endsWith('/v1')) { baseConfig.baseURL = baseConfig.baseURL.slice(0, -3) } - baseConfig.baseURL = isEmpty(baseConfig.baseURL) ? '' : baseConfig.baseURL } diff --git a/src/renderer/src/services/ApiService.ts b/src/renderer/src/services/ApiService.ts index f559e3317c..3e09050ea3 100644 --- a/src/renderer/src/services/ApiService.ts +++ b/src/renderer/src/services/ApiService.ts @@ -350,7 +350,7 @@ export function hasApiKey(provider: Provider) { // } export async function fetchModels(provider: Provider): Promise { - const AI = new AiProviderNew({} as Model, provider) + const AI = new AiProviderNew(provider) try { return await AI.models()