From 3a72f73338684800e09b90a3119118d36aa609ef Mon Sep 17 00:00:00 2001 From: karuo Date: Sun, 22 Feb 2026 11:32:54 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20=E5=8D=A1=E8=8B=A5AI=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=202026-02-22=2011:32=20|=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=9A=E9=87=91=E4=BB=93=E3=80=81=E8=BF=90=E8=90=A5=E4=B8=AD?= =?UTF-8?q?=E6=9E=A2=E5=B7=A5=E4=BD=9C=E5=8F=B0=20|=20=E6=8E=92=E9=99=A4?= =?UTF-8?q?=20>20MB:=208=20=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../金仓_存储备份/服务器管理/SKILL.md | 1 + .../references/Node项目未启动_MODULE_NOT_FOUND修复指南.md | 1 + .../服务器管理/references/宝塔Node项目管理_SKILL.md | 13 +- .../scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py | 181 ++++++++++++++++++ 运营中枢/工作台/gitea_push_log.md | 1 + 运营中枢/工作台/代码管理.md | 1 + 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/SKILL.md b/01_卡资(金)/金仓_存储备份/服务器管理/SKILL.md index 26710c52..8f94594c 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/SKILL.md +++ b/01_卡资(金)/金仓_存储备份/服务器管理/SKILL.md @@ -376,6 +376,7 @@ ss -tlnp | grep :端口号 | 脚本 | 功能 | 位置 | |------|------|------| +| `腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py` | word/ai_hair/is_phone 日志诊断、MODULE_NOT_FOUND 修复、重启(宝塔 API) | `./scripts/` | | `kr宝塔_node项目批量修复.py` | 批量启动 kr宝塔 Node 项目(服务器内执行,宝塔 API) | `./scripts/` | | `kr宝塔_宝塔API_修复502.py` | 修复 502(重启 Nginx + soul 相关 Node) | `./scripts/` | | `快速检查服务器.py` | 一键检查所有服务器状态 | `./脚本/` | diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/references/Node项目未启动_MODULE_NOT_FOUND修复指南.md b/01_卡资(金)/金仓_存储备份/服务器管理/references/Node项目未启动_MODULE_NOT_FOUND修复指南.md index 10b7242c..60c0d6e0 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/references/Node项目未启动_MODULE_NOT_FOUND修复指南.md +++ b/01_卡资(金)/金仓_存储备份/服务器管理/references/Node项目未启动_MODULE_NOT_FOUND修复指南.md @@ -31,6 +31,7 @@ Error: Cannot find module '/www/wwwroot/自营/wzdj' | **tongzhi** | /www/wwwroot/自营/玩值/tongzhi | `cd /www/wwwroot/自营/玩值/tongzhi && node server.js` 或 `npm run start` | 同上 | | **is_phone** | /www/wwwroot/自营/kr/kr-phone | `cd /www/wwwroot/自营/kr/kr-phone && node server.js` 或 `npm run start` | 同上 | | **ai_hair** | /www/wwwroot/客户/ai_hair | 同上 | 同上 | +| **word** | /www/wwwroot/自营/word 或 扩展/word | `cd 项目根目录 && npm run start` | Next.js,按实际路径 | | **AITOUFA** | /www/wwwroot/扩展/小工具/AITOUFA | `cd /www/wwwroot/扩展/小工具/AITOUFA && npm run start` | 参考 Skill §4.6 | | **zhiji** | /www/wwwroot/... | 同上 | 按实际结构 | | **ymao** | /www/wwwroot/扩展/ymao | 同上 | 同上 | diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/references/宝塔Node项目管理_SKILL.md b/01_卡资(金)/金仓_存储备份/服务器管理/references/宝塔Node项目管理_SKILL.md index 1dca9c0c..c814dcab 100644 --- a/01_卡资(金)/金仓_存储备份/服务器管理/references/宝塔Node项目管理_SKILL.md +++ b/01_卡资(金)/金仓_存储备份/服务器管理/references/宝塔Node项目管理_SKILL.md @@ -112,7 +112,17 @@ python3 "01_卡资(金)/金仓_存储备份/服务器管理/scripts/kr宝塔 **前置**:本机公网 IP 已加入 kr宝塔 **设置 → API 接口** 白名单。否则报「IP校验失败」。 -### 3.3 502 修复(kr宝塔) +### 3.3 word/ai_hair/is_phone 诊断修复(宝塔 API + TAT) + +**脚本**:`scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py` + +**执行**:通过 TAT 在服务器内调用 127.0.0.1 宝塔 API,获取项目列表与路径,查看启动日志,遇 MODULE_NOT_FOUND 则 pnpm install,最后 restart_project。 + +```bash +./scripts/.venv_tx/bin/python scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py +``` + +### 3.4 502 修复(kr宝塔) **脚本**:`scripts/kr宝塔_宝塔API_修复502.py` @@ -203,6 +213,7 @@ pm2 kill | 脚本 | 功能 | 执行位置 | |------|------|----------| | `scripts/kr宝塔_node项目批量修复.py` | 批量 stop→清端口→start Node 项目 | 服务器内 | +| `scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py` | word/ai_hair/is_phone 日志+MODULE_NOT_FOUND+restart(宝塔 API) | 本机(TAT) | | `scripts/kr宝塔_宝塔API_修复502.py` | 重启 Nginx + soul 相关 Node 项目 | 本机(API) | | `脚本/快速检查服务器.py` | 检查多台服务器状态 | 本机(API) | | `scripts/kr宝塔_腾讯云带宽与CPU近24h.py` | 腾讯云监控数据 | 本机 | diff --git a/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py new file mode 100644 index 00000000..0da84053 --- /dev/null +++ b/01_卡资(金)/金仓_存储备份/服务器管理/scripts/腾讯云_TAT_word_ai_hair_is_phone_诊断修复.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +腾讯云 TAT:在 kr宝塔 上对 word、ai_hair、is_phone 执行: +1. 通过宝塔 API get_project_list 获取项目配置与路径 +2. 查看启动日志(cat 常见日志路径) +3. 如发现 MODULE_NOT_FOUND,在项目目录执行 pnpm install(或 npm install) +4. 通过宝塔 API restart_project 重启 + +全程使用宝塔 API(127.0.0.1)进行操作,凭证见 00_账号与API索引.md +""" +import base64 +import os +import re +import sys +import time + +KR_INSTANCE_ID = "ins-aw0tnqjo" +REGION = "ap-guangzhou" +TARGET_NAMES = ["word", "ai_hair", "is_phone"] + +# 已知项目路径(API 无 path 时的后备) +PATH_MAP = { + "word": "/www/wwwroot/自营/word", + "ai_hair": "/www/wwwroot/客户/ai_hair", + "is_phone": "/www/wwwroot/自营/kr/kr-phone", +} + +SHELL_SCRIPT = r'''#!/bin/bash +set -e +echo "=== kr宝塔 word/ai_hair/is_phone 诊断修复(宝塔 API)===" +python3 - << 'PYEOF' +import hashlib, json, os, subprocess, time, urllib.request, urllib.parse, ssl +ssl._create_default_https_context = ssl._create_unverified_context +PANEL, K = "https://127.0.0.1:9988", "qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT" +PATH_MAP = {"word": "/www/wwwroot/自营/word", "ai_hair": "/www/wwwroot/客户/ai_hair", "is_phone": "/www/wwwroot/自营/kr/kr-phone"} +def sign(): + t = int(time.time()) + s = str(t) + hashlib.md5(K.encode()).hexdigest() + return {"request_time": t, "request_token": hashlib.md5(s.encode()).hexdigest()} +def post(p, d=None): + pl = sign() + if d: pl.update(d) + r = urllib.request.Request(PANEL + p, data=urllib.parse.urlencode(pl).encode()) + with urllib.request.urlopen(r, timeout=25) as resp: + return json.loads(resp.read().decode()) + +items = post("/project/nodejs/get_project_list").get("data") or post("/project/nodejs/get_project_list").get("list") or [] +by_name = {str(it.get("name","")).lower(): it for it in items} + +for nm in ["word", "ai_hair", "is_phone"]: + print("\n--- %s ---" % nm) + it = by_name.get(nm) or by_name.get(nm.replace("_","")) + if not it: + print(" 未找到项目,跳过") + continue + cfg = it.get("project_config") or {} + if isinstance(cfg, str): + try: cfg = json.loads(cfg) + except: cfg = {} + path = (it.get("path") or it.get("project_path") or cfg.get("path") or + cfg.get("project_path") or cfg.get("projectDir") or PATH_MAP.get(nm)) + if not path or not os.path.isdir(path): + path = PATH_MAP.get(nm) + print(" 路径:", path) + # 尝试查看日志 + log_paths = [ + "/www/server/nodejs/vhost/log/%s.log" % it.get("name", nm), + "/www/server/nodejs/vhost/logs/%s.log" % it.get("name", nm), + os.path.join(path or "", "logs", "out.log"), + os.path.join(path or "", "log", "out.log"), + ] + log_content = "" + for lp in log_paths: + try: + with open(lp, "r", encoding="utf-8", errors="ignore") as f: + log_content = f.read()[-4000:] + print(" 日志(%s) 尾 200 字符:" % lp) + print(" ", repr(log_content[-200:])) + break + except: pass + has_mod = "MODULE_NOT_FOUND" in log_content or "Cannot find module" in log_content + if has_mod and path and os.path.isdir(path): + print(" 检测到 MODULE_NOT_FOUND,执行 pnpm install...") + try: + subprocess.check_output("cd '%s' && (pnpm install 2>/dev/null || npm install 2>/dev/null || true)" % path, shell=True, timeout=120) + print(" 依赖安装完成") + except Exception as e: + print(" 依赖安装异常:", str(e)[:100]) + # 通过 API 重启 + pname = it.get("name") or it.get("project_name") or nm + try: + post("/project/nodejs/stop_project", {"project_name": pname}) + time.sleep(1) + r = post("/project/nodejs/start_project", {"project_name": pname}) + ok = r.get("status") is True or "成功" in str(r.get("msg","")) + print(" 重启:", "OK" if ok else "FAIL", r.get("msg","")[:80]) + except Exception as e: + print(" 重启异常:", str(e)[:100]) + time.sleep(2) + +print("\n=== 完成 ===") +PYEOF +''' + +def _read_creds(): + d = os.path.dirname(os.path.abspath(__file__)) + for _ in range(6): + root = d + if os.path.isfile(os.path.join(root, "运营中枢", "工作台", "00_账号与API索引.md")): + path = os.path.join(root, "运营中枢", "工作台", "00_账号与API索引.md") + with open(path, "r", encoding="utf-8") as f: + text = f.read() + sid = skey = None + in_tx = False + for line in text.splitlines(): + if "### 腾讯云" in line: + in_tx = True + continue + if in_tx and line.strip().startswith("###"): + break + if not in_tx: + continue + m = re.search(r"\|\s*[^|]*(?:SecretId|密钥)[^|]*\|\s*`([^`]+)`", line, re.I) + if m and m.group(1).strip().startswith("AKID"): + sid = m.group(1).strip() + m = re.search(r"\|\s*SecretKey\s*\|\s*`([^`]+)`", line, re.I) + if m: + skey = m.group(1).strip() + return sid or None, skey or None + d = os.path.dirname(d) + return None, None + + +def main(): + sid = os.environ.get("TENCENTCLOUD_SECRET_ID") + skey = os.environ.get("TENCENTCLOUD_SECRET_KEY") + if not sid or not skey: + sid, skey = _read_creds() + if not sid or not skey: + print("❌ 未配置腾讯云 SecretId/SecretKey") + return 1 + try: + from tencentcloud.common import credential + from tencentcloud.tat.v20201028 import tat_client, models + except ImportError: + print("pip install tencentcloud-sdk-python-tat") + return 1 + + cred = credential.Credential(sid, skey) + client = tat_client.TatClient(cred, REGION) + req = models.RunCommandRequest() + req.Content = base64.b64encode(SHELL_SCRIPT.encode()).decode() + req.InstanceIds = [KR_INSTANCE_ID] + req.CommandType = "SHELL" + req.Timeout = 180 + req.CommandName = "WordAiHairIsPhone_DiagFix" + resp = client.RunCommand(req) + print("✅ TAT 已下发 InvocationId:", resp.InvocationId) + print(" 目标项目: word, ai_hair, is_phone") + print(" 等待 90s...") + time.sleep(90) + try: + req2 = models.DescribeInvocationTasksRequest() + f = models.Filter() + f.Name = "invocation-id" + f.Values = [resp.InvocationId] + req2.Filters = [f] + r2 = client.DescribeInvocationTasks(req2) + for t in (r2.InvocationTaskSet or []): + print(" 状态:", getattr(t, "TaskStatus", "")) + out = getattr(t, "Output", None) or "" + if out: + print(" 输出:\n", out[:3500]) + except Exception as e: + print(" 查询:", e) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index 0b27c697..68699c60 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -80,3 +80,4 @@ | 2026-02-22 10:56:22 | 🔄 卡若AI 同步 2026-02-22 10:56 | 更新:卡土、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-22 10:57:44 | 🔄 卡若AI 同步 2026-02-22 10:57 | 更新:卡土、总索引与入口、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-22 11:00:29 | 🔄 卡若AI 同步 2026-02-22 11:00 | 更新:卡土、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 8 个 | +| 2026-02-22 11:07:02 | 🔄 卡若AI 同步 2026-02-22 11:07 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 8 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index acc0ea32..3c66680c 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -83,3 +83,4 @@ | 2026-02-22 10:56:22 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 10:56 | 更新:卡土、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-22 10:57:44 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 10:57 | 更新:卡土、总索引与入口、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-22 11:00:29 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 11:00 | 更新:卡土、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-02-22 11:07:02 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 11:07 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |