mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-03-20 13:58:30 +08:00
feat: release 2.0.3
This commit is contained in:
21
README.md
21
README.md
@@ -102,9 +102,9 @@ bash <(curl -fsSL https://cdn.link-ai.tech/code/cow/run.sh)
|
||||
|
||||
项目支持国内外主流厂商的模型接口,可选模型及配置说明参考:[模型说明](#模型说明)。
|
||||
|
||||
> 注:Agent模式下推荐使用以下模型,可根据效果及成本综合选择:MiniMax-M2.5、glm-5、kimi-k2.5、qwen3.5-plus、claude-sonnet-4-6、gemini-3.1-pro-preview、gpt-5.4
|
||||
> 注:Agent模式下推荐使用以下模型,可根据效果及成本综合选择:MiniMax-M2.5、glm-5、kimi-k2.5、qwen3.5-plus、claude-sonnet-4-6、gemini-3.1-pro-preview、gpt-5.4、gpt-5.4-mini
|
||||
|
||||
同时支持使用 **LinkAI平台** 接口,可灵活切换 OpenAI、Claude、Gemini、DeepSeek、Qwen、Kimi 等多种常用模型,并支持知识库、工作流、插件等Agent能力,参考 [接口文档](https://docs.link-ai.tech/platform/api)。
|
||||
同时支持使用 **LinkAI平台** 接口,支持上述全部模型,并支持知识库、工作流、插件等Agent技能,参考 [接口文档](https://docs.link-ai.tech/platform/api)。
|
||||
|
||||
### 2.环境安装
|
||||
|
||||
@@ -226,8 +226,9 @@ nohup python3 app.py & tail -f nohup.out
|
||||
|
||||
执行后程序运行于服务器后台,可通过 `ctrl+c` 关闭日志,不会影响后台程序的运行。使用 `ps -ef | grep app.py | grep -v grep` 命令可查看运行于后台的进程,如果想要重新启动程序可以先 `kill` 掉对应的进程。 日志关闭后如果想要再次打开只需输入 `tail -f nohup.out`。
|
||||
|
||||
此外,项目的 `scripts` 目录下有一键运行、关闭程序的脚本供使用。 运行后默认channel为web,通过可以通过修改配置文件进行切换。
|
||||
此外,项目根目录下的 `run.sh` 脚本支持一键启动和管理服务,包括 `./run.sh start`、`./run.sh stop`、`./run.sh restart`、`./run.sh logs` 等命令,执行 `./run.sh help` 可查看全部用法。
|
||||
|
||||
> 如果需要通过浏览器访问Web控制台,请确保服务器的 `9899` 端口已在防火墙或安全组中放行,建议仅对指定IP开放以保证安全。
|
||||
|
||||
### 3.Docker部署
|
||||
|
||||
@@ -257,17 +258,7 @@ sudo docker compose up -d # 若docker-compose为 1.X 版本,则执行
|
||||
sudo docker logs -f chatgpt-on-wechat
|
||||
```
|
||||
|
||||
**(3) 插件使用**
|
||||
|
||||
如果需要在docker容器中修改插件配置,可通过挂载的方式完成,将 [插件配置文件](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/config.json.template)
|
||||
重命名为 `config.json`,放置于 `docker-compose.yml` 相同目录下,并在 `docker-compose.yml` 中的 `chatgpt-on-wechat` 部分下添加 `volumes` 映射:
|
||||
|
||||
```
|
||||
volumes:
|
||||
- ./config.json:/app/plugins/config.json
|
||||
```
|
||||
**注**:使用docker方式部署的详细教程可以参考:[docker部署CoW项目](https://www.wangpc.cc/ai/docker-deploy-cow/)
|
||||
|
||||
> 如果需要通过浏览器访问Web控制台,请确保服务器的 `9899` 端口已在防火墙或安全组中放行,建议仅对指定IP开放以保证安全。
|
||||
|
||||
## 模型说明
|
||||
|
||||
@@ -613,7 +604,7 @@ API Key创建:在 [控制台](https://aistudio.google.com/app/apikey?hl=zh-cn)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Coding Plan (编程包月套餐)</summary>
|
||||
<summary>Coding Plan</summary>
|
||||
|
||||
Coding Plan 是各厂商推出的编程包月套餐,所有厂商均可通过 OpenAI 兼容方式接入:
|
||||
|
||||
|
||||
@@ -5,22 +5,37 @@ services:
|
||||
container_name: chatgpt-on-wechat
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
ports:
|
||||
- "9899:9899"
|
||||
environment:
|
||||
CHANNEL_TYPE: 'web'
|
||||
OPEN_AI_API_KEY: 'YOUR API KEY'
|
||||
MODEL: ''
|
||||
PROXY: ''
|
||||
SINGLE_CHAT_PREFIX: '["bot", "@bot"]'
|
||||
SINGLE_CHAT_REPLY_PREFIX: '"[bot] "'
|
||||
GROUP_CHAT_PREFIX: '["@bot"]'
|
||||
GROUP_NAME_WHITE_LIST: '["ChatGPT测试群", "ChatGPT测试群2"]'
|
||||
IMAGE_CREATE_PREFIX: '["画", "看", "找"]'
|
||||
CONVERSATION_MAX_TOKENS: 1000
|
||||
SPEECH_RECOGNITION: 'False'
|
||||
CHARACTER_DESC: '你是基于大语言模型的AI智能助手,旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。'
|
||||
EXPIRES_IN_SECONDS: 3600
|
||||
USE_GLOBAL_PLUGIN_CONFIG: 'True'
|
||||
MODEL: 'MiniMax-M2.5'
|
||||
MINIMAX_API_KEY: ''
|
||||
ZHIPU_AI_API_KEY: ''
|
||||
ARK_API_KEY: ''
|
||||
MOONSHOT_API_KEY: ''
|
||||
DASHSCOPE_API_KEY: ''
|
||||
CLAUDE_API_KEY: ''
|
||||
CLAUDE_API_BASE: 'https://api.anthropic.com/v1'
|
||||
OPEN_AI_API_KEY: ''
|
||||
OPEN_AI_API_BASE: 'https://api.openai.com/v1'
|
||||
GEMINI_API_KEY: ''
|
||||
GEMINI_API_BASE: 'https://generativelanguage.googleapis.com'
|
||||
VOICE_TO_TEXT: 'openai'
|
||||
TEXT_TO_VOICE: 'openai'
|
||||
VOICE_REPLY_VOICE: 'False'
|
||||
SPEECH_RECOGNITION: 'True'
|
||||
GROUP_SPEECH_RECOGNITION: 'False'
|
||||
USE_LINKAI: 'False'
|
||||
AGENT: 'True'
|
||||
LINKAI_API_KEY: ''
|
||||
LINKAI_APP_CODE: ''
|
||||
FEISHU_APP_ID: ''
|
||||
FEISHU_APP_SECRET: ''
|
||||
DINGTALK_CLIENT_ID: ''
|
||||
DINGTALK_CLIENT_SECRET: ''
|
||||
WECOM_BOT_ID: ''
|
||||
WECOM_BOT_SECRET: ''
|
||||
AGENT: 'True'
|
||||
AGENT_MAX_CONTEXT_TOKENS: 40000
|
||||
AGENT_MAX_CONTEXT_TURNS: 20
|
||||
AGENT_MAX_STEPS: 15
|
||||
|
||||
@@ -56,9 +56,13 @@ python3 app.py
|
||||
nohup python3 app.py & tail -f nohup.out
|
||||
```
|
||||
|
||||
<Tip>
|
||||
如果在服务器上部署,需要在防火墙或安全组中放行 `9899` 端口才能通过浏览器访问 Web 控制台,建议仅对指定IP开放以保证安全。
|
||||
</Tip>
|
||||
|
||||
## Docker 部署
|
||||
|
||||
使用 Docker 部署无需下载源码和安装依赖。Agent 模式下更推荐使用源码部署以获得更多系统访问能力。
|
||||
使用 Docker 部署无需下载源码和安装依赖。Agent模式下更推荐使用源码部署以获得更多系统访问能力。
|
||||
|
||||
<Note>
|
||||
需要安装 [Docker](https://docs.docker.com/engine/install/) 和 docker-compose。
|
||||
@@ -84,6 +88,10 @@ sudo docker compose up -d
|
||||
sudo docker logs -f chatgpt-on-wechat
|
||||
```
|
||||
|
||||
<Tip>
|
||||
如果在服务器上部署,需要在防火墙或安全组中放行 `9899` 端口才能通过浏览器访问 Web 控制台,建议仅对指定IP开放以保证安全。
|
||||
</Tip>
|
||||
|
||||
## 核心配置项
|
||||
|
||||
```json
|
||||
|
||||
@@ -55,6 +55,12 @@ Web 控制台对话界面支持文件和图片上传,可直接发送文件给
|
||||
- **图片识别**:将图片识别(Image Vision)从 Skill 重构为内置 Tool,新增独立的图片视觉提供方(Vision Provider)配置,提升稳定性和可维护性 ([a50fafa](https://github.com/zhayujie/chatgpt-on-wechat/commit/a50fafa), [3b8b562](https://github.com/zhayujie/chatgpt-on-wechat/commit/3b8b562))
|
||||
- **网页抓取**:将网页抓取(Web Fetch)从 Skill 重构为内置 Tool,支持远程文档文件(PDF、Word、Excel、PPT)的下载和解析 ([ccb9030](https://github.com/zhayujie/chatgpt-on-wechat/commit/ccb9030), [fa61744](https://github.com/zhayujie/chatgpt-on-wechat/commit/fa61744))
|
||||
|
||||
## 🐳 Docker 部署优化
|
||||
|
||||
- **配置模板对齐**:`docker-compose.yml` 环境变量与 `config-template.json` 对齐,补充完整的模型 API Key 和 Agent 等配置项
|
||||
- **Web 控制台端口映射**:新增 `9899` 端口映射,Docker 部署后可通过浏览器访问 Web 控制台
|
||||
- **配置热更新**:各模型 Bot 的 API Key 和 API Base 改为实时读取,通过 Web 控制台修改配置后无需重启即可生效
|
||||
|
||||
## ⚡ 性能优化
|
||||
|
||||
- **启动加速**:飞书通道采用懒加载方式导入依赖,避免 4-10 秒的启动延迟 ([924dc79](https://github.com/zhayujie/chatgpt-on-wechat/commit/924dc79))
|
||||
|
||||
@@ -30,11 +30,20 @@ user_session = dict()
|
||||
class ClaudeAPIBot(Bot, OpenAIImage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.api_key = conf().get("claude_api_key")
|
||||
self.api_base = conf().get("claude_api_base") or "https://api.anthropic.com/v1"
|
||||
self.proxy = conf().get("proxy", None)
|
||||
self.sessions = SessionManager(BaiduWenxinSession, model=conf().get("model") or "text-davinci-003")
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("claude_api_key")
|
||||
|
||||
@property
|
||||
def api_base(self):
|
||||
return conf().get("claude_api_base") or "https://api.anthropic.com/v1"
|
||||
|
||||
@property
|
||||
def proxy(self):
|
||||
return conf().get("proxy", None)
|
||||
|
||||
def reply(self, query, context=None):
|
||||
# acquire reply content
|
||||
if context and context.type:
|
||||
|
||||
@@ -35,10 +35,14 @@ class DashscopeBot(Bot):
|
||||
super().__init__()
|
||||
self.sessions = SessionManager(DashscopeSession, model=conf().get("model") or "qwen-plus")
|
||||
self.model_name = conf().get("model") or "qwen-plus"
|
||||
self.api_key = conf().get("dashscope_api_key")
|
||||
if self.api_key:
|
||||
os.environ["DASHSCOPE_API_KEY"] = self.api_key
|
||||
self.client = dashscope.Generation
|
||||
api_key = conf().get("dashscope_api_key")
|
||||
if api_key:
|
||||
os.environ["DASHSCOPE_API_KEY"] = api_key
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("dashscope_api_key")
|
||||
|
||||
@staticmethod
|
||||
def _is_multimodal_model(model_name: str) -> bool:
|
||||
|
||||
@@ -24,13 +24,17 @@ class DoubaoBot(Bot):
|
||||
"temperature": conf().get("temperature", 0.8),
|
||||
"top_p": conf().get("top_p", 1.0),
|
||||
}
|
||||
self.api_key = conf().get("ark_api_key")
|
||||
self.base_url = conf().get("ark_base_url", "https://ark.cn-beijing.volces.com/api/v3")
|
||||
# Ensure base_url does not end with /chat/completions
|
||||
if self.base_url.endswith("/chat/completions"):
|
||||
self.base_url = self.base_url.rsplit("/chat/completions", 1)[0]
|
||||
if self.base_url.endswith("/"):
|
||||
self.base_url = self.base_url.rstrip("/")
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("ark_api_key")
|
||||
|
||||
@property
|
||||
def base_url(self):
|
||||
url = conf().get("ark_base_url", "https://ark.cn-beijing.volces.com/api/v3")
|
||||
if url.endswith("/chat/completions"):
|
||||
url = url.rsplit("/chat/completions", 1)[0]
|
||||
return url.rstrip("/")
|
||||
|
||||
def reply(self, query, context=None):
|
||||
# acquire reply content
|
||||
|
||||
@@ -28,21 +28,18 @@ class GoogleGeminiBot(Bot):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.api_key = conf().get("gemini_api_key")
|
||||
# 复用chatGPT的token计算方式
|
||||
self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo")
|
||||
self.model = conf().get("model") or "gemini-pro"
|
||||
if self.model == "gemini":
|
||||
self.model = "gemini-pro"
|
||||
|
||||
# 支持自定义API base地址
|
||||
self.api_base = conf().get("gemini_api_base", "").strip()
|
||||
if self.api_base:
|
||||
# 移除末尾的斜杠
|
||||
self.api_base = self.api_base.rstrip('/')
|
||||
logger.info(f"[Gemini] Using custom API base: {self.api_base}")
|
||||
else:
|
||||
self.api_base = "https://generativelanguage.googleapis.com"
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("gemini_api_key")
|
||||
|
||||
@property
|
||||
def api_base(self):
|
||||
base = conf().get("gemini_api_base", "").strip()
|
||||
if base:
|
||||
return base.rstrip('/')
|
||||
return "https://generativelanguage.googleapis.com"
|
||||
|
||||
def reply(self, query, context: Context = None) -> Reply:
|
||||
session_id = None
|
||||
|
||||
@@ -24,21 +24,19 @@ class MinimaxBot(Bot):
|
||||
"temperature": conf().get("temperature", 0.3),
|
||||
"top_p": conf().get("top_p", 0.95),
|
||||
}
|
||||
# Use unified key name: minimax_api_key
|
||||
self.api_key = conf().get("minimax_api_key")
|
||||
if not self.api_key:
|
||||
# Fallback to old key name for backward compatibility
|
||||
self.api_key = conf().get("Minimax_api_key")
|
||||
if self.api_key:
|
||||
logger.warning("[MINIMAX] 'Minimax_api_key' is deprecated, please use 'minimax_api_key' instead")
|
||||
|
||||
# REST API endpoint
|
||||
# Use Chinese endpoint by default, users can override in config
|
||||
# International users should set: "minimax_api_base": "https://api.minimax.io/v1"
|
||||
self.api_base = conf().get("minimax_api_base", "https://api.minimaxi.com/v1")
|
||||
|
||||
self.sessions = SessionManager(MinimaxSession, model=const.MiniMax)
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
key = conf().get("minimax_api_key")
|
||||
if not key:
|
||||
key = conf().get("Minimax_api_key")
|
||||
return key
|
||||
|
||||
@property
|
||||
def api_base(self):
|
||||
return conf().get("minimax_api_base", "https://api.minimaxi.com/v1")
|
||||
|
||||
def reply(self, query, context: Context = None) -> Reply:
|
||||
# acquire reply content
|
||||
logger.info("[MINIMAX] query={}".format(query))
|
||||
|
||||
@@ -26,8 +26,14 @@ class ModelScopeBot(Bot):
|
||||
"temperature": conf().get("temperature", 0.3), # 如果设置,值域须为 [0, 1] 我们推荐 0.3,以达到较合适的效果。
|
||||
"top_p": conf().get("top_p", 1.0), # 使用默认值
|
||||
}
|
||||
self.api_key = conf().get("modelscope_api_key")
|
||||
self.base_url = conf().get("modelscope_base_url", "https://api-inference.modelscope.cn/v1/chat/completions")
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("modelscope_api_key")
|
||||
|
||||
@property
|
||||
def base_url(self):
|
||||
return conf().get("modelscope_base_url", "https://api-inference.modelscope.cn/v1/chat/completions")
|
||||
"""
|
||||
需要获取ModelScope支持API-inference的模型名称列表,请到魔搭社区官网模型中心查看 https://modelscope.cn/models?filter=inference_type&page=1。
|
||||
或者使用命令 curl https://api-inference.modelscope.cn/v1/models 对模型列表和ID进行获取。查看commend/const.py文件也可以获取模型列表。
|
||||
|
||||
@@ -26,13 +26,17 @@ class MoonshotBot(Bot):
|
||||
"temperature": conf().get("temperature", 0.3),
|
||||
"top_p": conf().get("top_p", 1.0),
|
||||
}
|
||||
self.api_key = conf().get("moonshot_api_key")
|
||||
self.base_url = conf().get("moonshot_base_url", "https://api.moonshot.cn/v1")
|
||||
# Ensure base_url does not end with /chat/completions (backward compat)
|
||||
if self.base_url.endswith("/chat/completions"):
|
||||
self.base_url = self.base_url.rsplit("/chat/completions", 1)[0]
|
||||
if self.base_url.endswith("/"):
|
||||
self.base_url = self.base_url.rstrip("/")
|
||||
|
||||
@property
|
||||
def api_key(self):
|
||||
return conf().get("moonshot_api_key")
|
||||
|
||||
@property
|
||||
def base_url(self):
|
||||
url = conf().get("moonshot_base_url", "https://api.moonshot.cn/v1")
|
||||
if url.endswith("/chat/completions"):
|
||||
url = url.rsplit("/chat/completions", 1)[0]
|
||||
return url.rstrip("/")
|
||||
|
||||
def reply(self, query, context=None):
|
||||
# acquire reply content
|
||||
|
||||
Reference in New Issue
Block a user