Files
script/ai/hwaishell.sh
T
2026-07-02 14:28:25 +08:00

288 lines
11 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ================= 颜色定义 =================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;36m'
PLAIN='\033[0m'
echo -e "${BLUE}==================================================${PLAIN}"
echo -e "${GREEN} 华为云 Token 动态网关 (6小时高能效缓存版) 部署 ${PLAIN}"
echo -e "${BLUE}==================================================${PLAIN}"
# 1. 检查权限
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}错误:请使用 root 用户运行此脚本!${PLAIN}"
exit 1
fi
# ================= 检测并安装 frpc =================
echo -e "\n${YELLOW}[1/5] 正在检测 frpc 环境...${PLAIN}"
if ! command -v frpc &> /dev/null && [ ! -f "/usr/local/bin/frpc" ] && [ ! -f "/usr/bin/frpc" ]; then
echo -e "${RED}未检测到 frpc${PLAIN}"
read -p "是否需要为您自动下载并安装最新版 frpc (使用国内加速镜像)? (y/n, 默认 y): " INSTALL_FRP
INSTALL_FRP=${INSTALL_FRP:-y}
if [[ "$INSTALL_FRP" == "y" || "$INSTALL_FRP" == "Y" ]]; then
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
FRP_ARCH="amd64"
elif [ "$ARCH" = "aarch64" ]; then
FRP_ARCH="arm64"
else
echo -e "${RED}错误:不支持的系统架构 $ARCH,请手动安装 frpc。${PLAIN}"
exit 1
fi
FRP_VERSION="0.58.1"
echo -e "${GREEN}开始通过国内节点下载 frpc v${FRP_VERSION} ($FRP_ARCH)...${PLAIN}"
FRP_URL="https://mirror.ghproxy.com/https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_${FRP_ARCH}.tar.gz"
wget --no-check-certificate -O frp.tar.gz "$FRP_URL"
if [ $? -ne 0 ]; then echo -e "${RED}下载失败!${PLAIN}"; exit 1; fi
tar -zxvf frp.tar.gz > /dev/null
cd frp_${FRP_VERSION}_linux_${FRP_ARCH} || { echo -e "${RED}错误:无法进入解压目录!${PLAIN}"; exit 1; }
cp frpc /usr/local/bin/ && chmod +x /usr/local/bin/frpc
mkdir -p /etc/frp
if [ ! -f "/etc/frp/frpc.toml" ]; then
cat << EOF > /etc/frp/frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
EOF
fi
cat << EOF > /etc/systemd/system/frpc.service
[Unit]
Description=Frp Client Service
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
ExecReload=/usr/local/bin/frpc reload -c /etc/frp/frpc.toml
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable frpc --now
cd .. && rm -rf frp_${FRP_VERSION}_linux_${FRP_ARCH} frp.tar.gz
echo -e "${GREEN}frpc 安装并注册成功!配置文件位于 /etc/frp/frpc.toml${PLAIN}"
fi
else
echo -e "${GREEN}系统已安装 frpc。${PLAIN}"
fi
# ================= 配置网关与映射端口 =================
echo -e "\n${YELLOW}[2/5] 配置动态网关参数:${PLAIN}"
read -p "请输入 Python 动态网关的本地监听端口 (默认 8080): " GATEWAY_PORT
GATEWAY_PORT=${GATEWAY_PORT:-8080}
read -p "请输入你想在 frps 公网端暴露的端口 (默认 18000): " REMOTE_PORT
REMOTE_PORT=${REMOTE_PORT:-18000}
# ================= 查找 frpc 配置文件 =================
echo -e "\n${YELLOW}[3/5] 检测 frpc 配置文件位置以追加代理规则:${PLAIN}"
FRPC_CONFIG=""
if [ -f "/etc/frp/frpc.toml" ]; then FRPC_CONFIG="/etc/frp/frpc.toml"; FRPC_TYPE="toml";
elif [ -f "/etc/frp/frpc.ini" ]; then FRPC_CONFIG="/etc/frp/frpc.ini"; FRPC_TYPE="ini";
else
FRPC_PATH_SEARCH=$(find /etc /usr/local/etc /opt /home -maxdepth 4 -name "frpc.toml" -o -name "frpc.ini" 2>/dev/null | head -n 1)
if [ -n "$FRPC_PATH_SEARCH" ]; then
FRPC_CONFIG="$FRPC_PATH_SEARCH"
if [[ "$FRPC_PATH_SEARCH" == *.toml ]]; then FRPC_TYPE="toml"; else FRPC_TYPE="ini"; fi
fi
fi
if [ -n "$FRPC_CONFIG" ]; then
echo -e "${GREEN}识别到 frpc 配置: $FRPC_CONFIG (${FRPC_TYPE})${PLAIN}"
read -p "是否自动将华为云转发规则追加到该文件? (y/n, 默认 y): " APPEND_FRP
APPEND_FRP=${APPEND_FRP:-y}
else
APPEND_FRP="n"
fi
# ================= 安装 Python 依赖 =================
echo -e "\n${YELLOW}[4/5] 部署 Python 运行环境...${PLAIN}"
if ! command -v python3 &> /dev/null; then
if command -v apt &> /dev/null; then apt update -y && apt install -y python3 python3-pip;
elif command -v yum &> /dev/null; then yum install -y python3 python3-pip; fi
fi
python3 -m pip install flask requests --quiet -i https://pypi.tuna.tsinghua.edu.cn/simple
# ================= 创建网关核心代码 (核心优化点) =================
echo -e "\n${YELLOW}[5/5] 生成网关代码并启动服务...${PLAIN}"
cat << 'EOF' > /usr/local/bin/huawei_gateway.py
import os
import re
import time
import logging
import threading
import traceback
import requests
from flask import Flask, request, Response
from concurrent.futures import ThreadPoolExecutor
app = Flask(__name__)
logging.basicConfig(level=logging.WARNING,
format='%(asctime)s [%(levelname)s] %(message)s')
# 内存缓存字典:6小时有效期,这里设置为安全线 5.5 小时 (19800秒)
cache = {"token": None, "expires_at": 0}
cache_lock = threading.Lock()
def scan_pid_mem(pid):
try:
with open(f'/proc/{pid}/maps', 'r') as f:
for line in f:
parts = line.split()
if len(parts) < 2 or 'r' not in parts[1]: continue
addrs = parts[0].split('-')
if len(addrs) != 2: continue
start, end = int(addrs[0], 16), int(addrs[1], 16)
if (end - start) > 200 * 1024 * 1024: continue
try:
with open(f'/proc/{pid}/mem', 'rb') as mem:
mem.seek(start)
data = mem.read(end - start)
for m in re.finditer(b'Bearer ([A-Za-z0-9+/=_-]+)', data):
val = m.group(1).decode(errors='replace')
if len(val) > 200:
return val
except Exception:
continue
except Exception:
pass
return None
def force_refresh_token():
"""强制重新从内存扫描 Token 并更新缓存时间"""
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
with ThreadPoolExecutor(max_workers=8) as executor:
results = executor.map(scan_pid_mem, pids)
for token in results:
if token:
with cache_lock:
cache["token"] = token
cache["expires_at"] = time.time() + 19800 # 缓存 5.5 小时
return token
return cache["token"]
def get_latest_token():
now = time.time()
with cache_lock:
# 如果缓存存在且没过期,直接返回缓存(消耗几乎为 0)
if cache["token"] and now < cache["expires_at"]:
return cache["token"]
# 否则,或者过期了,才去扫描内存
return force_refresh_token()
@app.route('/v2/<path:subpath>', methods=['POST', 'GET', 'OPTIONS'])
def proxy(subpath):
if request.method == 'OPTIONS':
return Response(), 200
real_token = get_latest_token()
if not real_token:
logging.error("未在内存中找到华为云Token")
return {"error": "未在内存中找到华为云Token"}, 500
headers = {k: v for k, v in request.headers if k.lower() != 'host'}
headers['Authorization'] = f'Bearer {real_token}'
headers['Host'] = 'tokenhub.developer.huaweicloud.com'
target_url = f'https://tokenhub.developer.huaweicloud.com/v2/{subpath}'
try:
resp = requests.request(
method=request.method, url=target_url, headers=headers,
data=request.get_data(), cookies=request.cookies,
allow_redirects=False, timeout=60
)
# 兜底保障:如果华为主端提早失效返回了 401,立即强制重新扫描内存并重试一次请求
if resp.status_code == 401:
new_token = force_refresh_token()
if new_token:
headers['Authorization'] = f'Bearer {new_token}'
resp = requests.request(
method=request.method, url=target_url, headers=headers,
data=request.get_data(), cookies=request.cookies,
allow_redirects=False, timeout=60
)
return Response(resp.content, resp.status_code, resp.headers.items())
except Exception as e:
logging.error(f"网关转发失败: {traceback.format_exc()}")
return {"error": f"网关转发失败: {str(e)}"}, 500
if __name__ == '__main__':
import sys
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
app.run(host='127.0.0.1', port=port, debug=False)
EOF
# 注册网关服务
cat << EOF > /etc/systemd/system/huawei-gateway.service
[Unit]
Description=Huawei Dynamic Gateway (6H Cache)
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/bin/python3 /usr/local/bin/huawei_gateway.py $GATEWAY_PORT
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable huawei-gateway --now &>/dev/null
# ================= 追加 frpc 规则 =================
if [[ "$APPEND_FRP" == "y" || "$APPEND_FRP" == "Y" ]] && [ -f "$FRPC_CONFIG" ]; then
if grep -q "huawei-dynamic-gateway" "$FRPC_CONFIG" 2>/dev/null; then
echo -e "${YELLOW}检测到 frpc 配置中已存在 huawei-dynamic-gateway 规则,跳过追加。${PLAIN}"
else
if [ "$FRPC_TYPE" = "toml" ]; then
cat << EOF >> "$FRPC_CONFIG"
[[proxies]]
name = "huawei-dynamic-gateway"
type = "tcp"
local_ip = "127.0.0.1"
local_port = $GATEWAY_PORT
remote_port = $REMOTE_PORT
EOF
else
cat << EOF >> "$FRPC_CONFIG"
[huawei-dynamic-gateway]
type = tcp
local_ip = 127.0.0.1
local_port = $GATEWAY_PORT
remote_port = $REMOTE_PORT
EOF
fi
echo -e "${GREEN}frpc 代理规则已追加到 $FRPC_CONFIG${PLAIN}"
fi
if systemctl list-units --type=service | grep -q "frpc"; then systemctl restart frpc; fi
fi
# ================= 部署总结 =================
echo -e "\n${BLUE}==================================================${PLAIN}"
echo -e "${GREEN} 🎉 6小时长效缓存网关部署完成 🎉 ${PLAIN}"
echo -e "${BLUE}==================================================${PLAIN}"
echo -e "1. 动态网关状态:$(systemctl is-active huawei-gateway)"
echo -e "2. 您的本地一劳永逸调用地址:"
echo -e " - ${GREEN}API Base URL:${PLAIN} http://【你的公网frps_IP】:$REMOTE_PORT/v2"
echo -e " - ${GREEN}API Key:${PLAIN} sk-anything"
echo -e " - ${GREEN}Model:${PLAIN} glm-5.1"
echo -e "${BLUE}==================================================${PLAIN}\n"