From 9be2cbd58e5d6d72366fdc3a45bbf23af21edbc4 Mon Sep 17 00:00:00 2001 From: Chaos Date: Thu, 2 Jul 2026 14:28:25 +0800 Subject: [PATCH] initial commit --- ai/hwaishell.sh | 288 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 ai/hwaishell.sh diff --git a/ai/hwaishell.sh b/ai/hwaishell.sh new file mode 100644 index 0000000..bdda3bb --- /dev/null +++ b/ai/hwaishell.sh @@ -0,0 +1,288 @@ +#!/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/', 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" \ No newline at end of file