diff --git a/README.en.md b/README.en.md
index 66824e3..31acaee 100644
--- a/README.en.md
+++ b/README.en.md
@@ -14,7 +14,7 @@
## ✨ Features
-- 🤖 **Multi AI Engines** — Ollama, MiMo, GLM, QwQ, MaaS and more
+- 🤖 **Multi AI Engines** — Ollama local models + OpenAI compatible format (DeepSeek, Grok, SiliconFlow, etc.)
- 🔧 **Precise Code Editing** — Search & replace, batch edits, diff comparison, line-level operations
- 🔍 **Code Search & Understanding** — Cross-file search, regex matching, symbol extraction, dependency analysis
- 🔄 **Git Integration** — Full Git workflow support
@@ -43,7 +43,7 @@ python -m xiaoli
python -m xiaoli --cli
# Specify engine
-python -m xiaoli --engine mimo
+python -m xiaoli --engine openai
# Show version
python -m xiaoli --version
diff --git a/README.md b/README.md
index 71e80c6..fe1246e 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
## ✨ 特性
-- 🤖 **多 AI 引擎** — 支持 Ollama、MiMo、智谱 GLM、QwQ、MaaS 等,随时切换
+- 🤖 **多 AI 引擎** — 支持 Ollama 本地模型 + OpenAI 兼容格式(DeepSeek、Grok、硅基流动等),随时切换
- 🔧 **精准代码编辑** — 搜索替换、批量编辑、diff 对比、行级操作
- 🔍 **代码搜索理解** — 跨文件搜索、正则匹配、符号提取、依赖分析
- 🔄 **Git 版本控制** — 完整 Git 操作支持
@@ -46,7 +46,7 @@ python -m xiaoli
python -m xiaoli --cli
# 指定引擎
-python -m xiaoli --engine mimo
+python -m xiaoli --engine openai
# 查看版本
python -m xiaoli --version
@@ -112,12 +112,7 @@ xiaoli-cli/
│
├── ai_engines/ # AI 引擎
│ ├── ollama_engine.py # Ollama 本地模型
-│ ├── mimo_engine.py # 小米 MiMo
-│ ├── GLM_http_engine.py # 智谱 GLM
-│ ├── qwq_engine.py # QwQ 深度思考
-│ ├── xfyun_spark_engine.py # 讯飞星火
-│ ├── SDK_openAI.py # OpenAI 兼容 SDK
-│ └── ...
+│ └── openai_engine.py # OpenAI 兼容格式(DeepSeek/Grok/硅基流动等)
│
├── image_engine/ # 图像引擎
├── core/ # 旧版核心模块(兼容)
@@ -196,12 +191,23 @@ def new():
| 引擎 | 类型 | 说明 |
|------|------|------|
| `ollama` | 本地 | Ollama 本地模型,无需 API 密钥 |
-| `mimo` | 云端 | 小米 MiMo |
-| `glm_http` | 云端 | 智谱 GLM |
-| `qwq` | 云端 | QwQ 深度思考引擎 |
-| `maas_http` | 云端 | MaaS |
-| `spark` | 云端 | 讯飞星火 |
-| `iflow` | 云端 | iFlow API |
+| `openai` | 云端/本地 | OpenAI 兼容格式,支持 DeepSeek、Grok、硅基流动、本地 vLLM 等 |
+
+#### OpenAI 兼容引擎配置示例
+
+```json
+{
+ "api": {
+ "engines": {
+ "openai": {
+ "api_key": "你的API密钥",
+ "base_url": "https://api.deepseek.com/v1",
+ "model": "deepseek-chat"
+ }
+ }
+ }
+}
+```
### 远程连接
diff --git a/ai_engines/GLM_http_engine.py b/ai_engines/GLM_http_engine.py
deleted file mode 100644
index 0c990e8..0000000
--- a/ai_engines/GLM_http_engine.py
+++ /dev/null
@@ -1,210 +0,0 @@
-import os
-import json
-import requests
-from colorama import Fore, Style
-from openai import OpenAI
-
-# 获取项目根目录
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir)
-
-
-class Glm_http_engineAI:
- """基于HTTP协议的智谱AI GLM引擎"""
- requires_api_key = True # GLM HTTP引擎需要API密钥
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = """
-GLM HTTP AI引擎插件帮助信息
-==========================
-
-引擎名称: glm_http
-描述: 基于HTTP协议的智谱AI GLM(GLM-4.5-Flash)引擎,支持智谱AI服务
-
-可用命令:
- 无特定命令,直接与AI对话即可
-
-使用说明:
-1. 此引擎使用HTTP协议调用智谱AI API
-2. 使用/engine.switch glm_http切换到此引擎
-3. 直接输入自然语言与AI对话
-4. 支持普通对话、流式对话、JSON模式等多种调用方式
-"""
- return help_text
-
- def __init__(self):
- self.name = "glm_http"
- self.cli = None
-
- # 直接从 config.json 读取配置
- config_file = os.path.join(project_root, "config.json")
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("GLM_http", {})
- self.api_key = engine_config.get("api_key", "")
- self.base_url = engine_config.get("base_url", "")
- self.model_id = engine_config.get("model", "")
- except Exception as e:
- # 如果读取失败,使用空值
- self.api_key = ""
- self.base_url = ""
- self.model_id = ""
-
- # 初始化对话历史
- self.conversation_history = []
- # 共享对话历史引用(由CLI设置)
- self.shared_conversation_history = None
- # 设置最大历史记录数
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- self.max_history = config.get("system", {}).get("max_history", 10)
- except:
- self.max_history = 10
-
- # 初始化 OpenAI 客户端(配置从 config.json 动态读取)
- try:
- self.client = OpenAI(
- api_key=self.api_key,
- base_url=self.base_url if self.base_url else None,
- timeout=None
- )
- except Exception as e:
- print(f"初始化 OpenAI 客户端失败: {e}")
- self.client = None
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI響應 - 使用智谱AI HTTP API"""
- try:
- # 如果有工具結果,將其作為上下文返回給AI處理
- if tool_results:
- tool_result_text = f"工具執行結果: {tool_results.get('result', '無結果')}"
-
- # 構建包含歷史記錄的消息列表
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "智谱AI HTTP API調用失敗"
-
- # 構建包含歷史記錄的消息列表
- messages = self._build_messages_with_history(system_prompt, user_input)
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "智谱AI HTTP API調用失敗"
-
- except Exception as e:
- # 如果API調用失敗,返回錯誤信息
- return f"智谱AI HTTP API調用失敗: {str(e)}"
-
- def _call_api(self, messages, use_stream=False, extra_body=None):
- """調用API的核心方法"""
- if extra_body is None:
- extra_body = {}
-
- try:
- response = self.client.chat.completions.create(
- model=self.model_id,
- messages=messages,
- stream=use_stream,
- temperature=0.7,
- max_tokens=4096,
- extra_headers={"lora_id": "0"}, # 調用微調大模型時,對應替換為模型服務卡片上的resourceId
- stream_options={"include_usage": True},
- extra_body=extra_body
- )
-
- if use_stream:
- # 處理流式響應
- full_response = ""
- for chunk in response:
- if hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
- content = chunk.choices[0].delta.content
- full_response += content
- return full_response
- else:
- # 處理非流式響應
- return response.choices[0].message.content
-
- except Exception as e:
- print(f"智谱AI HTTP API請求出錯: {e}")
- return None
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """構建包含歷史記錄的消息列表"""
- messages = []
-
- # 添加系統提示詞
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加歷史對話記錄(使用共享歷史)
- if self.shared_conversation_history is not None:
- # 確保歷史記錄格式正確
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正確,跳過該條記錄
- continue
-
- # 添加當前用戶輸入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
- def _call_api_with_history(self, content, system_prompt=None):
- """使用對話歷史調用API"""
- # 構建消息列表
- messages = []
- # 添加系統提示詞(如果提供)
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
- # 添加歷史對話記錄(使用共享歷史)
- if self.shared_conversation_history is not None:
- # 確保歷史記錄格式正確
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正確,跳過該條記錄
- continue
- # 添加當前內容
- messages.append({
- "role": "tool",
- "content": content
- })
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "智谱AI HTTP API調用失敗"
-
- def handle_command(self, command):
- """處理引擎特定命令"""
- # GLM HTTP引擎目前不支持特定命令
- print(f"{Fore.RED}GLM HTTP引擎不支持此命令{Style.RESET_ALL}")
- return False
\ No newline at end of file
diff --git a/ai_engines/SDK_openAI.py b/ai_engines/SDK_openAI.py
deleted file mode 100644
index b2dba98..0000000
--- a/ai_engines/SDK_openAI.py
+++ /dev/null
@@ -1,266 +0,0 @@
-"""
-小狸 Pro-CLI AI 引擎开发 SDK
-提供快速开发 AI 引擎的工具包
-"""
-import os
-import sys
-import json
-import requests
-from colorama import Fore, Style
-from openai import OpenAI
-import logging
-
-# 设置日志
-logger = logging.getLogger(__name__)
-
-# 添加项目根目录到sys.path
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir)
-sys.path.insert(0, project_root)
-
-
-class _AIEngineSDK:
- """AI 引擎 SDK 内部实现"""
-
- def __init__(self):
- self.name = ""
- self.api_key = ""
- self.base_url = ""
- self.model = ""
- self.is_online = True
- self.max_history = 10
- self.conversation_history = []
- self.shared_conversation_history = None
- self.cli = None
-
- # 深度思考引擎配置
- self.is_thinking_engine = False # 是否是深度思考引擎
- self.thinking_start_marker = "" # 思考开始标记
- self.thinking_end_marker = "" # 思考结束标记
- self.show_thinking = True # 是否显示思考过程
-
- # 配置文件路径
- self.config_file = os.path.join(project_root, "config.json")
-
- def _load_config(self):
- """从配置文件加载配置"""
- try:
- with open(self.config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get(self.name, {})
-
- if not self.api_key:
- self.api_key = engine_config.get("api_key", "")
- if not self.base_url:
- self.base_url = engine_config.get("base_url", "")
- if not self.model:
- self.model = engine_config.get("model", "")
-
- self.max_history = config.get("system", {}).get("max_history", 10)
- except Exception as e:
- logger.error(f"加载配置失败: {e}")
- self.max_history = 10
-
- def _call_openai_api(self, messages):
- """调用 OpenAI 格式的 API"""
- try:
- self._load_config()
-
- # 构建请求体
- body = {
- "model": self.model,
- "messages": messages,
- "stream": False
- }
-
- # 构建请求头
- headers = {
- 'Content-Type': 'application/json'
- }
-
- if self.api_key:
- headers['Authorization'] = f'Bearer {self.api_key}'
-
- # 确定 API 地址
- api_url = self.base_url
- if not api_url.endswith("/chat/completions"):
- api_url = api_url.rstrip('/') + "/chat/completions"
-
- # 发送请求
- response = requests.post(
- url=api_url,
- json=body,
- headers=headers,
- timeout=None
- )
-
- # 处理响应
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 如果是深度思考引擎,处理思考内容
- if self.is_thinking_engine:
- ai_response = self._process_thinking_content(ai_response)
-
- return ai_response
- else:
- return f"AI 返回格式错误: {response_data}"
- else:
- return f"AI 调用失败: {response.status_code} - {response.text}"
-
- except Exception as e:
- return f"AI 调用失败: {str(e)}"
-
- def _build_messages(self, system_prompt, user_input):
- """构建消息列表"""
- messages = []
-
- # 添加系统提示词
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加历史对话记录
- if self.shared_conversation_history is not None:
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
-
- # 添加当前用户输入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成 AI 响应"""
- try:
- # 如果有工具结果,将其作为上下文返回给AI处理
- if tool_results:
- tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
- messages = self._build_messages(system_prompt, tool_result_text)
- else:
- messages = self._build_messages(system_prompt, user_input)
-
- # 调用 API
- return self._call_openai_api(messages)
-
- except Exception as e:
- return f"AI 调用失败: {str(e)}"
-
- def _process_thinking_content(self, response):
- """处理思考内容,将思考部分以灰色文本显示,只返回回复部分"""
- import re
-
- if not self.thinking_start_marker or not self.thinking_end_marker:
- # 如果没有设置标记,直接返回
- return response
-
- # 使用正则表达式查找思考内容
- pattern = f"{re.escape(self.thinking_start_marker)}(.*?){re.escape(self.thinking_end_marker)}"
- matches = re.findall(pattern, response, re.DOTALL)
-
- if matches and self.show_thinking:
- for match in matches:
- # 用灰色文本显示思考内容
- thinking_text = f"{Fore.LIGHTBLACK_EX}[思考: {match}]{Style.RESET_ALL}"
- # 替换思考标记之间的内容,保留思考内容但以灰色显示
- response = re.sub(pattern, thinking_text, response, 1)
- elif matches and not self.show_thinking:
- # 如果不显示思考内容,直接删除
- for match in matches:
- response = re.sub(pattern, "", response, 1)
-
- return response
-
-
-# 全局 SDK 实例
-_sdk_instance = _AIEngineSDK()
-
-
-def engine_Online(mode):
- """
- 设置引擎模式
-
- Args:
- mode: "on" - 云模式(在线 API)
- "off" - 本地模式(如 Ollama)
- """
- _sdk_instance.is_online = (mode.lower() == "on")
-
-
-def ai_name(name):
- """设置引擎名称"""
- _sdk_instance.name = name
-
-
-def ai_api_url(url):
- """设置 API 地址"""
- _sdk_instance.base_url = url
-
-
-def ai_api_key(key):
- """设置 API 密钥"""
- _sdk_instance.api_key = key
-
-
-def ai_model_id(model):
- """设置模型名称"""
- _sdk_instance.model = model
-
-
-def ai_thinking_engine(enable=True, start_marker="", end_marker="", show_thinking=True):
- """
- 设置深度思考引擎配置
-
- Args:
- enable: 是否启用深度思考引擎模式
- start_marker: 思考开始标记,默认为 ""
- end_marker: 思考结束标记,默认为 ""
- show_thinking: 是否显示思考过程,默认为 True
- """
- _sdk_instance.is_thinking_engine = enable
- _sdk_instance.thinking_start_marker = start_marker
- _sdk_instance.thinking_end_marker = end_marker
- _sdk_instance.show_thinking = show_thinking
-
-
-def set_cli(cli):
- """设置 CLI 引用"""
- _sdk_instance.cli = cli
-
-
-def set_shared_history(history):
- """设置共享对话历史"""
- _sdk_instance.shared_conversation_history = history
-
-
-def generate_response(user_input, tool_results=None, system_prompt=None):
- """生成 AI 响应"""
- return _sdk_instance.generate_response(user_input, tool_results, system_prompt)
-
-
-def get_sdk_instance():
- """获取 SDK 实例(用于高级用法)"""
- return _sdk_instance
-
-
-# 导出
-__all__ = [
- 'engine_Online',
- 'ai_name',
- 'ai_api_url',
- 'ai_api_key',
- 'ai_model_id',
- 'ai_thinking_engine',
- 'set_cli',
- 'set_shared_history',
- 'generate_response',
- 'get_sdk_instance'
-]
\ No newline at end of file
diff --git a/ai_engines/iflow_api_engine.py b/ai_engines/iflow_api_engine.py
deleted file mode 100644
index 8f68d35..0000000
--- a/ai_engines/iflow_api_engine.py
+++ /dev/null
@@ -1,405 +0,0 @@
-import os
-import sys
-import json
-import requests
-import threading
-import time
-from colorama import Fore, Style
-import logging
-
-# 设置日志
-logger = logging.getLogger(__name__)
-
-# 添加项目根目录到sys.path,以便正确导入
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir) # 获取项目根目录
-sys.path.insert(0, project_root)
-
-
-class IflowAPIAI:
- """基于Qwen3-Coder-Plus模型的AI引擎"""
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = """
-iflow API AI引擎插件帮助信息
-==========================
-
-引擎名称: iflow-api
-描述: 基于Qwen3-Coder-Plus模型的AI引擎,支持复杂推理和代码生成
-
-可用命令:
- 无特定命令,直接与AI对话即可
-
-使用说明:
-1. 此引擎使用Qwen3-Coder-Plus云API
-2. 使用/engine.switch iflow-api切换到此引擎
-3. 直接输入自然语言与AI对话
-4. 特别适合处理代码生成、技术问题等复杂任务
-"""
- return help_text
-
- def __init__(self):
- self.name = "iflow-api"
- self.cli = None # 引用CLI实例以访问插件
-
- # 直接从 config.json 读取配置(一次性读取)
- project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- config_file = os.path.join(project_root, "config.json")
-
- # 默认值
- self.api_key = ""
- self.url = ""
- self.model = ""
- self.max_history = 10
-
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("iflow_api", {})
- self.api_key = engine_config.get("api_key", "")
- self.url = engine_config.get("base_url", "")
- self.model = engine_config.get("model", "")
- self.max_history = config.get("system", {}).get("max_history", 10)
- except Exception as e:
- # 如果读取失败,使用默认值
- logger.warning(f"警告: 读取配置文件失败: {e}")
- print(f"{Fore.YELLOW}警告: 读取配置文件失败: {e}{Style.RESET_ALL}")
-
- # 验证API密钥
- if not self.api_key:
- logger.warning("警告: iflow-api引擎的API密钥未设置")
- print(f"{Fore.YELLOW}警告: iflow-api引擎的API密钥未设置{Style.RESET_ALL}")
-
- self.headers = {
- 'Authorization': f'Bearer {self.api_key}',
- 'Content-Type': 'application/json'
- }
-
- # 初始化对话历史
- self.conversation_history = []
-
- # 设置思考标记
- self.thinking_start_marker = ""
- self.thinking_end_marker = ""
-
- # 共享对话历史引用(由CLI设置)
- self.shared_conversation_history = None
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI响应 - 使用 qwen3-coder-plus"""
- try:
- # 如果有工具结果,将其作为上下文返回给AI处理
- if tool_results:
- tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
- # 构建消息列表
-
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
-
-
-
- # 构建请求体
-
- body = {
-
- "model": self.model or "qwen3-coder-plus",
-
- "messages": messages,
-
- "stream": False # 使用非流式响应以便于处理
-
- }
-
-
-
- # 发送请求到qwen3-coder-plus API
-
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
-
-
- if response.status_code == 200:
-
- response_data = response.json()
-
- # 检查是否是API错误响应(例如认证失败)
- if isinstance(response_data, dict) and "status" in response_data:
- # 检查是否是认证错误
- if response_data.get("status") in ["434", "401", "403"]:
- error_msg = response_data.get("msg", "API认证失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
- elif "body" in response_data and response_data["body"] is None:
- error_msg = response_data.get("msg", "API请求失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
-
- if "choices" in response_data and len(response_data["choices"]) > 0:
-
- # 改进错误处理以适应不同的API响应格式
- choice = response_data["choices"][0]
- if "message" in choice and "content" in choice["message"]:
- ai_response = choice["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 返回处理后的AI回复
- return processed_response
- else:
- # 尝试其他可能的字段名
- if "text" in choice:
- return choice["text"]
- elif "delta" in choice and "content" in choice["delta"]:
- return choice["delta"]["content"]
- else:
- return f" qwen3-coder-plus返回格式错误: 缺少预期的响应字段 - {response_data}"
-
- else:
-
- return f" qwen3-coder-plus返回格式错误: {response_data}"
-
- else:
-
- return f" qwen3-coder-plus调用失败: {response.status_code} - {response.text}"
-
-
-
- # 构建消息列表
-
- messages = self._build_messages_with_history(system_prompt, user_input)
-
-
-
- # 构建请求体
-
- body = {
-
- "model": self.model or "qwen3-coder-plus",
-
- "messages": messages,
-
- "stream": False # 使用非流式响应以便于处理
-
- }
-
-
-
- # 发送请求到qwen3-coder-plus
-
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
-
-
- if response.status_code == 200:
-
- response_data = response.json()
-
- # 检查是否是API错误响应(例如认证失败)
- if isinstance(response_data, dict) and "status" in response_data:
- # 检查是否是认证错误
- if response_data.get("status") in ["434", "401", "403"]:
- error_msg = response_data.get("msg", "API认证失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
- elif "body" in response_data and response_data["body"] is None:
- error_msg = response_data.get("msg", "API请求失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
-
- if "choices" in response_data and len(response_data["choices"]) > 0:
-
- # 改进错误处理以适应不同的API响应格式
- choice = response_data["choices"][0]
- if "message" in choice and "content" in choice["message"]:
- ai_response = choice["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 返回处理后的AI回复
- return processed_response
- else:
- # 尝试其他可能的字段名
- if "text" in choice:
- return choice["text"]
- elif "delta" in choice and "content" in choice["delta"]:
- return choice["delta"]["content"]
- else:
- return f"qwen3-coder-plus返回格式错误: 缺少预期的响应字段 - {response_data}"
-
- else:
-
- return f"qwen3-coder-plus返回格式错误: {response_data}"
-
- else:
-
- return f"qwen3-coder-plus调用失败: {response.status_code} - {response.text}"
-
-
-
- except Exception as e:
-
- # 如果API调用失败,返回错误信息
-
- return f"qwen3-coder-plus调用失败: {str(e)}"
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """构建包含历史记录的消息列表"""
- messages = []
-
- # 添加系统提示词
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加历史对话记录(使用共享历史)
- if self.shared_conversation_history is not None:
- # 确保历史记录格式正确
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正确,跳过该条记录
- continue
-
- # 添加当前用户输入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
-
-
- def _call_api_with_history(self, content, system_prompt=None):
- """使用对话历史调用API"""
- # 构建消息列表
-
- messages = []
-
- # 添加系统提示词(如果提供)
-
- if system_prompt:
-
- messages.append({
-
- "role": "system",
-
- "content": system_prompt
-
- })
-
- # 添加历史对话记录(使用共享历史)
-
- if self.shared_conversation_history is not None:
-
- # 确保历史记录格式正确
-
- for msg in self.shared_conversation_history[-self.max_history:]:
-
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
-
- messages.append(msg)
-
- else:
-
- # 如果格式不正确,跳过该条记录
-
- continue
-
- # 添加当前内容
-
- messages.append({
-
- "role": "tool",
-
- "content": content
-
- })
-
-
-
- # 构建请求体
- body = {
- "model": self.model or "qwen3-coder-plus",
- "messages": messages,
- "stream": False # 使用非流式响应以便于处理
- }
-
-
- # 发送请求到qwen3-coder-plus
-
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
-
-
- if response.status_code == 200:
-
- response_data = response.json()
-
- # 检查是否是API错误响应(例如认证失败)
- if isinstance(response_data, dict) and "status" in response_data:
- # 检查是否是认证错误
- if response_data.get("status") in ["434", "401", "403"]:
- error_msg = response_data.get("msg", "API认证失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
- elif "body" in response_data and response_data["body"] is None:
- error_msg = response_data.get("msg", "API请求失败")
- return f"qwen3-coder-plus API错误: {error_msg}"
-
- if "choices" in response_data and len(response_data["choices"]) > 0:
-
- # 改进错误处理以适应不同的API响应格式
- choice = response_data["choices"][0]
- if "message" in choice and "content" in choice["message"]:
- ai_response = choice["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- return processed_response
- else:
- # 尝试其他可能的字段名
- if "text" in choice:
- return choice["text"]
- elif "delta" in choice and "content" in choice["delta"]:
- return choice["delta"]["content"]
- else:
- return f"qwen3-coder-plus返回格式错误: 缺少预期的响应字段 - {response_data}"
-
- else:
-
- return f"qwen3-coder-plus返回格式错误: {response_data}"
-
- else:
-
- return f"qwen3-coder-plus调用失败: {response.status_code} - {response.text}"
-
- def handle_command(self, command):
- """处理引擎特定命令"""
- # qwen3-coder-plus引擎目前不支持特定命令
- print(f"{Fore.RED}qwen3-coder-plus引擎不支持此命令{Style.RESET_ALL}")
- return False
-
- def _process_thinking_content(self, response):
- """处理思考内容,将思考部分以灰色文本显示,只返回回复部分"""
- from colorama import Fore, Style
- import re
-
- # 这里可以设置思考标记,由用户自己定义
- thinking_start_marker = ""
- thinking_end_marker = ""
-
- if self.thinking_start_marker and self.thinking_end_marker:
- # 使用正则表达式查找思考内容
- pattern = f"{re.escape(self.thinking_start_marker)}(.*?){re.escape(self.thinking_end_marker)}"
- matches = re.findall(pattern, response, re.DOTALL)
-
- if matches:
- for match in matches:
- # 用灰色文本显示思考内容
- thinking_text = f"{Fore.LIGHTBLACK_EX}[思考: {match}]{Style.RESET_ALL}"
- # 替换思考标记之间的内容,保留思考内容但以灰色显示
- response = re.sub(pattern, thinking_text, response, 1)
-
- return response
\ No newline at end of file
diff --git a/ai_engines/maas_http_engine.py b/ai_engines/maas_http_engine.py
deleted file mode 100644
index 5ae5446..0000000
--- a/ai_engines/maas_http_engine.py
+++ /dev/null
@@ -1,205 +0,0 @@
-import os
-import json
-import requests
-from colorama import Fore, Style
-from openai import OpenAI
-
-# 获取项目根目录
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir)
-
-
-class Maas_http_engineAI:
- """基于HTTP协议的MaaS(Model as a Service)AI引擎"""
- requires_api_key = True # MaaS HTTP引擎需要API密钥
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = """
-MaaS HTTP AI引擎插件帮助信息
-==========================
-
-引擎名称: maas_http
-描述: 基于HTTP协议的MaaS(Model as a Service)AI引擎,支持多种大模型推理服务
-
-可用命令:
- 无特定命令,直接与AI对话即可
-
-使用说明:
-1. 此引擎使用HTTP协议调用MaaS API
-2. 使用/engine.switch maas_http切换到此引擎
-3. 直接输入自然语言与AI对话
-4. 支持普通对话、流式对话、JSON模式等多种调用方式
-"""
- return help_text
-
- def __init__(self):
- self.name = "maas_http"
- self.cli = None # 引用CLI实例以訪問插件
-
- # 直接从 config.json 读取配置
- config_file = os.path.join(project_root, "config.json")
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("maas_http", {})
- self.api_key = engine_config.get("api_key", "")
- self.base_url = engine_config.get("base_url", "")
- self.model_id = engine_config.get("model", "")
- except Exception as e:
- # 如果读取失败,使用空值
- self.api_key = ""
- self.base_url = ""
- self.model_id = ""
- # 初始化客户端
- self.client = OpenAI(
- api_key=self.api_key,
- base_url=self.base_url
- )
-
- # 初始化对话历史
- self.conversation_history = []
- # 设置最大历史记录数
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- self.max_history = config.get("system", {}).get("max_history", 10)
- except:
- self.max_history = 10
-
- # 共享對話歷史引用(由CLI設置)
- self.shared_conversation_history = None
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI響應 - 使用MaaS HTTP API"""
- try:
- # 如果有工具結果,將其作為上下文返回給AI處理
- if tool_results:
- tool_result_text = f"工具執行結果: {tool_results.get('result', '無結果')}"
-
- # 構建包含歷史記錄的消息列表
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "MaaS HTTP API調用失敗"
-
- # 構建包含歷史記錄的消息列表
- messages = self._build_messages_with_history(system_prompt, user_input)
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "MaaS HTTP API調用失敗"
-
- except Exception as e:
- # 如果API調用失敗,返回錯誤信息
- return f"MaaS HTTP API調用失敗: {str(e)}"
-
- def _call_api(self, messages, use_stream=False, extra_body=None):
- """調用API的核心方法"""
- if extra_body is None:
- extra_body = {}
-
- try:
- response = self.client.chat.completions.create(
- model=self.model_id or self.default_model,
- messages=messages,
- stream=use_stream,
- temperature=0.7,
- max_tokens=4096,
- extra_headers={"lora_id": "0"},
- stream_options={"include_usage": True},
- extra_body=extra_body
- )
-
- if use_stream:
- # 處理流式響應
- full_response = ""
- for chunk in response:
- if hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
- content = chunk.choices[0].delta.content
- full_response += content
- return full_response
- else:
- # 處理非流式響應
- return response.choices[0].message.content
-
- except Exception as e:
- print(f"MaaS HTTP API請求出錯: {e}")
- return None
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """構建包含歷史記錄的消息列表"""
- messages = []
-
- # 添加系統提示詞
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加歷史對話記錄(使用共享歷史)
- if self.shared_conversation_history is not None:
- # 確保歷史記錄格式正確
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正確,跳過該條記錄
- continue
-
- # 添加當前用戶輸入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
- def _call_api_with_history(self, content, system_prompt=None):
- """使用對話歷史調用API"""
- # 構建消息列表
- messages = []
- # 添加系統提示詞(如果提供)
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
- # 添加歷史對話記錄(使用共享歷史)
- if self.shared_conversation_history is not None:
- # 確保歷史記錄格式正確
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正確,跳過該條記錄
- continue
- # 添加當前內容
- messages.append({
- "role": "tool",
- "content": content
- })
-
- # 調用API
- response = self._call_api(messages)
-
- if response:
- return response
- else:
- return "MaaS HTTP API調用失敗"
-
- def handle_command(self, command):
- """處理引擎特定命令"""
- # MaaS HTTP引擎目前不支持特定命令
- print(f"{Fore.RED}MaaS HTTP引擎不支持此命令{Style.RESET_ALL}")
- return False
\ No newline at end of file
diff --git a/ai_engines/mimo_engine.py b/ai_engines/mimo_engine.py
deleted file mode 100644
index f8a23a2..0000000
--- a/ai_engines/mimo_engine.py
+++ /dev/null
@@ -1,355 +0,0 @@
-import os
-import sys
-import json
-import requests
-from colorama import Fore, Style
-from openai import OpenAI
-import logging
-from datetime import datetime
-
-# 设置日志
-logger = logging.getLogger(__name__)
-
-# 添加项目根目录到sys.path
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir)
-sys.path.insert(0, project_root)
-
-
-class MimoAI:
- """小米MiMoAI引擎 - 使用MiMo-v2-flash模型 - OpenAI格式"""
- requires_api_key = True # MiMo引擎需要API密钥
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = """
-MiMo AI引擎插件帮助信息
-==========================
-
-引擎名称: MiMo
-描述: 基于MiMo模型的AI引擎,由小米公司开发
-
-可用命令:
- 无特定命令,直接与AI对话即可
-
-使用说明:
-1. 此引擎使用小米MiMo云API
-2. 使用/engine.switch mimo切换到此引擎
-3. 直接输入自然语言与AI对话
-4. 支持思考模式和多轮对话
-"""
- return help_text
-
- def __init__(self):
- self.name = "mimo"
- self.cli = None
-
- # 直接从 config.json 读取配置
- config_file = os.path.join(project_root, "config.json")
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("mimo", {})
- self.api_key = engine_config.get("api_key", "")
- base_url_raw = engine_config.get("base_url", "")
- self.base_url = base_url_raw.rstrip('/') + '/chat/completions' if base_url_raw else ""
- self.model = engine_config.get("model", "")
- except Exception as e:
- # 如果读取失败,使用空值
- self.api_key = ""
- self.base_url = ""
- self.model = ""
-
- # 初始化对话历史
- self.conversation_history = []
- # 设置最大历史记录数
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- self.max_history = config.get("system", {}).get("max_history", 10)
- except:
- self.max_history = 10
-
- # 初始化 headers(用于 API 请求)
- self.headers = {
- 'Authorization': f'Bearer {self.api_key}',
- 'Content-Type': 'application/json'
- }
-
- # 初始化 OpenAI 客户端
- try:
- if self.api_key and self.base_url:
- self.client = OpenAI(
- api_key=self.api_key,
- base_url=self.base_url.replace('/chat/completions', ''),
- timeout=None
- )
- else:
- self.client = None
- except Exception as e:
- logger.warning(f"初始化 MiMo OpenAI 客户端失败: {e}")
- self.client = None
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI响应 - 使用MiMo-v2-flash - OpenAI格式"""
- if not self.client:
- return "MiMo引擎未正确初始化,无法调用API"
-
- try:
- # 获取当前日期和星期
- now = datetime.now()
- date_str = now.strftime("%Y年%m月%d日")
- week_str = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"][now.weekday()]
- current_datetime = f"{date_str} {week_str}"
-
- # 设置默认系统提示词(如果未提供)
- if not system_prompt:
- system_prompt = f"You are MiMo, an AI assistant developed by Xiaomi. Today is date: {current_datetime}. Your knowledge cutoff date is December 2024."
-
- # 如果有工具结果,将其作为上下文返回给AI处理
- if tool_results:
- tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
-
- # 构建包含历史记录的消息列表
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
-
- # 构建请求体,使用MiMo特定参数
- body = {
- "model": self.model,
- "messages": messages,
- "temperature": 0.7,
- "max_tokens": 2048,
- "top_p": 0.95,
- "frequency_penalty": 0,
- "presence_penalty": 0,
- # MiMo特定参数
- "extra_body": {
- "thinking": {"type": "disabled"} # 禁用思考模式
- }
- }
-
- # 直接使用requests调用MiMo API,因为需要特定的header格式
- import requests
- response = requests.post(
- url=self.base_url,
- json=body,
- headers=self.headers,
- timeout=None
- )
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 更新对话历史
- self._update_conversation_history(user_input if not tool_results else tool_result_text, ai_response)
-
- # 返回处理后的AI回复,前面加上✦
- return processed_response
- else:
- return "MiMo-v2-flash API返回格式错误"
- elif response.status_code == 401:
- return "MiMo-v2-flash API认证失败,请检查API密钥是否正确配置"
- else:
- return f"MiMo-v2-flash API调用失败: {response.status_code} - {response.text}"
-
- # 构建包含历史记录的消息列表
- messages = self._build_messages_with_history(system_prompt, user_input)
-
- # 构建请求体,使用MiMo特定参数
- body = {
- "model": self.model,
- "messages": messages,
- "temperature": 0.7,
- "max_tokens": 2048,
- "top_p": 0.95,
- "frequency_penalty": 0,
- "presence_penalty": 0,
- # MiMo特定参数
- "extra_body": {
- "thinking": {"type": "disabled"} # 禁用思考模式
- }
- }
-
- # 直接使用requests调用MiMo API,因为需要特定的header格式
- import requests
- response = requests.post(
- url=self.base_url,
- json=body,
- headers=self.headers,
- timeout=None
- )
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 更新对话历史
- self._update_conversation_history(user_input, ai_response)
-
- # 返回处理后的AI回复
- return processed_response
- else:
- return "MiMo-v2-flash API返回格式错误"
- elif response.status_code == 401:
- return "MiMo-v2-flash API认证失败,请检查API密钥是否正确配置"
- else:
- return f"MiMo-v2-flash API调用失败: {response.status_code} - {response.text}"
-
- except Exception as e:
- # 如果API调用失败,返回错误信息
- return f"MiMo-v2-flash API调用失败: {str(e)}"
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """构建包含历史记录的消息列表"""
- messages = []
-
- # 添加系统提示词
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加历史对话记录(使用共享历史)
- if self.shared_conversation_history is not None:
- # 确保历史记录格式正确
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正确,跳过该条记录
- continue
-
- # 添加当前用户输入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
- def _update_conversation_history(self, user_input, ai_response):
- """更新对话历史"""
- # 添加用户输入到历史记录
- self.conversation_history.append({
- "role": "user",
- "content": user_input
- })
- # 添加AI回复到历史记录
- self.conversation_history.append({
- "role": "assistant",
- "content": ai_response
- })
- # 限制历史记录数量
- if len(self.conversation_history) > self.max_history * 2:
- self.conversation_history = self.conversation_history[-self.max_history * 2:]
-
- def _call_api_with_history(self, content, system_prompt=None):
- """使用对话历史调用API"""
- # 获取当前日期和星期
- now = datetime.now()
- date_str = now.strftime("%Y年%m月%d日")
- week_str = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"][now.weekday()]
- current_datetime = f"{date_str} {week_str}"
-
- # 设置默认系统提示词(如果未提供)
- if not system_prompt:
- system_prompt = f"You are MiMo, an AI assistant developed by Xiaomi. Today is date: {current_datetime}. Your knowledge cutoff date is December 2024."
-
- # 构建消息列表
- messages = []
-
- # 添加系统提示词(如果提供)
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加历史对话记录(使用共享历史)
- if self.shared_conversation_history is not None:
- # 确保历史记录格式正确
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正确,跳过该条记录
- continue
-
- # 添加当前内容
- messages.append({
- "role": "user",
- "content": content
- })
-
- # 构建请求体
- body = {
- "model": self.model,
- "messages": messages,
- "max_completion_tokens": 1024,
- "temperature": 0.3,
- "top_p": 0.95,
- "stream": False,
- "frequency_penalty": 0,
- "presence_penalty": 0,
- "extra_body": {
- "thinking": {"type": "disabled"}
- }
- }
-
- # 发送请求到MiMo-v2-flash API
- response = requests.post(url=self.base_url, json=body, headers=self.headers, timeout=None)
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- return processed_response
- else:
- return "MiMo-v2-flash API返回格式错误"
- else:
- return f"MiMo-v2-flash API调用失败: {response.status_code} - {response.text}"
-
- def handle_command(self, command):
- """处理引擎特定命令"""
- # MiMo引擎目前不支持特定命令
- print(f"{Fore.RED}MiMo引擎不支持此命令{Style.RESET_ALL}")
- return False
-
- def _process_thinking_content(self, response):
- """处理思考内容,将思考部分以灰色文本显示,只返回回复部分"""
- from colorama import Fore, Style
- import re
-
- # 这里可以设置思考标记,由用户自己定义
- thinking_start_marker = ""
- thinking_end_marker = ""
-
- # 如果响应中包含思考标记,则提取思考内容和回复内容
- if thinking_start_marker in response and thinking_end_marker in response:
- # 提取思考内容
- thinking_match = re.search(f'{thinking_start_marker}(.*?){thinking_end_marker}', response, re.DOTALL)
- if thinking_match:
- thinking_content = thinking_match.group(1).strip()
- # 打印思考内容(灰色)
- print(f"{Fore.LIGHTBLACK_EX}思考: {thinking_content}{Style.RESET_ALL}")
-
- # 提取回复内容
- response_content = re.split(f'{thinking_end_marker}', response, maxsplit=1)[-1].strip()
- return response_content
-
- # 如果没有思考标记,直接返回响应
- return response
diff --git a/ai_engines/openai_engine.py b/ai_engines/openai_engine.py
new file mode 100644
index 0000000..9a0d2dd
--- /dev/null
+++ b/ai_engines/openai_engine.py
@@ -0,0 +1,332 @@
+"""
+OpenAI 兼容格式引擎
+支持所有兼容 OpenAI API 格式的服务(如 DeepSeek、Grok、硅基流动、本地 vLLM 等)
+"""
+
+import os
+import sys
+import json
+import requests
+from colorama import Fore, Style
+import logging
+
+# 设置日志
+logger = logging.getLogger(__name__)
+
+# 添加项目根目录到sys.path
+current_dir = os.path.dirname(os.path.abspath(__file__))
+project_root = os.path.dirname(current_dir)
+sys.path.insert(0, project_root)
+
+
+class OpenaiAI:
+ """OpenAI 兼容格式 AI 引擎 - 支持所有兼容 OpenAI API 的服务"""
+ requires_api_key = True
+
+ def get_help_info(self):
+ """获取引擎帮助信息"""
+ help_text = """
+OpenAI 兼容格式引擎帮助信息
+============================
+
+引擎名称: openai
+描述: 通用 OpenAI API 兼容引擎,支持所有兼容 OpenAI 格式的服务
+
+支持的服务:
+ - OpenAI 官方 API
+ - DeepSeek API
+ - Grok (xAI) API
+ - 硅基流动 (SiliconFlow) API
+ - 本地 vLLM / LiteLLM / OneAPI 等转发服务
+ - 任何兼容 /chat/completions 接口的服务
+
+配置方式 (config.json):
+ {
+ "api": {
+ "engines": {
+ "openai": {
+ "api_key": "你的API密钥",
+ "base_url": "https://api.openai.com/v1",
+ "model": "gpt-4o"
+ }
+ }
+ }
+ }
+
+可用命令:
+ /engine.openai models - 列出可用模型(需要服务端支持)
+ /engine.openai set <模型名> - 切换模型
+ /engine.openai info - 显示当前配置信息
+
+使用说明:
+1. 在 config.json 中配置 api_key、base_url、model
+2. 使用 /engine switch openai 切换到此引擎
+3. 直接输入自然语言与 AI 对话
+
+注意:
+ - base_url 填写 API 的基础地址,无需包含 /chat/completions
+ - 例如 OpenAI 官方填 https://api.openai.com/v1
+ - 本地服务填 http://localhost:8000/v1
+"""
+ return help_text
+
+ def __init__(self):
+ self.name = "openai"
+ self.cli = None
+
+ # 从 config.json 读取配置
+ config_file = os.path.join(project_root, "config.json")
+ try:
+ with open(config_file, 'r', encoding='utf-8') as f:
+ config = json.load(f)
+ engine_config = config.get("api", {}).get("engines", {}).get("openai", {})
+ self.api_key = engine_config.get("api_key", "")
+ self.base_url = engine_config.get("base_url", "").rstrip('/')
+ self.model = engine_config.get("model", "")
+ self.max_history = config.get("system", {}).get("max_history", 10)
+ except Exception as e:
+ logger.warning(f"读取配置文件失败: {e}")
+ self.api_key = ""
+ self.base_url = ""
+ self.model = ""
+ self.max_history = 10
+
+ # 初始化对话历史
+ self.conversation_history = []
+ self.shared_conversation_history = None
+
+ # 思考标记(兼容深度思考模型)
+ self.thinking_start_marker = ""
+ self.thinking_end_marker = ""
+
+ # 检查配置
+ if not self.api_key:
+ print(f"{Fore.YELLOW}警告: openai 引擎的 API 密钥未设置{Style.RESET_ALL}")
+ if not self.base_url:
+ print(f"{Fore.YELLOW}警告: openai 引擎的 base_url 未设置{Style.RESET_ALL}")
+ else:
+ print(f"{Fore.GREEN}OpenAI 兼容引擎已启用 (base_url: {self.base_url}){Style.RESET_ALL}")
+
+ def _get_headers(self):
+ """构建请求头"""
+ headers = {
+ 'Content-Type': 'application/json'
+ }
+ if self.api_key:
+ headers['Authorization'] = f'Bearer {self.api_key}'
+ return headers
+
+ def _get_api_url(self):
+ """获取完整的 API 地址"""
+ url = self.base_url
+ if not url:
+ return ""
+ if not url.endswith('/chat/completions'):
+ url = url.rstrip('/') + '/chat/completions'
+ return url
+
+ def generate_response(self, user_input, tool_results=None, system_prompt=None):
+ """生成 AI 响应"""
+ try:
+ if not self.base_url:
+ return "错误: openai 引擎的 base_url 未配置,请在 config.json 中设置"
+
+ # 处理工具结果
+ if tool_results:
+ tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
+ messages = self._build_messages_with_history(system_prompt, tool_result_text)
+ else:
+ messages = self._build_messages_with_history(system_prompt, user_input)
+
+ # 构建请求体
+ body = {
+ "model": self.model,
+ "messages": messages,
+ "stream": False
+ }
+
+ # 发送请求
+ api_url = self._get_api_url()
+ response = requests.post(
+ url=api_url,
+ json=body,
+ headers=self._get_headers(),
+ timeout=None
+ )
+
+ if response.status_code == 200:
+ response_data = response.json()
+ if "choices" in response_data and len(response_data["choices"]) > 0:
+ ai_response = response_data["choices"][0]["message"]["content"]
+ # 清理无效的 UTF-8 代理字符
+ ai_response = ai_response.encode('utf-8', 'replace').decode('utf-8')
+ # 处理思考内容
+ ai_response = self._process_thinking_content(ai_response)
+ return ai_response
+ else:
+ return f"API 返回格式错误: {response_data}"
+ elif response.status_code == 401:
+ return "API 认证失败,请检查 api_key 是否正确"
+ elif response.status_code == 404:
+ return f"API 端点不存在,请检查 base_url 是否正确: {api_url}"
+ else:
+ return f"API 调用失败: {response.status_code} - {response.text}"
+
+ except requests.exceptions.ConnectionError:
+ return f"无法连接到 API 服务: {self.base_url},请检查服务是否运行"
+ except Exception as e:
+ return f"API 调用失败: {str(e)}"
+
+ def _build_messages_with_history(self, system_prompt, user_input):
+ """构建包含历史记录的消息列表"""
+ messages = []
+
+ # 添加系统提示词
+ if system_prompt:
+ clean_prompt = system_prompt.encode('utf-8', 'replace').decode('utf-8')
+ messages.append({
+ "role": "system",
+ "content": clean_prompt
+ })
+
+ # 添加历史对话记录(使用共享历史)
+ if self.shared_conversation_history is not None:
+ for msg in self.shared_conversation_history[-self.max_history:]:
+ if isinstance(msg, dict) and "role" in msg and "content" in msg:
+ clean_content = msg["content"].encode('utf-8', 'replace').decode('utf-8')
+ messages.append({"role": msg["role"], "content": clean_content})
+ else:
+ continue
+
+ # 添加当前用户输入
+ if user_input:
+ clean_input = user_input.encode('utf-8', 'replace').decode('utf-8')
+ messages.append({
+ "role": "user",
+ "content": clean_input
+ })
+
+ return messages
+
+ def _call_api_with_history(self, content, system_prompt=None):
+ """使用对话历史调用 API"""
+ if not self.base_url:
+ return "错误: openai 引擎的 base_url 未配置"
+
+ messages = []
+ if system_prompt:
+ messages.append({"role": "system", "content": system_prompt})
+ if self.shared_conversation_history is not None:
+ for msg in self.shared_conversation_history[-self.max_history:]:
+ if isinstance(msg, dict) and "role" in msg and "content" in msg:
+ messages.append(msg)
+ messages.append({"role": "user", "content": content})
+
+ body = {
+ "model": self.model,
+ "messages": messages,
+ "stream": False
+ }
+
+ try:
+ response = requests.post(
+ url=self._get_api_url(),
+ json=body,
+ headers=self._get_headers(),
+ timeout=None
+ )
+
+ if response.status_code == 200:
+ response_data = response.json()
+ if "choices" in response_data and len(response_data["choices"]) > 0:
+ ai_response = response_data["choices"][0]["message"]["content"]
+ ai_response = ai_response.encode('utf-8', 'replace').decode('utf-8')
+ return self._process_thinking_content(ai_response)
+ return f"API 调用失败: {response.status_code} - {response.text}"
+ except Exception as e:
+ return f"API 调用失败: {str(e)}"
+
+ def _process_thinking_content(self, response):
+ """处理思考内容,将思考部分以灰色文本显示"""
+ import re
+
+ if not self.thinking_start_marker or not self.thinking_end_marker:
+ return response
+
+ if self.thinking_start_marker in response and self.thinking_end_marker in response:
+ parts = response.split(self.thinking_start_marker)
+ if len(parts) > 1:
+ remaining = parts[1]
+ if self.thinking_end_marker in remaining:
+ thinking_part, reply_part = remaining.split(self.thinking_end_marker, 1)
+ thinking_content = thinking_part.strip()
+ reply_content = reply_part.strip()
+ if thinking_content:
+ print(f"{Fore.LIGHTBLACK_EX}[思考: {thinking_content}]{Style.RESET_ALL}")
+ return reply_content if reply_content else ""
+
+ return response
+
+ def set_model(self, model_name):
+ """设置模型"""
+ self.model = model_name
+ print(f"{Fore.GREEN}已切换模型为: {model_name}{Style.RESET_ALL}")
+
+ def list_models(self):
+ """列出可用模型(调用 API 的 /models 端点)"""
+ if not self.base_url:
+ return ["错误: base_url 未配置"]
+
+ try:
+ models_url = self.base_url.rstrip('/')
+ if models_url.endswith('/chat/completions'):
+ models_url = models_url[:-len('/chat/completions')]
+ models_url = models_url.rstrip('/') + '/models'
+
+ response = requests.get(
+ url=models_url,
+ headers=self._get_headers(),
+ timeout=10
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ if "data" in data:
+ models = [m.get("id", "unknown") for m in data["data"]]
+ return models
+ else:
+ return ["API 返回格式不标准,无法解析模型列表"]
+ else:
+ return [f"获取模型列表失败: {response.status_code}"]
+ except Exception as e:
+ return [f"获取模型列表失败: {str(e)}"]
+
+ def handle_command(self, command):
+ """处理引擎特定命令"""
+ if command == "models":
+ models = self.list_models()
+ print(f"{Fore.GREEN}可用模型列表:{Style.RESET_ALL}")
+ for model in models:
+ status = " (当前使用)" if model == self.model else ""
+ print(f"{Fore.GREEN} - {model}{status}{Style.RESET_ALL}")
+ return True
+
+ elif command.startswith("set "):
+ model_name = command[4:].strip()
+ if model_name:
+ self.set_model(model_name)
+ return True
+ else:
+ print(f"{Fore.RED}请提供模型名称. 用法: /engine.openai set <模型名>{Style.RESET_ALL}")
+ return False
+
+ elif command == "info":
+ print(f"{Fore.GREEN}OpenAI 兼容引擎配置:{Style.RESET_ALL}")
+ print(f" base_url: {self.base_url}")
+ print(f" model: {self.model}")
+ print(f" api_key: {'已设置' if self.api_key else '未设置'}")
+ return True
+
+ else:
+ print(f"{Fore.RED}未知命令. 可用命令: models, set, info{Style.RESET_ALL}")
+ return False
diff --git a/ai_engines/qwq_engine.py b/ai_engines/qwq_engine.py
deleted file mode 100644
index eee52eb..0000000
--- a/ai_engines/qwq_engine.py
+++ /dev/null
@@ -1,291 +0,0 @@
-import os
-import json
-import requests
-import threading
-import time
-from colorama import Fore, Style
-
-
-class QwqAI:
- """基于QwQ-32B模型的AI引擎"""
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = """
-QwQ-32B AI引擎插件帮助信息
-==========================
-
-引擎名称: QwQ
-描述: 基于QwQ-32B模型的AI引擎,支持复杂推理和数学计算
-
-可用命令:
- 无特定命令,直接与AI对话即可
-
-使用说明:
-1. 此引擎使用QwQ-32B云API
-2. 使用/engine.switch qwq切换到此引擎
-3. 直接输入自然语言与AI对话
-4. 特别适合处理数学、逻辑推理等复杂任务
-"""
- return help_text
-
- def __init__(self):
- self.name = "qwq"
- self.cli = None # 引用CLI实例以访问插件
-
- # 直接从 config.json 读取配置
- import json
- import os
- project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- config_file = os.path.join(project_root, "config.json")
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("qwq", {})
- self.api_key = engine_config.get("api_key", "")
- self.url = engine_config.get("base_url", "")
- self.model = engine_config.get("model", "")
- except Exception as e:
- # 如果读取失败,使用空值
- print(f"{Fore.YELLOW}警告: 读取配置文件失败: {e}{Style.RESET_ALL}")
- self.api_key = ""
- self.url = ""
- self.model = ""
-
- self.headers = {
- 'Authorization': f'Bearer {self.api_key}',
- 'Content-Type': 'application/json'
- }
- # 初始化对话历史
- self.conversation_history = []
- # 设置最大历史记录数
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- self.max_history = config.get("system", {}).get("max_history", 10)
- except:
- self.max_history = 10
-
- # 设置思考标记
- self.thinking_start_marker = ""
- self.thinking_end_marker = ""
-
- # 共享对话历史引用(由CLI设置)
- self.shared_conversation_history = None
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI响应 - 使用QwQ API"""
- try:
- # 如果有工具结果,将其作为上下文返回给AI处理
- if tool_results:
- tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
- # 构建消息列表
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
-
- # 构建请求体
- body = {
- "model": self.model,
- "messages": messages,
- "stream": False # 使用非流式响应以便于处理
- }
-
- # 发送请求到QwQ API
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 返回处理后的AI回复
- return processed_response
- else:
- return "QwQ API返回格式错误"
- else:
- return f"QwQ API调用失败: {response.status_code} - {response.text}"
-
- # 构建消息列表
- messages = self._build_messages_with_history(system_prompt, user_input)
-
- # 构建请求体
- body = {
- "model": self.model,
- "messages": messages,
- "stream": False # 使用非流式响应以便于处理
- }
-
- # 发送请求到QwQ API
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- # 返回处理后的AI回复
- return processed_response
- else:
- return "QwQ API返回格式错误"
- else:
- return f"QwQ API调用失败: {response.status_code} - {response.text}"
-
- except Exception as e:
- # 如果API调用失败,返回错误信息
- return f"QwQ API调用失败: {str(e)}"
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """构建包含历史记录的消息列表"""
- messages = []
-
- # 添加系统提示词
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加历史对话记录(使用共享历史)
- if self.shared_conversation_history is not None:
- # 确保历史记录格式正确
- for msg in self.shared_conversation_history[-self.max_history:]:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- messages.append(msg)
- else:
- # 如果格式不正确,跳过该条记录
- continue
-
- # 添加当前用户输入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
-
-
- def _call_api_with_history(self, content, system_prompt=None):
- """使用对话历史调用API"""
- # 构建消息列表
-
- messages = []
-
- # 添加系统提示词(如果提供)
-
- if system_prompt:
-
- messages.append({
-
- "role": "system",
-
- "content": system_prompt
-
- })
-
- # 添加历史对话记录(使用共享历史)
-
- if self.shared_conversation_history is not None:
-
- # 确保历史记录格式正确
-
- for msg in self.shared_conversation_history[-self.max_history:]:
-
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
-
- messages.append(msg)
-
- else:
-
- # 如果格式不正确,跳过该条记录
-
- continue
-
- # 添加当前内容
-
- messages.append({
-
- "role": "tool",
-
- "content": content
-
- })
-
-
-
- # 构建请求体
- body = {
- "model": self.model,
- "messages": messages,
- "stream": False # 使用非流式响应以便于处理
- }
-
- # 发送请求到QwQ API
- response = requests.post(url=self.url, json=body, headers=self.headers, timeout=None)
-
- if response.status_code == 200:
- response_data = response.json()
- if "choices" in response_data and len(response_data["choices"]) > 0:
- ai_response = response_data["choices"][0]["message"]["content"]
-
- # 处理思考标记
- processed_response = self._process_thinking_content(ai_response)
-
- return processed_response
- else:
- return "QwQ API返回格式错误"
- else:
- return f"QwQ API调用失败: {response.status_code} - {response.text}"
-
- def handle_command(self, command):
- """处理引擎特定命令"""
- # QwQ引擎目前不支持特定命令
- print(f"{Fore.RED}QwQ引擎不支持此命令{Style.RESET_ALL}")
- return False
-
- def _process_thinking_content(self, response):
- """处理思考内容,将思考部分以灰色文本显示,只返回回复部分"""
- from colorama import Fore, Style
- import re
-
- # 这里可以设置思考标记,由用户自己定义
- thinking_start_marker = "" # 用户可以设置开始标记
- thinking_end_marker = "" # 用户可以设置结束标记
-
- # 如果用户设置了思考标记,则处理思考内容
- if thinking_start_marker and thinking_end_marker and thinking_start_marker in response and thinking_end_marker in response:
- # 分离思考内容和回复内容
- parts = response.split(thinking_start_marker)
- if len(parts) > 1:
- # 获取包含结束标记的部分
- remaining = parts[1]
- thinking_content = ""
- reply_content = ""
-
- # 检查结束标记
- if thinking_end_marker in remaining:
- thinking_part, reply_part = remaining.split(thinking_end_marker, 1)
- thinking_content = thinking_part.strip()
- reply_content = reply_part.strip()
- else:
- # 如果没有找到结束标记,将剩余部分都视为思考内容
- thinking_content = remaining.strip()
- reply_content = ""
-
- # 显示思考内容为灰色文本
- if thinking_content:
- print(f"{Fore.LIGHTBLACK_EX}[思考: {thinking_content}]{Style.RESET_ALL}")
-
- # 返回回复内容
- if reply_content:
- return reply_content
- else:
- return "" # 如果没有回复内容,返回空字符串
- else:
- # 如果没有设置思考标记或没有找到标记,直接返回原始响应
- return response
\ No newline at end of file
diff --git a/ai_engines/xfyun_spark_engine.py b/ai_engines/xfyun_spark_engine.py
deleted file mode 100644
index 7f69da5..0000000
--- a/ai_engines/xfyun_spark_engine.py
+++ /dev/null
@@ -1,275 +0,0 @@
-import os
-import sys
-import json
-import hashlib
-import hmac
-import base64
-import websocket
-import time
-import threading
-from datetime import datetime
-from time import mktime
-from urllib.parse import urlparse, urlencode
-from wsgiref.handlers import format_date_time
-from colorama import Fore, Style
-
-# 获取项目根目录
-current_dir = os.path.dirname(os.path.abspath(__file__))
-project_root = os.path.dirname(current_dir)
-sys.path.insert(0, project_root)
-
-
-class XfyunSparkAI:
- """基于讯飞星火深度推理X2模型的AI引擎(WebSocket接口)"""
- requires_api_key = True # 讯飞引擎需要API密钥
-
- # X2深度推理版本固定配置
- URL = "wss://spark-api.xf-yun.com/x2"
- DOMAIN = "spark-x"
- MAX_TOKENS = 131072 # X2输出上限128K
-
- def __init__(self):
- self.name = "xfyun-spark"
- self.cli = None
-
- # 直接从 config.json 读取配置
- config_file = os.path.join(project_root, "config.json")
- try:
- with open(config_file, 'r', encoding='utf-8') as f:
- config = json.load(f)
- engine_config = config.get("api", {}).get("engines", {}).get("xfyun_spark", {})
- self.app_id = engine_config.get("app_id", "")
- self.api_key = engine_config.get("api_key", "")
- self.api_secret = engine_config.get("api_secret", "")
- self.max_history = config.get("system", {}).get("max_history", 10)
- except Exception as e:
- self.app_id = ""
- self.api_key = ""
- self.api_secret = ""
- self.max_history = 10
-
- # 初始化对话历史
- self.conversation_history = []
- self.shared_conversation_history = None
- self.chat_id = f"chat_{self.app_id}_{int(time.time())}" # 固定会话ID,确保上下文连续性
-
- # 验证API密钥
- if not self.app_id or not self.api_key or not self.api_secret:
- print(f"{Fore.YELLOW}警告: xfyun-spark引擎的API配置未完整设置(需要app_id、api_key、api_secret){Style.RESET_ALL}")
-
- def get_help_info(self):
- """获取引擎帮助信息"""
- help_text = f"""
-讯飞星火深度推理X2引擎帮助信息
-================================
-
-引擎名称: xfyun-spark
-描述: 基于讯飞星火深度推理X2模型的AI引擎,支持WebSocket流式输出
-
-版本: X2深度推理 (输入64K, 输出128K)
-
-配置要求:
- 在config.json中配置:
- {{
- "api": {{
- "engines": {{
- "xfyun_spark": {{
- "app_id": "你的应用ID",
- "api_key": "你的API Key",
- "api_secret": "你的API Secret"
- }}
- }}
- }}
- }}
-
-使用说明:
-1. 使用/engine.switch xfyun-spark切换到此引擎
-2. 直接输入自然语言与AI对话
-3. 本引擎强制使用流式输出,AI回复会实时显示
-4. 支持深度思考模式,思考过程会自动显示
-
-注意: 本引擎使用WebSocket协议,需要app_id、api_key、api_secret三个参数
-"""
- return help_text
-
- def _generate_url(self):
- """生成鉴权URL(使用官方示例的方式)"""
- # 生成RFC1123格式的时间戳
- now = datetime.now()
- date = format_date_time(mktime(now.timetuple()))
-
- # 解析URL获取host和path
- parsed_url = urlparse(self.URL)
- host = parsed_url.netloc
- path = parsed_url.path
-
- # 拼接签名字符串
- signature_origin = "host: " + host + "\n"
- signature_origin += "date: " + date + "\n"
- signature_origin += "GET " + path + " HTTP/1.1"
-
- # 进行hmac-sha256进行加密
- signature_sha = hmac.new(
- self.api_secret.encode('utf-8'),
- signature_origin.encode('utf-8'),
- digestmod=hashlib.sha256
- ).digest()
-
- signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
-
- # 拼接authorization_origin
- authorization_origin = f'api_key="{self.api_key}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
-
- authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
-
- # 将请求的鉴权参数组合为字典
- v = {
- "authorization": authorization,
- "date": date,
- "host": host
- }
-
- # 拼接鉴权参数,生成url
- url = self.URL + '?' + urlencode(v)
-
- return url
-
- def _build_messages_with_history(self, system_prompt, user_input):
- """构建包含历史记录的消息列表(传递完整历史对话)"""
- messages = []
-
- # 添加系统提示词
- if system_prompt:
- messages.append({
- "role": "system",
- "content": system_prompt
- })
-
- # 添加完整的历史对话(不限制数量,让API自己处理)
- if self.shared_conversation_history:
- for msg in self.shared_conversation_history:
- if isinstance(msg, dict) and "role" in msg and "content" in msg:
- role = msg["role"]
- content = msg["content"]
- # 转换角色名称
- if role == "user":
- messages.append({"role": "user", "content": content})
- elif role == "assistant":
- messages.append({"role": "assistant", "content": content})
-
- # 添加当前用户输入
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- return messages
-
- def generate_response(self, user_input, tool_results=None, system_prompt=None):
- """生成AI响应(非流式)"""
- try:
- # 处理工具结果
- if tool_results:
- tool_result_text = f"工具执行结果: {tool_results.get('result', '无结果')}"
- messages = self._build_messages_with_history(system_prompt, tool_result_text)
- else:
- messages = self._build_messages_with_history(system_prompt, user_input)
-
- # 构建请求数据
- request_data = {
- "header": {
- "app_id": self.app_id,
- "uid": str(time.time()).replace('.', '')[:32]
- },
- "parameter": {
- "chat": {
- "domain": self.DOMAIN,
- "temperature": 0,
- "max_tokens": 4096,
- "presence_penalty": 1,
- "frequency_penalty": 0.02,
- "top_k": 5,
- "chat_id": self.chat_id
- }
- },
- "payload": {
- "message": {
- "text": messages
- }
- }
- }
-
- # 生成鉴权URL
- auth_url = self._generate_url()
-
- # 收集完整响应
- full_response = ""
- thinking_content = ""
- ws = None
- result_queue = []
- done_event = threading.Event()
-
- def on_message(ws, message):
- nonlocal full_response, thinking_content
- try:
- data = json.loads(message)
- code = data.get("header", {}).get("code", -1)
-
- if code != 0:
- result_queue.append(("error", data.get('header', {}).get('message', '未知错误')))
- done_event.set()
- return
-
- payload = data.get("payload", {})
- choices = payload.get("choices", {})
-
- # 处理文本响应
- text_list = choices.get("text", [])
- if text_list:
- reasoning = text_list[0].get("reasoning_content", "")
- if reasoning:
- thinking_content += reasoning
- content = text_list[0].get("content", "")
- if content:
- full_response += content
-
- if choices.get("status") == 2:
- done_event.set()
-
- except Exception as e:
- result_queue.append(("error", str(e)))
- done_event.set()
-
- def on_error(ws, error):
- result_queue.append(("error", str(error)))
- done_event.set()
-
- def on_close(ws, close_status_code, close_msg):
- pass
-
- def on_open(ws):
- ws.send(json.dumps(request_data))
-
- # 创建WebSocket连接
- ws = websocket.WebSocketApp(
- auth_url,
- on_open=on_open,
- on_message=on_message,
- on_error=on_error,
- on_close=on_close
- )
-
- # 在后台线程运行WebSocket
- ws_thread = threading.Thread(target=ws.run_forever)
- ws_thread.daemon = True
- ws_thread.start()
-
- # 等待完成
- done_event.wait(timeout=60)
-
- # 返回完整响应
- return full_response
-
- except Exception as e:
- print(f"\n{Fore.RED}讯飞星火API调用失败: {str(e)}{Style.RESET_ALL}")
- return f"讯飞星火API调用失败: {str(e)}"
\ No newline at end of file
diff --git a/config.json.example b/config.json.example
new file mode 100644
index 0000000..c09eb28
--- /dev/null
+++ b/config.json.example
@@ -0,0 +1,20 @@
+{
+ "api": {
+ "engines": {
+ "ollama": {
+ "api_key": "",
+ "base_url": "http://localhost:11434",
+ "model": "qwen2.5:latest"
+ },
+ "openai": {
+ "api_key": "your-api-key-here",
+ "base_url": "https://api.deepseek.com/v1",
+ "model": "deepseek-chat"
+ }
+ }
+ },
+ "system": {
+ "default_engine": "ollama",
+ "max_history": 50
+ }
+}