mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-05-16 17:29:18 +08:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 883f0d449b | |||
| f4c62e7844 | |||
| f0d212a9d2 | |||
| 76a8974034 | |||
| 0614e822f4 | |||
| 6f682c9a2e | |||
| a9fdbc31c5 | |||
| 086fdb5856 | |||
| 63c8ef4f17 | |||
| 736f6523c7 | |||
| 8b0b360d25 | |||
| 80b84e2ee6 | |||
| b5b7d86f7b | |||
| f20d704390 | |||
| e4e1e2e944 | |||
| 6bc7eeb4cc | |||
| 656ed5de7b | |||
| a11d695c78 | |||
| c4f9acd5c5 | |||
| 5ef929dc42 | |||
| c8cf27b544 | |||
| bb5ecfc398 | |||
| c91e7c35bb | |||
| 532d56df2d | |||
| 111ad44029 | |||
| 6b02bae957 | |||
| 6831743416 | |||
| 63e2f42636 | |||
| f6e6805453 | |||
| ad77ad8f2b |
@@ -46,7 +46,9 @@ DEMO视频:https://cdn.link-ai.tech/doc/cow_demo.mp4
|
||||
|
||||
# 🏷 更新日志
|
||||
|
||||
>**2024.08.02:** [1.7.0版本](https://github.com/zhayujie/chatgpt-on-wechat/releases/tag/1.6.9) 新增 讯飞4.0 模型、知识库引用来源展示、相关插件优化
|
||||
>**2024.09.26:** [1.7.2版本](https://github.com/zhayujie/chatgpt-on-wechat/releases/tag/1.7.2) 和 [1.7.1版本](https://github.com/zhayujie/chatgpt-on-wechat/releases/tag/1.7.1) 文心,讯飞等模型优化、o1 模型、快速安装和管理脚本
|
||||
|
||||
>**2024.08.02:** [1.7.0版本](https://github.com/zhayujie/chatgpt-on-wechat/releases/tag/1.7.0) 新增 讯飞4.0 模型、知识库引用来源展示、相关插件优化
|
||||
|
||||
>**2024.07.19:** [1.6.9版本](https://github.com/zhayujie/chatgpt-on-wechat/releases/tag/1.6.9) 新增 gpt-4o-mini 模型、阿里语音识别、企微应用渠道路由优化
|
||||
|
||||
@@ -80,8 +82,13 @@ DEMO视频:https://cdn.link-ai.tech/doc/cow_demo.mp4
|
||||
|
||||
# 🚀 快速开始
|
||||
|
||||
快速开始详细文档:[项目搭建文档](https://docs.link-ai.tech/cow/quick-start)
|
||||
- 快速开始详细文档:[项目搭建文档](https://docs.link-ai.tech/cow/quick-start)
|
||||
|
||||
- 快速安装脚本,详细使用指导:[一键安装启动脚本](https://github.com/zhayujie/chatgpt-on-wechat/wiki/%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC)
|
||||
```bash
|
||||
bash <(curl -sS https://cdn.link-ai.tech/code/cow/install.sh)
|
||||
```
|
||||
- 项目管理脚本,详细使用指导:[项目管理脚本](https://github.com/zhayujie/chatgpt-on-wechat/wiki/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E8%84%9A%E6%9C%AC)
|
||||
## 一、准备
|
||||
|
||||
### 1. 账号注册
|
||||
|
||||
@@ -5,7 +5,7 @@ import time
|
||||
import openai
|
||||
import openai.error
|
||||
import requests
|
||||
|
||||
from common import const
|
||||
from bot.bot import Bot
|
||||
from bot.chatgpt.chat_gpt_session import ChatGPTSession
|
||||
from bot.openai.open_ai_image import OpenAIImage
|
||||
@@ -15,7 +15,7 @@ from bridge.reply import Reply, ReplyType
|
||||
from common.log import logger
|
||||
from common.token_bucket import TokenBucket
|
||||
from config import conf, load_config
|
||||
|
||||
from bot.baidu.baidu_wenxin_session import BaiduWenxinSession
|
||||
|
||||
# OpenAI对话模型API (可用)
|
||||
class ChatGPTBot(Bot, OpenAIImage):
|
||||
@@ -30,10 +30,12 @@ class ChatGPTBot(Bot, OpenAIImage):
|
||||
openai.proxy = proxy
|
||||
if conf().get("rate_limit_chatgpt"):
|
||||
self.tb4chatgpt = TokenBucket(conf().get("rate_limit_chatgpt", 20))
|
||||
|
||||
conf_model = conf().get("model") or "gpt-3.5-turbo"
|
||||
self.sessions = SessionManager(ChatGPTSession, model=conf().get("model") or "gpt-3.5-turbo")
|
||||
# o1相关模型不支持system prompt,暂时用文心模型的session
|
||||
|
||||
self.args = {
|
||||
"model": conf().get("model") or "gpt-3.5-turbo", # 对话模型的名称
|
||||
"model": conf_model, # 对话模型的名称
|
||||
"temperature": conf().get("temperature", 0.9), # 值在[0,1]之间,越大表示回复越具有不确定性
|
||||
# "max_tokens":4096, # 回复最大的字符数
|
||||
"top_p": conf().get("top_p", 1),
|
||||
@@ -42,6 +44,12 @@ class ChatGPTBot(Bot, OpenAIImage):
|
||||
"request_timeout": conf().get("request_timeout", None), # 请求超时时间,openai接口默认设置为600,对于难问题一般需要较长时间
|
||||
"timeout": conf().get("request_timeout", None), # 重试超时时间,在这个时间内,将会自动重试
|
||||
}
|
||||
# o1相关模型固定了部分参数,暂时去掉
|
||||
if conf_model in [const.O1, const.O1_MINI]:
|
||||
self.sessions = SessionManager(BaiduWenxinSession, model=conf().get("model") or const.O1_MINI)
|
||||
remove_keys = ["temperature", "top_p", "frequency_penalty", "presence_penalty"]
|
||||
for key in remove_keys:
|
||||
self.args.pop(key, None) # 如果键不存在,使用 None 来避免抛出错误
|
||||
|
||||
def reply(self, query, context=None):
|
||||
# acquire reply content
|
||||
|
||||
@@ -67,7 +67,7 @@ def num_tokens_from_messages(messages, model):
|
||||
elif model in ["gpt-4-0314", "gpt-4-0613", "gpt-4-32k", "gpt-4-32k-0613", "gpt-3.5-turbo-0613",
|
||||
"gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-35-turbo-16k", "gpt-4-turbo-preview",
|
||||
"gpt-4-1106-preview", const.GPT4_TURBO_PREVIEW, const.GPT4_VISION_PREVIEW, const.GPT4_TURBO_01_25,
|
||||
const.GPT_4o, const.GPT_4o_MINI, const.LINKAI_4o, const.LINKAI_4_TURBO]:
|
||||
const.GPT_4o, const.GPT_4O_0806, const.GPT_4o_MINI, const.LINKAI_4o, const.LINKAI_4_TURBO]:
|
||||
return num_tokens_from_messages(messages, model="gpt-4")
|
||||
elif model.startswith("claude-3"):
|
||||
return num_tokens_from_messages(messages, model="gpt-3.5-turbo")
|
||||
|
||||
@@ -13,7 +13,9 @@ from bridge.context import ContextType, Context
|
||||
from bridge.reply import Reply, ReplyType
|
||||
from common.log import logger
|
||||
from config import conf
|
||||
from bot.chatgpt.chat_gpt_session import ChatGPTSession
|
||||
from bot.baidu.baidu_wenxin_session import BaiduWenxinSession
|
||||
from google.generativeai.types import HarmCategory, HarmBlockThreshold
|
||||
|
||||
|
||||
# OpenAI对话模型API (可用)
|
||||
@@ -22,8 +24,8 @@ class GoogleGeminiBot(Bot):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.api_key = conf().get("gemini_api_key")
|
||||
# 复用文心的token计算方式
|
||||
self.sessions = SessionManager(BaiduWenxinSession, model=conf().get("model") or "gpt-3.5-turbo")
|
||||
# 复用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"
|
||||
@@ -36,18 +38,44 @@ class GoogleGeminiBot(Bot):
|
||||
session_id = context["session_id"]
|
||||
session = self.sessions.session_query(query, session_id)
|
||||
gemini_messages = self._convert_to_gemini_messages(self.filter_messages(session.messages))
|
||||
logger.debug(f"[Gemini] messages={gemini_messages}")
|
||||
genai.configure(api_key=self.api_key)
|
||||
model = genai.GenerativeModel(self.model)
|
||||
response = model.generate_content(gemini_messages)
|
||||
reply_text = response.text
|
||||
self.sessions.session_reply(reply_text, session_id)
|
||||
logger.info(f"[Gemini] reply={reply_text}")
|
||||
return Reply(ReplyType.TEXT, reply_text)
|
||||
|
||||
# 添加安全设置
|
||||
safety_settings = {
|
||||
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
|
||||
HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
|
||||
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
|
||||
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
|
||||
}
|
||||
|
||||
# 生成回复,包含安全设置
|
||||
response = model.generate_content(
|
||||
gemini_messages,
|
||||
safety_settings=safety_settings
|
||||
)
|
||||
if response.candidates and response.candidates[0].content:
|
||||
reply_text = response.candidates[0].content.parts[0].text
|
||||
logger.info(f"[Gemini] reply={reply_text}")
|
||||
self.sessions.session_reply(reply_text, session_id)
|
||||
return Reply(ReplyType.TEXT, reply_text)
|
||||
else:
|
||||
# 没有有效响应内容,可能内容被屏蔽,输出安全评分
|
||||
logger.warning("[Gemini] No valid response generated. Checking safety ratings.")
|
||||
if hasattr(response, 'candidates') and response.candidates:
|
||||
for rating in response.candidates[0].safety_ratings:
|
||||
logger.warning(f"Safety rating: {rating.category} - {rating.probability}")
|
||||
error_message = "No valid response generated due to safety constraints."
|
||||
self.sessions.session_reply(error_message, session_id)
|
||||
return Reply(ReplyType.ERROR, error_message)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("[Gemini] fetch reply error, may contain unsafe content")
|
||||
logger.error(e)
|
||||
return Reply(ReplyType.ERROR, "invoke [Gemini] api failed!")
|
||||
|
||||
logger.error(f"[Gemini] Error generating response: {str(e)}", exc_info=True)
|
||||
error_message = "Failed to invoke [Gemini] api!"
|
||||
self.sessions.session_reply(error_message, session_id)
|
||||
return Reply(ReplyType.ERROR, error_message)
|
||||
|
||||
def _convert_to_gemini_messages(self, messages: list):
|
||||
res = []
|
||||
for msg in messages:
|
||||
@@ -55,6 +83,8 @@ class GoogleGeminiBot(Bot):
|
||||
role = "user"
|
||||
elif msg.get("role") == "assistant":
|
||||
role = "model"
|
||||
elif msg.get("role") == "system":
|
||||
role = "user"
|
||||
else:
|
||||
continue
|
||||
res.append({
|
||||
@@ -71,7 +101,11 @@ class GoogleGeminiBot(Bot):
|
||||
return res
|
||||
for i in range(len(messages) - 1, -1, -1):
|
||||
message = messages[i]
|
||||
if message.get("role") != turn:
|
||||
role = message.get("role")
|
||||
if role == "system":
|
||||
res.insert(0, message)
|
||||
continue
|
||||
if role != turn:
|
||||
continue
|
||||
res.insert(0, message)
|
||||
if turn == "user":
|
||||
|
||||
@@ -19,8 +19,11 @@ class MoonshotBot(Bot):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.sessions = SessionManager(MoonshotSession, model=conf().get("model") or "moonshot-v1-128k")
|
||||
model = conf().get("model") or "moonshot-v1-128k"
|
||||
if model == "moonshot":
|
||||
model = "moonshot-v1-32k"
|
||||
self.args = {
|
||||
"model": conf().get("model") or "moonshot-v1-128k", # 对话模型的名称
|
||||
"model": model, # 对话模型的名称
|
||||
"temperature": conf().get("temperature", 0.3), # 如果设置,值域须为 [0, 1] 我们推荐 0.3,以达到较合适的效果。
|
||||
"top_p": conf().get("top_p", 1.0), # 使用默认值
|
||||
}
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ class Bridge(object):
|
||||
self.btype["chat"] = const.QWEN_DASHSCOPE
|
||||
if model_type and model_type.startswith("gemini"):
|
||||
self.btype["chat"] = const.GEMINI
|
||||
if model_type in [const.ZHIPU_AI]:
|
||||
if model_type and model_type.startswith("glm"):
|
||||
self.btype["chat"] = const.ZHIPU_AI
|
||||
if model_type and model_type.startswith("claude-3"):
|
||||
self.btype["chat"] = const.CLAUDEAPI
|
||||
@@ -46,7 +46,7 @@ class Bridge(object):
|
||||
if model_type in ["claude"]:
|
||||
self.btype["chat"] = const.CLAUDEAI
|
||||
|
||||
if model_type in ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"]:
|
||||
if model_type in [const.MOONSHOT, "moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"]:
|
||||
self.btype["chat"] = const.MOONSHOT
|
||||
|
||||
if model_type in ["abab6.5-chat"]:
|
||||
|
||||
@@ -100,7 +100,10 @@ def qrCallback(uuid, status, qrcode):
|
||||
qr = qrcode.QRCode(border=1)
|
||||
qr.add_data(url)
|
||||
qr.make(fit=True)
|
||||
qr.print_ascii(invert=True)
|
||||
try:
|
||||
qr.print_ascii(invert=True)
|
||||
except UnicodeEncodeError:
|
||||
print("ASCII QR code printing failed due to encoding issues.")
|
||||
|
||||
|
||||
@singleton
|
||||
|
||||
+17
-2
@@ -24,6 +24,7 @@ GPT35_0125 = "gpt-3.5-turbo-0125"
|
||||
GPT35_1106 = "gpt-3.5-turbo-1106"
|
||||
|
||||
GPT_4o = "gpt-4o"
|
||||
GPT_4O_0806 = "gpt-4o-2024-08-06"
|
||||
GPT4_TURBO = "gpt-4-turbo"
|
||||
GPT4_TURBO_PREVIEW = "gpt-4-turbo-preview"
|
||||
GPT4_TURBO_04_09 = "gpt-4-turbo-2024-04-09"
|
||||
@@ -37,6 +38,9 @@ GPT4_32k = "gpt-4-32k"
|
||||
GPT4_06_13 = "gpt-4-0613"
|
||||
GPT4_32k_06_13 = "gpt-4-32k-0613"
|
||||
|
||||
O1 = "o1-preview"
|
||||
O1_MINI = "o1-mini"
|
||||
|
||||
WHISPER_1 = "whisper-1"
|
||||
TTS_1 = "tts-1"
|
||||
TTS_1_HD = "tts-1-hd"
|
||||
@@ -56,11 +60,22 @@ GEMINI_PRO = "gemini-1.0-pro"
|
||||
GEMINI_15_flash = "gemini-1.5-flash"
|
||||
GEMINI_15_PRO = "gemini-1.5-pro"
|
||||
|
||||
GLM_4 = "glm-4"
|
||||
GLM_4_PLUS = "glm-4-plus"
|
||||
GLM_4_flash = "glm-4-flash"
|
||||
GLM_4_LONG = "glm-4-long"
|
||||
GLM_4_ALLTOOLS = "glm-4-alltools"
|
||||
GLM_4_0520 = "glm-4-0520"
|
||||
GLM_4_AIR = "glm-4-air"
|
||||
GLM_4_AIRX = "glm-4-airx"
|
||||
|
||||
MODEL_LIST = [
|
||||
GPT35, GPT35_0125, GPT35_1106, "gpt-3.5-turbo-16k",
|
||||
GPT_4o, GPT_4o_MINI, GPT4_TURBO, GPT4_TURBO_PREVIEW, GPT4_TURBO_01_25, GPT4_TURBO_11_06, GPT4, GPT4_32k, GPT4_06_13, GPT4_32k_06_13,
|
||||
O1, O1_MINI, GPT_4o, GPT_4O_0806, GPT_4o_MINI, GPT4_TURBO, GPT4_TURBO_PREVIEW, GPT4_TURBO_01_25, GPT4_TURBO_11_06, GPT4, GPT4_32k, GPT4_06_13, GPT4_32k_06_13,
|
||||
WEN_XIN, WEN_XIN_4,
|
||||
XUNFEI, ZHIPU_AI, MOONSHOT, MiniMax,
|
||||
XUNFEI,
|
||||
ZHIPU_AI, GLM_4, GLM_4_PLUS, GLM_4_flash, GLM_4_LONG, GLM_4_ALLTOOLS, GLM_4_0520, GLM_4_AIR, GLM_4_AIRX,
|
||||
MOONSHOT, MiniMax,
|
||||
GEMINI, GEMINI_PRO, GEMINI_15_flash, GEMINI_15_PRO,
|
||||
"claude", "claude-3-haiku", "claude-3-sonnet", "claude-3-opus", "claude-3-opus-20240229", "claude-3.5-sonnet",
|
||||
"moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k",
|
||||
|
||||
@@ -42,8 +42,13 @@ class ChatClient(LinkAIClient):
|
||||
if reply_voice_mode:
|
||||
if reply_voice_mode == "voice_reply_voice":
|
||||
local_config["voice_reply_voice"] = True
|
||||
local_config["always_reply_voice"] = False
|
||||
elif reply_voice_mode == "always_reply_voice":
|
||||
local_config["always_reply_voice"] = True
|
||||
local_config["voice_reply_voice"] = True
|
||||
elif reply_voice_mode == "no_reply_voice":
|
||||
local_config["always_reply_voice"] = False
|
||||
local_config["voice_reply_voice"] = False
|
||||
|
||||
if config.get("admin_password"):
|
||||
if not plugin_config.get("Godcmd"):
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m' # 红色
|
||||
GREEN='\033[0;32m' # 绿色
|
||||
YELLOW='\033[0;33m' # 黄色
|
||||
BLUE='\033[0;34m' # 蓝色
|
||||
NC='\033[0m' # 无颜色
|
||||
|
||||
# 获取当前脚本的目录
|
||||
export BASE_DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
echo -e "${GREEN}📁 BASE_DIR: ${BASE_DIR}${NC}"
|
||||
|
||||
# 检查 config.json 文件是否存在
|
||||
check_config_file() {
|
||||
if [ ! -f "${BASE_DIR}/config.json" ]; then
|
||||
echo -e "${RED}❌ 错误:未找到 config.json 文件。请确保 config.json 存在于当前目录。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 Python 版本是否大于等于 3.7,并检查 pip 是否可用
|
||||
check_python_version() {
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo -e "${RED}❌ 错误:未找到 Python3。请安装 Python 3.7 或以上版本。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||||
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d'.' -f1)
|
||||
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d'.' -f2)
|
||||
|
||||
if (( PYTHON_MAJOR < 3 || (PYTHON_MAJOR == 3 && PYTHON_MINOR < 7) )); then
|
||||
echo -e "${RED}❌ 错误:Python 版本为 ${PYTHON_VERSION}。请安装 Python 3.7 或以上版本。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! python3 -m pip --version &> /dev/null; then
|
||||
echo -e "${RED}❌ 错误:未找到 pip。请安装 pip。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查并安装缺失的依赖
|
||||
install_dependencies() {
|
||||
echo -e "${YELLOW}⏳ 正在安装依赖...${NC}"
|
||||
|
||||
if [ ! -f "${BASE_DIR}/requirements.txt" ]; then
|
||||
echo -e "${RED}❌ 错误:未找到 requirements.txt 文件。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 安装 requirements.txt 中的依赖,使用清华大学的 PyPI 镜像
|
||||
pip3 install -r "${BASE_DIR}/requirements.txt" -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# 处理 requirements-optional.txt(如果存在)
|
||||
if [ -f "${BASE_DIR}/requirements-optional.txt" ]; then
|
||||
echo -e "${YELLOW}⏳ 正在安装可选的依赖...${NC}"
|
||||
pip3 install -r "${BASE_DIR}/requirements-optional.txt" -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动项目
|
||||
run_project() {
|
||||
echo -e "${GREEN}🚀 准备启动项目...${NC}"
|
||||
cd "${BASE_DIR}"
|
||||
sleep 2
|
||||
|
||||
|
||||
# 判断操作系统类型
|
||||
OS_TYPE=$(uname)
|
||||
|
||||
if [[ "$OS_TYPE" == "Linux" ]]; then
|
||||
# 在 Linux 上使用 setsid
|
||||
setsid python3 "${BASE_DIR}/app.py" > "${BASE_DIR}/nohup.out" 2>&1 &
|
||||
echo -e "${GREEN}🚀 正在启动 ChatGPT-on-WeChat (Linux)...${NC}"
|
||||
elif [[ "$OS_TYPE" == "Darwin" ]]; then
|
||||
# 在 macOS 上直接运行
|
||||
python3 "${BASE_DIR}/app.py" > "${BASE_DIR}/nohup.out" 2>&1 &
|
||||
echo -e "${GREEN}🚀 正在启动 ChatGPT-on-WeChat (macOS)...${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ 错误:不支持的操作系统 ${OS_TYPE}。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
# 显示日志输出,供用户扫码
|
||||
tail -n 30 -f "${BASE_DIR}/nohup.out"
|
||||
|
||||
}
|
||||
# 更新项目
|
||||
update_project() {
|
||||
echo -e "${GREEN}🔄 准备更新项目,现在停止项目...${NC}"
|
||||
cd "${BASE_DIR}"
|
||||
|
||||
# 停止项目
|
||||
stop_project
|
||||
echo -e "${GREEN}🔄 开始更新项目...${NC}"
|
||||
# 更新代码,从 git 仓库拉取最新代码
|
||||
if [ -d .git ]; then
|
||||
GIT_PULL_OUTPUT=$(git pull)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [[ "$GIT_PULL_OUTPUT" == *"Already up to date."* ]]; then
|
||||
echo -e "${GREEN}✅ 代码已经是最新的。${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✅ 代码更新完成。${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 从 GitHub 更新失败,尝试切换到 Gitee 仓库...${NC}"
|
||||
# 更改远程仓库为 Gitee
|
||||
git remote set-url origin https://gitee.com/zhayujie/chatgpt-on-wechat.git
|
||||
GIT_PULL_OUTPUT=$(git pull)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [[ "$GIT_PULL_OUTPUT" == *"Already up to date."* ]]; then
|
||||
echo -e "${GREEN}✅ 代码已经是最新的。${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✅ 从 Gitee 更新成功。${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}❌ 错误:从 Gitee 更新仍然失败,请检查网络连接。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}❌ 错误:当前目录不是 git 仓库,无法更新代码。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 安装依赖
|
||||
install_dependencies
|
||||
|
||||
# 启动项目
|
||||
run_project
|
||||
}
|
||||
|
||||
# 停止项目
|
||||
stop_project() {
|
||||
echo -e "${GREEN}🛑 正在停止项目...${NC}"
|
||||
cd "${BASE_DIR}"
|
||||
pid=$(ps ax | grep -i app.py | grep "${BASE_DIR}" | grep python3 | grep -v grep | awk '{print $1}')
|
||||
if [ -z "$pid" ] ; then
|
||||
echo -e "${YELLOW}⚠️ 未找到正在运行的 ChatGPT-on-WeChat。${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}🛑 正在运行的 ChatGPT-on-WeChat (PID: ${pid})${NC}"
|
||||
|
||||
kill ${pid}
|
||||
sleep 3
|
||||
|
||||
if ps -p $pid > /dev/null; then
|
||||
echo -e "${YELLOW}⚠️ 进程未停止,尝试强制终止...${NC}"
|
||||
kill -9 ${pid}
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ 已停止 ChatGPT-on-WeChat (PID: ${pid})${NC}"
|
||||
}
|
||||
|
||||
# 主函数,根据用户参数执行操作
|
||||
case "$1" in
|
||||
start)
|
||||
check_config_file
|
||||
check_python_version
|
||||
run_project
|
||||
;;
|
||||
stop)
|
||||
stop_project
|
||||
;;
|
||||
restart)
|
||||
stop_project
|
||||
check_config_file
|
||||
check_python_version
|
||||
run_project
|
||||
;;
|
||||
update)
|
||||
check_config_file
|
||||
check_python_version
|
||||
update_project
|
||||
;;
|
||||
*)
|
||||
echo -e "${YELLOW}=========================================${NC}"
|
||||
echo -e "${YELLOW}用法:${GREEN}$0 ${BLUE}{start|stop|restart|update}${NC}"
|
||||
echo -e "${YELLOW}示例:${NC}"
|
||||
echo -e " ${GREEN}$0 ${BLUE}start${NC}"
|
||||
echo -e " ${GREEN}$0 ${BLUE}stop${NC}"
|
||||
echo -e " ${GREEN}$0 ${BLUE}restart${NC}"
|
||||
echo -e " ${GREEN}$0 ${BLUE}update${NC}"
|
||||
echo -e "${YELLOW}=========================================${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user