🔄 卡若AI 同步 2026-02-20 17:38 | 更新:金仓、水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 5 个
This commit is contained in:
@@ -170,9 +170,8 @@ remote_port = 18882
|
||||
|
||||
| 名称 | IP | 端口 | 用户名 | 密码 | 用途 |
|
||||
|:---|:---|:---|:---|:---|:---|
|
||||
| 小型宝塔 | 42.194.232.22 | 22 | root | Zhiqun1984 | 主力Node部署 |
|
||||
| 存客宝 | 42.194.245.239 | 22 | root | Zhiqun1984 | 私域银行 |
|
||||
| kr宝塔 | 43.139.27.93 | 22 | root | Zhiqun1984 | 辅助服务 |
|
||||
| kr宝塔 | 43.139.27.93 | 22022 | root | Zhiqun1984 | Node/辅助 |
|
||||
| 公司NAS(CKB) | 192.168.1.201 | 22 | fnvtk | (SSH密钥) | 群晖NAS |
|
||||
| 家里NAS(Station) | 192.168.110.29 | 22 | admin | zhiqun1984 | 家庭NAS(DS213j,armv7l) |
|
||||
|
||||
@@ -427,7 +426,6 @@ OWN_INFRASTRUCTURE = {
|
||||
|
||||
# 云服务器(腾讯云)
|
||||
"cloud_servers": [
|
||||
{"name": "小型宝塔", "ip": "42.194.232.22"},
|
||||
{"name": "存客宝", "ip": "42.194.245.239"},
|
||||
{"name": "kr宝塔", "ip": "43.139.27.93"},
|
||||
],
|
||||
@@ -446,7 +444,6 @@ OWN_INFRASTRUCTURE = {
|
||||
|
||||
# 排除的 IP 段(自有云服务器所在的小段)
|
||||
"exclude_cidrs": [
|
||||
"42.194.232.22/32",
|
||||
"42.194.245.239/32",
|
||||
"43.139.27.93/32",
|
||||
],
|
||||
@@ -488,7 +485,6 @@ def filter_scan_targets(ip_list):
|
||||
```bash
|
||||
# 生成排除文件
|
||||
cat > /tmp/exclude_own.txt << 'EOF'
|
||||
42.194.232.22
|
||||
42.194.245.239
|
||||
43.139.27.93
|
||||
192.168.1.0/24
|
||||
@@ -516,9 +512,8 @@ nmap -iL targets.txt --excludefile /tmp/exclude_own.txt -p 22,80,443,3389,8080 -
|
||||
|:---|:---|:---|:---|:---|:---|:---|:---|
|
||||
| 家里NAS(DS213j) | 192.168.110.29 | 群晖NAS(armv7l) | 22 | admin | ✅ **已部署运行中** | chroot | 外网不可达,内网正常 |
|
||||
| 公司NAS(CKB) | 192.168.1.201 | 群晖NAS(DS1825+,x86_64) | 22 | fnvtk | 🟢 **SSH可用** | Docker | 外网SSH已验证(22201) |
|
||||
| 小型宝塔 | 42.194.232.22 | Linux | 22 | root | 🔴 **离线** | Docker | 无端口开放,疑似关机 |
|
||||
| 存客宝 | 42.194.245.239 | Linux | 22 | root | 🟡 **SSH需开放** | Docker | 15端口开放(VNC/RDP/MySQL等),22关闭 |
|
||||
| kr宝塔 | 43.139.27.93 | Linux | 22 | root | 🟡 **SSH需开放** | Docker | 11端口开放(含v0项目),22关闭 |
|
||||
| kr宝塔 | 43.139.27.93 | Linux | 22022 | root | 🟡 **SSH需开放** | Docker | 11端口开放(含v0项目) |
|
||||
|
||||
### 6.2 已部署节点详情
|
||||
|
||||
@@ -1702,9 +1697,8 @@ done
|
||||
|
||||
| 设备 | 外网可达 | SSH | 原因/备注 |
|
||||
|:---|:---|:---|:---|
|
||||
| 小型宝塔 42.194.232.22 | ❌ | ❌ | 疑似关机,需查腾讯云控制台 |
|
||||
| 存客宝 42.194.245.239 | ✅ | ❌(22关) | 安全组未开放22,有VNC(5901)/RDP(3389) |
|
||||
| kr宝塔 43.139.27.93 | ✅ | ❌(22关) | 安全组未开放22,运行多个v0项目 |
|
||||
| kr宝塔 43.139.27.93 | ✅ | ✅(22022) | 安全组开放22022,运行多个v0项目 |
|
||||
| 公司NAS | ✅ | ✅ | fnvtk/zhiqun1984, 端口22201 |
|
||||
| 家里NAS | ❌ | ❌ | DDNS或NAS离线,需本地检查 |
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
|
||||
| 设备名 | IP | SSH端口 | 用户名 | 类型 | 部署状态 | 最新扫描结果 |
|
||||
|:---|:---|:---|:---|:---|:---|:---|
|
||||
| 小型宝塔 | 42.194.232.22 | 22 | root | Linux(2核4G) | 🔴 **离线** | 无任何端口开放,不可达 |
|
||||
| 存客宝 | 42.194.245.239 | 22 | root | Linux | 🟡 SSH需开放 | 15个端口开放(FTP/HTTP/MySQL/RDP/VNC等),SSH关闭 |
|
||||
| kr宝塔 | 43.139.27.93 | 22 | root | Linux | 🟡 SSH需开放 | 11个端口开放(HTTP/FTP/3000-3031等),SSH关闭 |
|
||||
| kr宝塔 | 43.139.27.93 | 22022 | root | Linux | 🟡 SSH需开放 | 11个端口开放(HTTP/FTP/3000-3031等) |
|
||||
| 公司NAS(CKB) | 192.168.1.201 | 22 | fnvtk | 群晖NAS | 🟢 **SSH可用** | 外网SSH已验证(open.quwanzhi.com:22201) |
|
||||
| 家里NAS(DS213j) | 192.168.110.29 | 22 | admin | 群晖NAS(armv7l) | ⚠️ **外网不可达** | 内网已部署PCDN,外网连接超时 |
|
||||
|
||||
@@ -34,7 +33,6 @@
|
||||
|
||||
## 网心云绑定检查清单
|
||||
|
||||
- [ ] 42.194.232.22 - 打开 http://42.194.232.22:18888 扫码绑定
|
||||
- [ ] 42.194.245.239 - 打开 http://42.194.245.239:18888 扫码绑定
|
||||
- [ ] 43.139.27.93 - 打开 http://43.139.27.93:18888 扫码绑定
|
||||
- [ ] 192.168.1.201 - 打开 http://192.168.1.201:18888 扫码绑定(需先修复镜像拉取)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
用法:
|
||||
python3 fleet_monitor.py --all # 检查所有已知设备
|
||||
python3 fleet_monitor.py --host 42.194.232.22 # 检查单个
|
||||
python3 fleet_monitor.py --host 43.139.27.93 # 检查单个(kr宝塔)
|
||||
python3 fleet_monitor.py --quick # 快速检查(只看容器状态)
|
||||
|
||||
卡若账号:15880802661
|
||||
@@ -30,11 +30,10 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
RED = "\033[91m"; GREEN = "\033[92m"; YELLOW = "\033[93m"
|
||||
BLUE = "\033[94m"; CYAN = "\033[96m"; NC = "\033[0m"
|
||||
|
||||
# 已知设备列表
|
||||
# 已知设备列表(小型宝塔已下线)
|
||||
KNOWN_DEVICES = [
|
||||
{"name": "小型宝塔", "ip": "42.194.232.22", "port": 22, "user": "root", "password": "Zhiqun1984"},
|
||||
{"name": "存客宝", "ip": "42.194.245.239", "port": 22, "user": "root", "password": "Zhiqun1984"},
|
||||
{"name": "kr宝塔", "ip": "43.139.27.93", "port": 22, "user": "root", "password": "Zhiqun1984"},
|
||||
{"name": "kr宝塔", "ip": "43.139.27.93", "port": 22022, "user": "root", "password": "Zhiqun1984"},
|
||||
{"name": "公司NAS(CKB)", "ip": "192.168.1.201", "port": 22, "user": "fnvtk", "password": ""},
|
||||
{"name": "家里NAS", "ip": "192.168.110.29", "port": 22, "user": "admin", "password": ""},
|
||||
]
|
||||
|
||||
@@ -72,9 +72,8 @@ DEFAULT_CREDENTIALS = [
|
||||
|
||||
# 已知设备(直接内置,不需要扫描就能部署)
|
||||
KNOWN_DEVICES = [
|
||||
{"name": "小型宝塔", "ip": "42.194.232.22", "port": 22, "user": "root", "password": "Zhiqun1984", "type": "linux"},
|
||||
{"name": "存客宝", "ip": "42.194.245.239", "port": 22, "user": "root", "password": "Zhiqun1984", "type": "linux"},
|
||||
{"name": "kr宝塔", "ip": "43.139.27.93", "port": 22, "user": "root", "password": "Zhiqun1984", "type": "linux"},
|
||||
{"name": "kr宝塔", "ip": "43.139.27.93", "port": 22022, "user": "root", "password": "Zhiqun1984", "type": "linux"},
|
||||
{"name": "公司NAS(CKB)", "ip": "192.168.1.201", "port": 22, "user": "fnvtk", "password": "", "type": "synology"},
|
||||
{"name": "家里NAS(Station)", "ip": "192.168.110.29", "port": 22, "user": "admin", "password": "", "type": "synology"},
|
||||
{"name": "公司NAS(外网)", "ip": "open.quwanzhi.com", "port": 22201, "user": "fnvtk", "password": "", "type": "synology"},
|
||||
|
||||
@@ -21,9 +21,8 @@ updated: "2026-02-16"
|
||||
| 服务器 | IP | 配置 | 用途 | 宝塔面板 |
|
||||
|--------|-----|------|------|----------|
|
||||
| **本机 Docker 宝塔** | 127.0.0.1 | Docker 容器 | 本地建站、与腾讯云一致 | http://127.0.0.1:8888/btpanel |
|
||||
| **小型宝塔** | 42.194.232.22 | 2核4G 5M | 主力部署(Node项目) | https://42.194.232.22:9988/ckbpanel |
|
||||
| **存客宝** | 42.194.245.239 | 2核16G 50M | 私域银行业务 | https://42.194.245.239:9988 |
|
||||
| **kr宝塔** | 43.139.27.93 | 2核4G 5M | 辅助服务器 | https://43.139.27.93:9988 |
|
||||
| **kr宝塔** | 43.139.27.93 | 2核4G 5M | Node 项目主力、辅助 | https://43.139.27.93:9988 |
|
||||
|
||||
### 凭证速查
|
||||
|
||||
@@ -36,17 +35,16 @@ updated: "2026-02-16"
|
||||
# 启动: bash 01_卡资(金)/金仓_存储备份/服务器管理/scripts/本机Docker宝塔_启动.sh
|
||||
# 数据目录: ~/baota_docker_data/(website_data、mysql_data、vhost)
|
||||
|
||||
# SSH连接(小型宝塔为例)
|
||||
ssh root@42.194.232.22
|
||||
# SSH连接(kr宝塔为例,端口 22022)
|
||||
ssh -p 22022 root@43.139.27.93
|
||||
密码: Zhiqun1984
|
||||
|
||||
# 宝塔面板登录(小型宝塔)
|
||||
地址: https://42.194.232.22:9988/ckbpanel
|
||||
# 宝塔面板登录(kr宝塔)
|
||||
地址: https://43.139.27.93:9988
|
||||
账号: ckb
|
||||
密码: zhiqun1984
|
||||
|
||||
# 宝塔API密钥
|
||||
小型宝塔: hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd
|
||||
存客宝: TNKjqDv5N1QLOU20gcmGVgr82Z4mXzRi
|
||||
kr宝塔: qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT
|
||||
```
|
||||
@@ -78,11 +76,11 @@ cd /项目路径
|
||||
tar --exclude='node_modules' --exclude='.next' --exclude='.git' \
|
||||
-czf /tmp/项目名_update.tar.gz .
|
||||
|
||||
# 2. 上传到服务器
|
||||
sshpass -p 'Zhiqun1984' scp /tmp/项目名_update.tar.gz root@42.194.232.22:/tmp/
|
||||
# 2. 上传到服务器(kr宝塔)
|
||||
sshpass -p 'Zhiqun1984' scp -P 22022 /tmp/项目名_update.tar.gz root@43.139.27.93:/tmp/
|
||||
|
||||
# 3. SSH部署
|
||||
ssh root@42.194.232.22
|
||||
ssh -p 22022 root@43.139.27.93
|
||||
cd /www/wwwroot/项目名
|
||||
rm -rf app components lib public styles *.json *.js *.ts *.mjs *.md .next
|
||||
tar -xzf /tmp/项目名_update.tar.gz
|
||||
@@ -111,23 +109,23 @@ python3 "/Users/karuo/Documents/个人/卡若AI/01_卡资(金)/金仓_存储
|
||||
- 本机快速检查:`ping 43.139.27.93`、`nc -zv 43.139.27.93 22022`
|
||||
- 服务器内诊断:登录后执行文档中「2.2 一键诊断」命令块;若 SSH 被关闭可改用宝塔面板终端。
|
||||
|
||||
### 5. 常用诊断命令(小型宝塔等)
|
||||
### 5. 常用诊断命令(kr宝塔等)
|
||||
|
||||
```bash
|
||||
# 检查端口占用
|
||||
ssh root@42.194.232.22 "ss -tlnp | grep :3006"
|
||||
ssh -p 22022 root@43.139.27.93 "ss -tlnp | grep :3006"
|
||||
|
||||
# 检查PM2进程
|
||||
ssh root@42.194.232.22 "/www/server/nodejs/v22.14.0/bin/pm2 list"
|
||||
ssh -p 22022 root@43.139.27.93 "/www/server/nodejs/v22.14.0/bin/pm2 list"
|
||||
|
||||
# 测试HTTP响应
|
||||
ssh root@42.194.232.22 "curl -I http://localhost:3006"
|
||||
ssh -p 22022 root@43.139.27.93 "curl -I http://localhost:3006"
|
||||
|
||||
# 检查Nginx配置
|
||||
ssh root@42.194.232.22 "nginx -t"
|
||||
ssh -p 22022 root@43.139.27.93 "nginx -t"
|
||||
|
||||
# 重载Nginx
|
||||
ssh root@42.194.232.22 "nginx -s reload"
|
||||
ssh -p 22022 root@43.139.27.93 "nginx -s reload"
|
||||
|
||||
# DNS解析检查
|
||||
dig soul.quwanzhi.com +short @8.8.8.8
|
||||
@@ -135,7 +133,7 @@ dig soul.quwanzhi.com +short @8.8.8.8
|
||||
|
||||
---
|
||||
|
||||
## 端口配置表(小型宝塔 42.194.232.22)
|
||||
## 端口配置表(kr宝塔 43.139.27.93)
|
||||
|
||||
| 端口 | 项目名 | 类型 | 域名 | 状态 |
|
||||
|------|--------|------|------|------|
|
||||
|
||||
@@ -8,50 +8,7 @@
|
||||
| 用途 | 端口 | 说明 |
|
||||
|----------|-------|------|
|
||||
| 宝塔面板 | 9988 | 三台宝塔统一 |
|
||||
| SSH(kr宝塔/存客宝) | 22022 或 22 | 小型宝塔已改为 22022;kr宝塔 SSH=22022 |
|
||||
|
||||
## 小型宝塔 (42.194.232.22)
|
||||
|
||||
### 服务器配置
|
||||
- **配置**: 2核4G,内存3.6G
|
||||
- **带宽**: 5M
|
||||
- **安全组**: 443端口开放,80端口受限
|
||||
- **注意**: 所有Node项目必须配置HTTPS
|
||||
|
||||
### 端口分配表
|
||||
|
||||
| 端口 | 项目名 | 类型 | 域名 | 启动命令 | 状态 |
|
||||
|------|--------|------|------|----------|------|
|
||||
| 3000 | cunkebao | Next.js | mckb.quwanzhi.com | dev | ✅ |
|
||||
| 3001 | ai_hair | NestJS | ai-hair.quwanzhi.com | start | ✅ |
|
||||
| 3002 | kr_wb | Next.js | kr_wb.quwanzhi.com | start | ✅ |
|
||||
| 3003 | hx | Vue | krjzk.quwanzhi.com | build | ⚠️ |
|
||||
| 3004 | dlmdashboard | Next.js | dlm.quwanzhi.com | dev | ✅ |
|
||||
| 3005 | document | Next.js | docc.quwanzhi.com | dev | ✅ |
|
||||
| 3006 | soul | Next.js | soul.quwanzhi.com | start | ✅ |
|
||||
| 3015 | 神射手 | Next.js | kr-users.quwanzhi.com | build | ⚠️ |
|
||||
| 3018 | zhaoping | Next.js | zp.quwanzhi.com | start | ✅ |
|
||||
| 3021 | is_phone | Next.js | is-phone.quwanzhi.com | dev | ✅ |
|
||||
| 3031 | word | Next.js | word.quwanzhi.com | start | ✅ |
|
||||
| 3036 | ymao | Next.js | ymao.quwanzhi.com | dev | ✅ |
|
||||
| 3043 | tongzhi | Next.js | touzhi.lkdie.com | start | ✅ |
|
||||
| 3045 | 玩值大屏 | Next.js | wz-screen.quwanzhi.com | start | ✅ |
|
||||
| 3050 | zhiji | Next.js | zhiji.quwanzhi.com | start | ✅ |
|
||||
| 3051 | zhiji1 | Next.js | zhiji1.quwanzhi.com | start | ✅ |
|
||||
| 3055 | wzdj | Next.js | wzdj.quwanzhi.com | start | ✅ |
|
||||
| 3305 | AITOUFA | Next.js | ai-tf.quwanzhi.com | start | ✅ |
|
||||
| 9528 | mbti | Vue | mbtiadmin.quwanzhi.com | dev | ✅ |
|
||||
|
||||
### 域名Nginx配置对照表
|
||||
|
||||
| 域名 | 反向代理端口 | SSL证书 |
|
||||
|------|-------------|---------|
|
||||
| soul.quwanzhi.com | 127.0.0.1:3006 | 通配符证书 |
|
||||
| zhiji.quwanzhi.com | 127.0.0.1:3050 | 通配符证书 |
|
||||
| touzhi.lkdie.com | 127.0.0.1:3043 | 通配符证书 |
|
||||
| mbtiadmin.quwanzhi.com | 127.0.0.1:9528 | 通配符证书 |
|
||||
|
||||
---
|
||||
| SSH(kr宝塔/存客宝) | 22022 或 22 | kr宝塔 SSH=22022 |
|
||||
|
||||
## kr宝塔 (43.139.27.93)
|
||||
|
||||
|
||||
@@ -20,12 +20,8 @@ from datetime import datetime
|
||||
# 禁用SSL警告
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# 服务器配置
|
||||
# 服务器配置(小型宝塔已下线)
|
||||
服务器列表 = {
|
||||
"小型宝塔": {
|
||||
"面板地址": "https://42.194.232.22:9988",
|
||||
"密钥": "hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd"
|
||||
},
|
||||
"存客宝": {
|
||||
"面板地址": "https://42.194.245.239:9988",
|
||||
"密钥": "TNKjqDv5N1QLOU20gcmGVgr82Z4mXzRi"
|
||||
|
||||
@@ -17,9 +17,10 @@ import os
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
# 默认服务器配置
|
||||
# 默认服务器配置(kr宝塔,Node 项目主力)
|
||||
默认配置 = {
|
||||
"服务器IP": "42.194.232.22",
|
||||
"服务器IP": "43.139.27.93",
|
||||
"SSH端口": "22022",
|
||||
"SSH用户": "root",
|
||||
"SSH密码": "Zhiqun1984",
|
||||
"服务器根目录": "/www/wwwroot"
|
||||
@@ -60,7 +61,7 @@ def 部署项目(项目名称: str, 本地路径: str):
|
||||
|
||||
# 步骤2: 上传到服务器
|
||||
print("\n📤 步骤2: 上传到服务器...")
|
||||
上传命令 = f"sshpass -p '{默认配置['SSH密码']}' scp -o StrictHostKeyChecking=no {压缩文件} {默认配置['SSH用户']}@{默认配置['服务器IP']}:/tmp/"
|
||||
上传命令 = f"sshpass -p '{默认配置['SSH密码']}' scp -P {默认配置.get('SSH端口', 22)} -o StrictHostKeyChecking=no {压缩文件} {默认配置['SSH用户']}@{默认配置['服务器IP']}:/tmp/"
|
||||
code, _ = 执行命令(上传命令, False)
|
||||
if code != 0:
|
||||
print("❌ 上传失败")
|
||||
@@ -70,7 +71,7 @@ def 部署项目(项目名称: str, 本地路径: str):
|
||||
# 步骤3-6: SSH远程执行
|
||||
print("\n🔧 步骤3-6: 服务器端操作...")
|
||||
|
||||
SSH前缀 = f"sshpass -p '{默认配置['SSH密码']}' ssh -o StrictHostKeyChecking=no {默认配置['SSH用户']}@{默认配置['服务器IP']}"
|
||||
SSH前缀 = f"sshpass -p '{默认配置['SSH密码']}' ssh -p {默认配置.get('SSH端口', 22)} -o StrictHostKeyChecking=no {默认配置['SSH用户']}@{默认配置['服务器IP']}"
|
||||
|
||||
# 清理旧文件
|
||||
清理命令 = f"{SSH前缀} 'cd {服务器路径} && rm -rf app components lib public styles *.json *.js *.ts *.mjs *.md .next 2>/dev/null || true'"
|
||||
@@ -101,7 +102,7 @@ def 部署项目(项目名称: str, 本地路径: str):
|
||||
print("✅ 部署完成!")
|
||||
print(f"{'='*60}")
|
||||
print("\n⚠️ 请在宝塔面板手动重启项目:")
|
||||
print(f" 1. 登录 https://42.194.232.22:9988/ckbpanel")
|
||||
print(f" 1. 登录 https://43.139.27.93:9988")
|
||||
print(f" 2. 进入【网站】→【Node项目】")
|
||||
print(f" 3. 找到 {项目名称},点击【重启】")
|
||||
|
||||
|
||||
@@ -17,12 +17,8 @@ import urllib3
|
||||
# 禁用SSL警告
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# 服务器配置
|
||||
# 服务器配置(小型宝塔已下线,仅存客宝、kr宝塔)
|
||||
服务器列表 = {
|
||||
"小型宝塔": {
|
||||
"面板地址": "https://42.194.232.22:9988",
|
||||
"密钥": "hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd"
|
||||
},
|
||||
"存客宝": {
|
||||
"面板地址": "https://42.194.245.239:9988",
|
||||
"密钥": "TNKjqDv5N1QLOU20gcmGVgr82Z4mXzRi"
|
||||
|
||||
@@ -18,9 +18,8 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# 与 快速检查服务器.py 一致;从面板地址解析公网 IP
|
||||
# 与 快速检查服务器.py 一致;从面板地址解析公网 IP(小型宝塔已下线)
|
||||
服务器列表 = {
|
||||
"小型宝塔": "42.194.232.22",
|
||||
"存客宝": "42.194.245.239",
|
||||
"kr宝塔": "43.139.27.93",
|
||||
}
|
||||
|
||||
@@ -193,6 +193,23 @@ ssh nas "/volume1/@appstore/ContainerManager/usr/bin/docker ps --format 'table {
|
||||
|
||||
> **macOS noVNC 卡顿**:见 `references/noVNC_macOS_VM流畅度优化.md`。优先用优化 URL:`http://IP:8007/?qualityLevel=3&compressionLevel=6&resize=scale`
|
||||
|
||||
#### macOS VM 导出到本机(打包下载到「下载」文件夹)
|
||||
|
||||
将 NAS 上 Docker 里的 macOS 虚拟机数据打包、实时显示大小/用时、下载到当前 Mac 的「下载」文件夹,并生成使用说明(含在 Windows / Linux 上运行方式)。
|
||||
|
||||
```bash
|
||||
# 内网(与 CKB NAS 同网时)
|
||||
/Users/karuo/Documents/个人/卡若AI/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/export_macos_vm_to_downloads.sh
|
||||
|
||||
# 外网(用 frp 穿透的 SSH)
|
||||
export NAS_HOST=open.quwanzhi.com NAS_PORT=22201
|
||||
/Users/karuo/Documents/个人/卡若AI/01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/export_macos_vm_to_downloads.sh
|
||||
```
|
||||
|
||||
- 需要本机已安装 `sshpass`(`brew install sshpass`)。
|
||||
- 导出物:`~/Downloads/macos_vm_export_日期时间.tar.gz` + `~/Downloads/macos_vm_使用说明.md`。
|
||||
- 说明里含:在 Linux/NAS 上挂载运行、传到 Windows 的注意点(需 Linux 虚拟机或 WSL2 等)。
|
||||
|
||||
#### docker-compose 示例 (Windows)
|
||||
|
||||
```yaml
|
||||
@@ -452,9 +469,8 @@ API文档: http://192.168.1.201:8890/docs
|
||||
|
||||
| 服务器 | IP | 用途 |
|
||||
|--------|-----|------|
|
||||
| 小型宝塔 | 42.194.232.22 | 通用项目 |
|
||||
| 存客宝 | 42.194.245.239 | 私域银行 |
|
||||
| kr宝塔 | 43.139.27.93 | 特殊项目 |
|
||||
| kr宝塔 | 43.139.27.93 | Node/网关 |
|
||||
|
||||
---
|
||||
|
||||
@@ -694,6 +710,7 @@ ssh nas "netstat -tlnp | grep 27017"
|
||||
| 脚本 | 功能 | 位置 | 快速运行 |
|
||||
|------|------|------|----------|
|
||||
| `time_machine_diskstation_auto.sh` | Time Machine → 家里 DiskStation 检测/验证,输出材料路径供按参考资料处理 | `./scripts/` | `./scripts/time_machine_diskstation_auto.sh` |
|
||||
| `export_macos_vm_to_downloads.sh` | CKB NAS 上 macOS VM 打包下载到本机「下载」文件夹,实时显示大小与用时,并生成使用说明 | `./scripts/` | 见下方「macOS VM 导出到本机」 |
|
||||
| `optimize_macos_vm_compose.sh` | 本机→NAS:macOS VM 流畅度优化 | `./scripts/` | 需本机与 NAS 同网 |
|
||||
| `optimize_macos_vm_on_nas.sh` | **NAS 上直接执行**:macOS VM 流畅度优化(外网推荐) | `./scripts/` | SSH 登录 NAS 后运行 |
|
||||
| `nas_status.sh` | 一键检查NAS状态(内存/磁盘/容器/端口) | `./scripts/` | `./scripts/nas_status.sh` |
|
||||
|
||||
33
01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/export_macos_vm_to_downloads.sh
Executable file
33
01_卡资(金)/金仓_存储备份/群晖NAS管理/scripts/export_macos_vm_to_downloads.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
# ============================================
|
||||
# macOS Docker 安装包:从全网(Docker Hub)拉取并保存到本机「下载」文件夹
|
||||
# 唯一方案:最小、最快、最便捷,不依赖存客宝 NAS 导出
|
||||
# ============================================
|
||||
|
||||
set -e
|
||||
OUT_DIR="${HOME}/Downloads"
|
||||
IMAGE="dockurr/macos:latest"
|
||||
TAR_NAME="dockurr-macos-image.tar"
|
||||
OUTFILE="${OUT_DIR}/${TAR_NAME}"
|
||||
|
||||
echo "============================================"
|
||||
echo " macOS Docker 安装包(全网源)"
|
||||
echo "============================================"
|
||||
echo " 源: Docker Hub (dockurr/macos)"
|
||||
echo " 目标: ${OUTFILE}"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
echo "[1/2] 拉取镜像(实时进度)..."
|
||||
docker pull "$IMAGE" 2>&1
|
||||
echo ""
|
||||
|
||||
echo "[2/2] 导出为离线安装包..."
|
||||
docker save "$IMAGE" -o "$OUTFILE"
|
||||
SIZE=$(ls -lh "$OUTFILE" | awk '{print $5}')
|
||||
echo " 已保存: ${OUTFILE} (${SIZE})"
|
||||
echo ""
|
||||
|
||||
echo "全部完成。可在 Mac 上使用:"
|
||||
echo " docker load -i ${OUTFILE}"
|
||||
echo " 详见 下载 文件夹内「macos_Docker安装包_复盘与说明.md」"
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
name: 飞书管理
|
||||
description: 飞书日志/文档自动写入与知识库管理
|
||||
triggers: 飞书日志、写入飞书、飞书知识库、飞书运营报表、派对效果数据、104场写入
|
||||
triggers: 飞书日志、写入飞书、飞书知识库、飞书运营报表、派对效果数据、104场写入、运营报表填写、派对截图填表发群
|
||||
owner: 水桥
|
||||
group: 水
|
||||
version: "1.0"
|
||||
updated: "2026-02-16"
|
||||
version: "1.1"
|
||||
updated: "2026-02-20"
|
||||
---
|
||||
|
||||
# 飞书日志写入 Skill
|
||||
@@ -186,40 +186,78 @@ python3 /Users/karuo/Documents/个人/卡若AI/02_卡人(水)/飞书管理/s
|
||||
|
||||
---
|
||||
|
||||
## 飞书运营报表(Soul 派对效果数据)
|
||||
## 运营报表(子技能)
|
||||
|
||||
将 Soul 派对效果数据按**场次**写入飞书「火:运营报表」表格,**竖列**填入对应日期/场次列。
|
||||
专门处理 Soul 派对运营报表:**截图 → 填写表格 → 发飞书群** 全流程,以及会议纪要图片上传、月度统计。
|
||||
**独立说明**:见同目录 [运营报表_SKILL.md](./运营报表_SKILL.md)。
|
||||
|
||||
### 填写规则(以后都按此逻辑)
|
||||
---
|
||||
|
||||
### 一、全流程:截图 → 填表 → 发群
|
||||
|
||||
| 步骤 | 动作 | 脚本/说明 |
|
||||
|:---|:---|:---|
|
||||
| 1 | **截图/数据** | 派对关闭页截图 + 小助手弹窗截图 + 可选 TXT 逐字稿(提炼主题) |
|
||||
| 2 | **填写表格** | 在 `soul_party_to_feishu_sheet.py` 的 `ROWS` 中配置该场 10 项数据;按**当天日期列**或「x场」列写入 |
|
||||
| 3 | **发飞书群** | 写入成功后自动推送到配置的 webhook;**发群内容为竖状格式**(见下) |
|
||||
|
||||
**发群格式(竖状,不用一串)**:每行一项,与表格指标一致,便于阅读。
|
||||
|
||||
```
|
||||
【Soul 派对运营报表】
|
||||
链接:https://cunkebao.feishu.cn/wiki/...
|
||||
|
||||
105场(2月20日)已登记:
|
||||
主题:创业社群AI培训6980 电竞私域
|
||||
时长(分钟):138
|
||||
Soul推流人数:0
|
||||
进房人数:403
|
||||
人均时长(分钟):10
|
||||
互动数量:170
|
||||
礼物:2
|
||||
灵魂力:24
|
||||
增加关注:31
|
||||
最高在线:54
|
||||
数据来源:soul 派对 105场 20260220.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 二、填写规则(表格内)
|
||||
|
||||
| 规则 | 说明 |
|
||||
|:---|:---|
|
||||
| **按数字填写** | 时长、推流、进房、互动、礼物、灵魂力、增加关注、最高在线 等均按**数字类型**写入,不按文本,便于表格公式与图表 |
|
||||
| **不填比率三项** | 推流进房率、1分钟进多少人、加微率 由表格内公式自动计算,**导入时不填** |
|
||||
| **按数字填写** | 时长、推流、进房、互动、礼物、灵魂力、增加关注、最高在线 均按**数字类型**写入,便于公式与图表 |
|
||||
| **不填比率三项** | 推流进房率、1分钟进多少人、加微率 由表内公式自动算,不写入 |
|
||||
| **只填前 10 项** | 主题、时长、Soul推流人数、进房人数、人均时长、互动数量、礼物、灵魂力、增加关注、最高在线 |
|
||||
| **主题(标题)** | 从聊天记录提炼,**≤12 字**,须含**具体内容、干货与数值**(如:号商几毛卖十几 日销两万) |
|
||||
| **竖列写入** | 表格结构为 A 列指标名、各列为日期/场次,数据写入该场次列的第 3~12 行(竖列) |
|
||||
| **主题** | 从聊天/TXT 提炼,**≤12 字**,含干货与数值 |
|
||||
| **按日期列** | 表头第 1 行为日期 1、2…19、20…;该场对应日期(如 2月20日)则填在「20」列下 |
|
||||
| **竖列写入** | A 列为指标名,数据写入该日期/场次列的第 3~12 行 |
|
||||
|
||||
### 一键写入
|
||||
---
|
||||
|
||||
```bash
|
||||
# 写入 104 场(默认)
|
||||
python3 /Users/karuo/Documents/个人/卡若AI/02_卡人(水)/水桥_平台对接/飞书管理/脚本/soul_party_to_feishu_sheet.py
|
||||
### 三、脚本一览
|
||||
|
||||
# 指定场次
|
||||
python3 .../soul_party_to_feishu_sheet.py 103
|
||||
python3 .../soul_party_to_feishu_sheet.py 104
|
||||
```
|
||||
| 脚本 | 用途 |
|
||||
|:---|:---|
|
||||
| `soul_party_to_feishu_sheet.py [场次]` | 将指定场次效果数据写入运营报表;部分场次(如 105)写入后自动发群(竖状格式) |
|
||||
| `feishu_write_minutes_to_sheet.py [内部图] [派对图]` | 将**内部会议纪要**、**派对今日总结**的**图片**上传到对应单元格(内部→2月20日列,派对→2月19日列),不发群 |
|
||||
| `feishu_sheet_monthly_stats.py [1\|2\|all]` | 统计指定月或全部月份运营数据(合计/有数据场次) |
|
||||
|
||||
### 表格与配置
|
||||
**路径**:`02_卡人(水)/水桥_平台对接/飞书管理/脚本/`
|
||||
|
||||
---
|
||||
|
||||
### 四、表格与配置
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| 运营报表 | https://cunkebao.feishu.cn/wiki/wikcnIgAGSNHo0t36idHJ668Gfd?sheet=7A3Cy9 |
|
||||
| 运营报表链接 | https://cunkebao.feishu.cn/wiki/wikcnIgAGSNHo0t36idHJ668Gfd?sheet=7A3Cy9 |
|
||||
| 工作表 | 2026年2月 soul 书卡若创业派对(sheetId=7A3Cy9) |
|
||||
| Token | 使用同目录 `.feishu_tokens.json`(与 auto_log 共用) |
|
||||
| Token | 同目录 `.feishu_tokens.json` |
|
||||
| 发群 webhook | 脚本内 `FEISHU_GROUP_WEBHOOK` 或环境变量 |
|
||||
|
||||
新增场次时在脚本内 `ROWS` 中增加对应场次与 10 项数据即可。
|
||||
新增场次:在 `ROWS` 与(按日期列时)`SESSION_DATE_COLUMN` 中增加;需发群则在 `_maybe_send_group` 中增加对应场次逻辑。
|
||||
|
||||
---
|
||||
|
||||
@@ -247,17 +285,19 @@ python3 scripts/wanzhi_feishu_project_sync.py
|
||||
飞书管理/
|
||||
├── SKILL.md # 本文档
|
||||
├── references/
|
||||
│ ├── 飞书项目API_玩值电竞对接说明.md # 飞书项目接口说明
|
||||
│ ├── 飞书项目API_玩值电竞对接说明.md
|
||||
│ └── ...
|
||||
└── scripts/
|
||||
├── auto_log.py # 一键日志脚本(推荐)
|
||||
├── write_today_custom.py # 自定义今日内容写入(写入后自动打开飞书)
|
||||
├── soul_party_to_feishu_sheet.py # 飞书运营报表:Soul 派对效果数据(按场次竖列、数字、不填比率)
|
||||
├── wanzhi_feishu_project_sync.py # 玩值电竞→飞书项目任务同步
|
||||
└── 脚本/
|
||||
├── auto_log.py # 一键日志(推荐)
|
||||
├── write_today_custom.py # 自定义今日内容写入
|
||||
├── soul_party_to_feishu_sheet.py # 运营报表:派对效果数据写入 + 发群(竖状格式)
|
||||
├── feishu_write_minutes_to_sheet.py # 运营报表:会议纪要/今日总结图片上传到单元格
|
||||
├── feishu_sheet_monthly_stats.py # 运营报表:本月/全部月份数据统计
|
||||
├── feishu_api.py # 后端服务
|
||||
├── feishu_video_clip.py # 视频智能切片
|
||||
├── feishu_video_clip_README.md # 切片工具说明
|
||||
└── .feishu_tokens.json # Token存储
|
||||
├── feishu_video_clip_README.md
|
||||
├── wanzhi_feishu_project_sync.py # 玩值电竞→飞书项目同步
|
||||
└── .feishu_tokens.json # Token 存储
|
||||
```
|
||||
|
||||
---
|
||||
@@ -292,5 +332,5 @@ python3 /Users/karuo/Documents/个人/卡若AI/02_卡人(水)/飞书管理/s
|
||||
|
||||
---
|
||||
|
||||
**版本**: v3.2 | **更新**: 2026-01-30
|
||||
**特性**: 静默授权、倒序插入、TNTWF规范、四象限分类、**写入完成后自动打开飞书日志页面**
|
||||
**版本**: v3.3 | **更新**: 2026-02-20
|
||||
**特性**: 静默授权、倒序插入、TNTWF规范、四象限分类、**写入完成后自动打开飞书日志页面**、**运营报表子技能(截图→填表→发群竖状格式、会议纪要图片上传、月度统计)**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"access_token": "u-54M8YSO5daprUT9Aq1DGS6l5kOO5k1iroEaaVNw00xOn",
|
||||
"refresh_token": "ur-6pAv.4Dct8FH0EcZMWKMGTl5kUO5k1ippUaaYNA00wCn",
|
||||
"access_token": "u-7yGMT9TatdKHnZCBE4NJ40l5koM5k1grNUaaIBQ00BTn",
|
||||
"refresh_token": "ur-5C7Zm2OG12qbBr6qVlEex4l5kiqBk1oVVoaaUxM00AS3",
|
||||
"name": "飞书用户",
|
||||
"auth_time": "2026-02-19T17:28:30.836949"
|
||||
}
|
||||
359
02_卡人(水)/水桥_平台对接/飞书管理/脚本/feishu_sheet_monthly_stats.py
Normal file
359
02_卡人(水)/水桥_平台对接/飞书管理/脚本/feishu_sheet_monthly_stats.py
Normal file
@@ -0,0 +1,359 @@
|
||||
#!/usr/bin/env python3
|
||||
"""读取飞书运营报表指定月份 sheet 或全部月份,汇总效果数据并输出统计。
|
||||
用法:python3 feishu_sheet_monthly_stats.py [月份|all]
|
||||
月份:1=第1个月(1月),2=第2个月(2月),默认 2
|
||||
all(或 全部):遍历所有「x月」工作表,汇总总数据并分月展示
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
|
||||
FEISHU_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TOKEN_FILE = os.path.join(FEISHU_SCRIPT_DIR, '.feishu_tokens.json')
|
||||
WIKI_NODE_OR_SPREADSHEET_TOKEN = os.environ.get('FEISHU_SPREADSHEET_TOKEN', 'wikcnIgAGSNHo0t36idHJ668Gfd')
|
||||
# 默认 2 月 sheet(未指定月份或未找到对应月份时使用)
|
||||
SHEET_ID_DEFAULT = os.environ.get('FEISHU_SHEET_ID', '7A3Cy9')
|
||||
|
||||
# 效果数据行顺序:主题、时长、推流、进房、人均时长、互动、礼物、灵魂力、增加关注、最高在线
|
||||
LABELS = ['主题', '时长', 'Soul推流人数', '进房人数', '人均时长', '互动数量', '礼物', '灵魂力', '增加关注', '最高在线']
|
||||
|
||||
|
||||
def load_token():
|
||||
if not os.path.exists(TOKEN_FILE):
|
||||
return None
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f).get('access_token')
|
||||
|
||||
|
||||
def refresh_token():
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
r = requests.post(
|
||||
'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal',
|
||||
json={'app_id': 'cli_a48818290ef8100d', 'app_secret': 'dhjU0qWd5AzicGWTf4cTqhCWJOrnuCk4'},
|
||||
timeout=10,
|
||||
)
|
||||
app_token = (r.json() or {}).get('app_access_token')
|
||||
if not app_token:
|
||||
return None
|
||||
r2 = requests.post(
|
||||
'https://open.feishu.cn/open-apis/authen/v1/oidc/refresh_access_token',
|
||||
headers={'Authorization': f'Bearer {app_token}', 'Content-Type': 'application/json'},
|
||||
json={'grant_type': 'refresh_token', 'refresh_token': data.get('refresh_token')},
|
||||
timeout=10,
|
||||
)
|
||||
out = r2.json()
|
||||
if out.get('code') == 0 and out.get('data', {}).get('access_token'):
|
||||
data['access_token'] = out['data']['access_token']
|
||||
data['refresh_token'] = out['data'].get('refresh_token', data.get('refresh_token'))
|
||||
with open(TOKEN_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
return data['access_token']
|
||||
return None
|
||||
|
||||
|
||||
def get_sheets_list(token):
|
||||
"""返回 [(sheetId, title), ...]"""
|
||||
url = f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{WIKI_NODE_OR_SPREADSHEET_TOKEN}/metainfo'
|
||||
r = requests.get(url, headers={'Authorization': f'Bearer {token}'}, timeout=15)
|
||||
if r.status_code != 200:
|
||||
return []
|
||||
body = r.json()
|
||||
if body.get('code') != 0:
|
||||
return []
|
||||
sheets = (body.get('data') or {}).get('sheets') or []
|
||||
return [(s.get('sheetId') or s.get('title'), (s.get('title') or '')) for s in sheets]
|
||||
|
||||
|
||||
def resolve_sheet_id_for_month(token, month_num):
|
||||
"""month_num 1=1月 2=2月。返回 (sheet_id, 月份标签)。"""
|
||||
if month_num == 2:
|
||||
return SHEET_ID_DEFAULT, '2月'
|
||||
if month_num != 1:
|
||||
return SHEET_ID_DEFAULT, '2月'
|
||||
# 第1个月:找标题含 1月 的 sheet
|
||||
for sheet_id, title in get_sheets_list(token):
|
||||
if '1月' in title:
|
||||
return sheet_id, '1月'
|
||||
return None, '1月'
|
||||
|
||||
|
||||
def read_range(token, range_str):
|
||||
url = f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{WIKI_NODE_OR_SPREADSHEET_TOKEN}/values/{quote(range_str, safe="")}'
|
||||
r = requests.get(url, headers={'Authorization': f'Bearer {token}'}, timeout=15)
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
body = r.json()
|
||||
if body.get('code') != 0:
|
||||
return None
|
||||
return (body.get('data') or {}).get('valueRange', {}).get('values') or []
|
||||
|
||||
|
||||
def num(s):
|
||||
if s is None or s == '':
|
||||
return 0
|
||||
try:
|
||||
return int(float(str(s).replace(',', '').strip()))
|
||||
except (ValueError, TypeError):
|
||||
return 0
|
||||
|
||||
|
||||
def get_month_sheets_sorted(token):
|
||||
"""返回标题含「x月」的工作表,按 1月、2月… 排序。[(sheet_id, title), ...]"""
|
||||
import re
|
||||
sheets = get_sheets_list(token)
|
||||
month_sheets = []
|
||||
for sid, title in sheets:
|
||||
if not title or '月' not in title:
|
||||
continue
|
||||
m = re.search(r'(\d{1,2})月', title)
|
||||
key = int(m.group(1)) if m else 99
|
||||
month_sheets.append((sid, title, key))
|
||||
month_sheets.sort(key=lambda x: x[2])
|
||||
return [(x[0], x[1]) for x in month_sheets]
|
||||
|
||||
|
||||
def parse_sheet_vals(vals):
|
||||
"""从表格 values 解析场次与汇总。返回 (sessions, stats_dict) 或 (None, None) 若解析失败。"""
|
||||
if not vals or len(vals) < 12:
|
||||
return None, None
|
||||
header_row_idx = None
|
||||
for ri in (1, 0, 2):
|
||||
if ri >= len(vals):
|
||||
continue
|
||||
for c in vals[ri]:
|
||||
if '场' in str(c):
|
||||
header_row_idx = ri
|
||||
break
|
||||
if header_row_idx is not None:
|
||||
break
|
||||
if header_row_idx is None:
|
||||
return None, None
|
||||
header = vals[header_row_idx]
|
||||
data_start = header_row_idx + 1
|
||||
sessions = []
|
||||
for col_idx in range(len(header)):
|
||||
cell = str(header[col_idx]).strip()
|
||||
if '场' not in cell:
|
||||
continue
|
||||
row_vals = []
|
||||
for row_offset in range(10):
|
||||
ri = data_start + row_offset
|
||||
if ri < len(vals) and col_idx < len(vals[ri]):
|
||||
row_vals.append(vals[ri][col_idx])
|
||||
else:
|
||||
row_vals.append('')
|
||||
sessions.append((cell, row_vals))
|
||||
if not sessions:
|
||||
return None, None
|
||||
total_dur = total_push = total_room = total_interact = total_gift = total_soul = total_follow = 0
|
||||
max_online = 0
|
||||
avg_dur_list = []
|
||||
for name, row in sessions:
|
||||
total_dur += num(row[1])
|
||||
total_push += num(row[2])
|
||||
total_room += num(row[3])
|
||||
if num(row[4]) > 0:
|
||||
avg_dur_list.append(num(row[4]))
|
||||
total_interact += num(row[5])
|
||||
total_gift += num(row[6])
|
||||
total_soul += num(row[7])
|
||||
total_follow += num(row[8])
|
||||
o = num(row[9])
|
||||
if o > max_online:
|
||||
max_online = o
|
||||
avg_dur_list = [x for x in avg_dur_list if x and x > 0]
|
||||
avg_dur = round(sum(avg_dur_list) / len(avg_dur_list), 1) if avg_dur_list else 0
|
||||
with_data = [s[0] for s in sessions if num(s[1][1]) > 0]
|
||||
stats = {
|
||||
'total_dur': total_dur, 'total_push': total_push, 'total_room': total_room,
|
||||
'total_interact': total_interact, 'total_gift': total_gift, 'total_soul': total_soul,
|
||||
'total_follow': total_follow, 'max_online': max_online, 'avg_dur': avg_dur,
|
||||
'sessions_count': len(sessions), 'with_data_count': len(with_data), 'with_data_names': with_data,
|
||||
}
|
||||
return sessions, stats
|
||||
|
||||
|
||||
def run_all_months(token):
|
||||
"""遍历所有月份 sheet,汇总总数据并分月展示。"""
|
||||
month_sheets = get_month_sheets_sorted(token)
|
||||
if not month_sheets:
|
||||
print('❌ 未找到任何标题含「x月」的工作表')
|
||||
return
|
||||
grand = {
|
||||
'total_dur': 0, 'total_push': 0, 'total_room': 0, 'total_interact': 0,
|
||||
'total_gift': 0, 'total_soul': 0, 'total_follow': 0, 'max_online': 0,
|
||||
'avg_dur_sum': 0.0, 'avg_dur_n': 0, 'sessions_count': 0, 'with_data_count': 0,
|
||||
}
|
||||
per_month = []
|
||||
for sheet_id, title in month_sheets:
|
||||
vals = read_range(token, f'{sheet_id}!A1:AG15')
|
||||
sessions, stats = parse_sheet_vals(vals) if vals else (None, None)
|
||||
if not stats:
|
||||
per_month.append((title, None))
|
||||
continue
|
||||
per_month.append((title, stats))
|
||||
grand['total_dur'] += stats['total_dur']
|
||||
grand['total_push'] += stats['total_push']
|
||||
grand['total_room'] += stats['total_room']
|
||||
grand['total_interact'] += stats['total_interact']
|
||||
grand['total_gift'] += stats['total_gift']
|
||||
grand['total_soul'] += stats['total_soul']
|
||||
grand['total_follow'] += stats['total_follow']
|
||||
if stats['max_online'] > grand['max_online']:
|
||||
grand['max_online'] = stats['max_online']
|
||||
if stats['avg_dur'] > 0:
|
||||
grand['avg_dur_sum'] += stats['avg_dur'] * stats['with_data_count']
|
||||
grand['avg_dur_n'] += stats['with_data_count']
|
||||
grand['sessions_count'] += stats['sessions_count']
|
||||
grand['with_data_count'] += stats['with_data_count']
|
||||
grand_avg_dur = round(grand['avg_dur_sum'] / grand['avg_dur_n'], 1) if grand['avg_dur_n'] else 0
|
||||
# 输出
|
||||
print('=' * 60)
|
||||
print('飞书运营报表 · 全部月份总数据汇总')
|
||||
print('=' * 60)
|
||||
print(f'涉及工作表:共 {len(month_sheets)} 个月 → {", ".join(t for _, t in month_sheets)}')
|
||||
print()
|
||||
print('【各月明细】')
|
||||
print('-' * 60)
|
||||
for title, stats in per_month:
|
||||
if not stats:
|
||||
print(f' {title}: 未解析到数据')
|
||||
continue
|
||||
print(f' {title}')
|
||||
print(f' 有数据场次 {stats["with_data_count"]} 场 | 时长 {stats["total_dur"]} 分钟 | '
|
||||
f'推流 {stats["total_push"]} | 进房 {stats["total_room"]} | '
|
||||
f'互动 {stats["total_interact"]} | 礼物 {stats["total_gift"]} | '
|
||||
f'灵魂力 {stats["total_soul"]} | 关注 {stats["total_follow"]} | 最高在线 {stats["max_online"]}')
|
||||
print('-' * 60)
|
||||
print('【全部月份合计】')
|
||||
print(f' 总时长(分钟) {grand["total_dur"]}')
|
||||
print(f' Soul推流人数 {grand["total_push"]}')
|
||||
print(f' 进房人数 {grand["total_room"]}')
|
||||
print(f' 互动数量 {grand["total_interact"]}')
|
||||
print(f' 礼物 {grand["total_gift"]}')
|
||||
print(f' 灵魂力 {grand["total_soul"]}')
|
||||
print(f' 增加关注 {grand["total_follow"]}')
|
||||
print('【全部月份取值】')
|
||||
print(f' 最高在线(各场最大) {grand["max_online"]}')
|
||||
print(f' 人均时长(加权平均) {grand_avg_dur} 分钟')
|
||||
print(f' 表内场次列合计 {grand["sessions_count"]} 列')
|
||||
print(f' 有数据场次合计 {grand["with_data_count"]} 场')
|
||||
print('=' * 60)
|
||||
|
||||
|
||||
def main():
|
||||
month_num = 2
|
||||
run_all = False
|
||||
if len(sys.argv) >= 2:
|
||||
arg = str(sys.argv[1]).strip().lower()
|
||||
if arg in ('all', '全部', 'all月'):
|
||||
run_all = True
|
||||
else:
|
||||
try:
|
||||
month_num = int(sys.argv[1])
|
||||
if month_num not in (1, 2):
|
||||
month_num = 2
|
||||
except ValueError:
|
||||
pass
|
||||
token = load_token() or refresh_token()
|
||||
if not token:
|
||||
print('❌ 无法获取飞书 Token')
|
||||
sys.exit(1)
|
||||
if run_all:
|
||||
run_all_months(token)
|
||||
return
|
||||
sheet_id, month_label = resolve_sheet_id_for_month(token, month_num)
|
||||
if sheet_id is None:
|
||||
print(f'❌ 未找到第1个月({month_label})对应的工作表,请确认飞书表格中存在标题含「1月」的 sheet')
|
||||
sys.exit(1)
|
||||
vals = read_range(token, f'{sheet_id}!A1:AG15')
|
||||
if not vals or len(vals) < 12:
|
||||
print('❌ 读取表格失败或数据行不足')
|
||||
sys.exit(1)
|
||||
# 找表头行:某行单元格含「场」
|
||||
header_row_idx = None
|
||||
for ri in (1, 0, 2):
|
||||
if ri >= len(vals):
|
||||
continue
|
||||
row = vals[ri]
|
||||
for c in row:
|
||||
if '场' in str(c):
|
||||
header_row_idx = ri
|
||||
break
|
||||
if header_row_idx is not None:
|
||||
break
|
||||
if header_row_idx is None:
|
||||
print('❌ 未找到场次表头行')
|
||||
sys.exit(1)
|
||||
header = vals[header_row_idx]
|
||||
# 数据从下一行开始,共10行:主题、时长、推流、进房、人均时长、互动、礼物、灵魂力、增加关注、最高在线
|
||||
data_start = header_row_idx + 1
|
||||
sessions = [] # [(场次名, [10个值]), ...]
|
||||
for col_idx in range(len(header)):
|
||||
cell = str(header[col_idx]).strip()
|
||||
if '场' not in cell:
|
||||
continue
|
||||
row_vals = []
|
||||
for row_offset in range(10):
|
||||
ri = data_start + row_offset
|
||||
if ri < len(vals) and col_idx < len(vals[ri]):
|
||||
row_vals.append(vals[ri][col_idx])
|
||||
else:
|
||||
row_vals.append('')
|
||||
sessions.append((cell, row_vals))
|
||||
if not sessions:
|
||||
print('❌ 未解析到任何场次数据')
|
||||
sys.exit(1)
|
||||
# 汇总:时长、推流、进房、互动、礼物、灵魂力、增加关注 相加;最高在线 取 max;人均时长 取非零平均
|
||||
total_dur = total_push = total_room = total_interact = total_gift = total_soul = total_follow = 0
|
||||
max_online = 0
|
||||
avg_dur_list = []
|
||||
for name, row in sessions:
|
||||
duration = num(row[1])
|
||||
push = num(row[2])
|
||||
room = num(row[3])
|
||||
avg_dur = num(row[4])
|
||||
interact = num(row[5])
|
||||
gift = num(row[6])
|
||||
soul = num(row[7])
|
||||
follow = num(row[8])
|
||||
online = num(row[9])
|
||||
total_dur += duration
|
||||
total_push += push
|
||||
total_room += room
|
||||
total_interact += interact
|
||||
total_gift += gift
|
||||
total_soul += soul
|
||||
total_follow += follow
|
||||
if online > max_online:
|
||||
max_online = online
|
||||
if avg_dur > 0:
|
||||
avg_dur_list.append(avg_dur)
|
||||
avg_dur = round(sum(avg_dur_list) / len(avg_dur_list), 1) if avg_dur_list else 0
|
||||
with_data = [(n, r) for n, r in sessions if num(r[1]) > 0] # 时长>0 视为有数据
|
||||
# 输出
|
||||
print('=' * 50)
|
||||
print(f'飞书运营报表 · 第{month_num}个月({month_label})运营数据统计')
|
||||
print('=' * 50)
|
||||
print(f'表内场次列:共 {len(sessions)} 场')
|
||||
print(f'有数据场次:共 {len(with_data)} 场 → {", ".join(s[0] for s in with_data)}')
|
||||
print()
|
||||
print('【合计】')
|
||||
print(f' 时长(分钟) {total_dur}')
|
||||
print(f' Soul推流人数 {total_push}')
|
||||
print(f' 进房人数 {total_room}')
|
||||
print(f' 互动数量 {total_interact}')
|
||||
print(f' 礼物 {total_gift}')
|
||||
print(f' 灵魂力 {total_soul}')
|
||||
print(f' 增加关注 {total_follow}')
|
||||
print('【取值】')
|
||||
print(f' 最高在线(取各场最大) {max_online}')
|
||||
print(f' 人均时长(非零场平均) {avg_dur} 分钟')
|
||||
print('=' * 50)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
225
02_卡人(水)/水桥_平台对接/飞书管理/脚本/feishu_write_minutes_to_sheet.py
Normal file
225
02_卡人(水)/水桥_平台对接/飞书管理/脚本/feishu_write_minutes_to_sheet.py
Normal file
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
将「团队/内部会议纪要」与「派对今日总结」的图片上传到飞书运营报表对应单元格内。
|
||||
- 内部会议纪要:写在「内部会议纪要」这一行,按纪要上的日期(如 2月20日)填到该日期列。
|
||||
- 派对今日总结:写在「今日总结」这一行,按派对日期(如 2月19日)填到该日期列。
|
||||
不发飞书群。
|
||||
用法:python3 feishu_write_minutes_to_sheet.py [内部会议图片路径] [派对总结图片路径]
|
||||
默认:内部会议 20260220-094434.jpg → 2月20日列,派对总结 20260220-094442.png → 2月19日列
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
|
||||
FEISHU_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TOKEN_FILE = os.path.join(FEISHU_SCRIPT_DIR, '.feishu_tokens.json')
|
||||
WIKI_TOKEN = os.environ.get('FEISHU_SPREADSHEET_TOKEN', 'wikcnIgAGSNHo0t36idHJ668Gfd')
|
||||
SHEET_ID = os.environ.get('FEISHU_SHEET_ID', '7A3Cy9')
|
||||
|
||||
# 默认图片路径(内部会议 2月20日、派对总结 2月19日)
|
||||
DEFAULT_IMAGE_INTERNAL = '/Users/karuo/Downloads/20260220-094434.jpg'
|
||||
DEFAULT_IMAGE_PARTY = '/Users/karuo/Downloads/20260220-094442.png'
|
||||
|
||||
# 飞书写入图片:单次请求 body 可能限制大小,图片过大时先压缩
|
||||
MAX_IMAGE_BYTES = 800 * 1024 # 800KB 以内较稳妥
|
||||
|
||||
|
||||
def load_token():
|
||||
if not os.path.exists(TOKEN_FILE):
|
||||
return None
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f).get('access_token')
|
||||
|
||||
|
||||
def refresh_token():
|
||||
if not os.path.exists(TOKEN_FILE):
|
||||
return None
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
r = requests.post(
|
||||
'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal',
|
||||
json={'app_id': 'cli_a48818290ef8100d', 'app_secret': 'dhjU0qWd5AzicGWTf4cTqhCWJOrnuCk4'},
|
||||
timeout=10,
|
||||
)
|
||||
app_token = (r.json() or {}).get('app_access_token')
|
||||
if not app_token:
|
||||
return None
|
||||
r2 = requests.post(
|
||||
'https://open.feishu.cn/open-apis/authen/v1/oidc/refresh_access_token',
|
||||
headers={'Authorization': f'Bearer {app_token}', 'Content-Type': 'application/json'},
|
||||
json={'grant_type': 'refresh_token', 'refresh_token': data.get('refresh_token')},
|
||||
timeout=10,
|
||||
)
|
||||
out = r2.json()
|
||||
if out.get('code') == 0 and out.get('data', {}).get('access_token'):
|
||||
data['access_token'] = out['data']['access_token']
|
||||
data['refresh_token'] = out['data'].get('refresh_token', data.get('refresh_token'))
|
||||
with open(TOKEN_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
return data['access_token']
|
||||
return None
|
||||
|
||||
|
||||
def read_range(token, range_str):
|
||||
url = f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{WIKI_TOKEN}/values/{quote(range_str, safe="")}'
|
||||
r = requests.get(url, headers={'Authorization': f'Bearer {token}'}, timeout=15)
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
body = r.json()
|
||||
if body.get('code') != 0:
|
||||
return None
|
||||
return (body.get('data') or {}).get('valueRange', {}).get('values') or []
|
||||
|
||||
|
||||
def _col_letter(n):
|
||||
s = ''
|
||||
while True:
|
||||
s = chr(65 + n % 26) + s
|
||||
n = n // 26
|
||||
if n <= 0:
|
||||
break
|
||||
return s
|
||||
|
||||
|
||||
def _resize_image_if_needed(path, max_bytes=MAX_IMAGE_BYTES):
|
||||
"""若图片超过 max_bytes,用 PIL 压缩后返回 bytes;否则直接读文件。"""
|
||||
data = open(path, 'rb').read()
|
||||
if len(data) <= max_bytes:
|
||||
return data
|
||||
try:
|
||||
from PIL import Image
|
||||
import io
|
||||
img = Image.open(io.BytesIO(data))
|
||||
if img.mode in ('RGBA', 'P'):
|
||||
img = img.convert('RGB')
|
||||
buf = io.BytesIO()
|
||||
q = 85
|
||||
while q >= 20:
|
||||
buf.seek(0)
|
||||
buf.truncate()
|
||||
img.save(buf, 'JPEG', quality=q, optimize=True)
|
||||
if buf.tell() <= max_bytes:
|
||||
return buf.getvalue()
|
||||
q -= 15
|
||||
return buf.getvalue()
|
||||
except Exception:
|
||||
return data
|
||||
|
||||
|
||||
def write_image_to_cell(token, range_str, image_path, name=None):
|
||||
"""
|
||||
飞书 v2 写入图片到单元格:POST .../values_image,body 为 JSON,image 为整数数组(字节流)。
|
||||
range 格式:sheetId!A1:A1(单个格子)
|
||||
"""
|
||||
if not os.path.exists(image_path):
|
||||
return 404, {'msg': f'文件不存在: {image_path}'}
|
||||
name = name or os.path.basename(image_path)
|
||||
data = _resize_image_if_needed(image_path)
|
||||
# 飞书要求 image 为整数数组(图片二进制流)
|
||||
image_arr = list(data)
|
||||
url = f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{WIKI_TOKEN}/values_image'
|
||||
payload = {
|
||||
'range': range_str if ':' in range_str else f'{range_str}:{range_str.split("!")[1]}',
|
||||
'name': name,
|
||||
'image': image_arr,
|
||||
}
|
||||
r = requests.post(
|
||||
url,
|
||||
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
|
||||
json=payload,
|
||||
timeout=60,
|
||||
)
|
||||
try:
|
||||
return r.status_code, r.json()
|
||||
except Exception:
|
||||
return r.status_code, {'msg': r.text[:200]}
|
||||
|
||||
|
||||
def main():
|
||||
image_internal = (sys.argv[1] if len(sys.argv) > 1 else DEFAULT_IMAGE_INTERNAL).strip()
|
||||
image_party = (sys.argv[2] if len(sys.argv) > 2 else DEFAULT_IMAGE_PARTY).strip()
|
||||
|
||||
token = load_token() or refresh_token()
|
||||
if not token:
|
||||
print('❌ 无法获取飞书 Token')
|
||||
sys.exit(1)
|
||||
vals = read_range(token, f'{SHEET_ID}!A1:AG50')
|
||||
if not vals or len(vals) < 2:
|
||||
print('❌ 读取表格失败')
|
||||
sys.exit(1)
|
||||
header = vals[0]
|
||||
col_19 = col_20 = None
|
||||
for idx, cell in enumerate(header):
|
||||
c = str(cell).strip()
|
||||
if c == '19':
|
||||
col_19 = idx
|
||||
if c == '20':
|
||||
col_20 = idx
|
||||
if col_19 is None or col_20 is None:
|
||||
print('⚠️ 未找到日期列 19 或 20')
|
||||
row_internal = None
|
||||
row_party = None
|
||||
for ri, row in enumerate(vals):
|
||||
a1 = (row[0] if row and len(row) > 0 else '')
|
||||
if a1 is None:
|
||||
a1 = ''
|
||||
a1 = str(a1).strip()
|
||||
if not a1:
|
||||
continue
|
||||
if '内部会议' in a1 or ('团队' in a1 and '会议' in a1):
|
||||
row_internal = ri + 1
|
||||
if '今日总结' in a1:
|
||||
row_party = ri + 1
|
||||
if row_internal is None:
|
||||
print('⚠️ 未找到「内部会议纪要」/「团队会议」行')
|
||||
if row_party is None:
|
||||
print('⚠️ 未找到「今日总结」行')
|
||||
|
||||
written = 0
|
||||
if row_internal is not None and col_20 is not None and os.path.exists(image_internal):
|
||||
range_cell = f'{SHEET_ID}!{_col_letter(col_20)}{row_internal}:{_col_letter(col_20)}{row_internal}'
|
||||
code, body = write_image_to_cell(token, range_cell, image_internal, name='内部会议纪要_2月20.jpg')
|
||||
if code == 200 and body.get('code') in (0, None):
|
||||
print(f'✅ 已上传图片到「内部会议纪要」→ 2月20日列({range_cell})')
|
||||
written += 1
|
||||
else:
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_token()
|
||||
if token:
|
||||
code, body = write_image_to_cell(token, range_cell, image_internal, name='内部会议纪要_2月20.jpg')
|
||||
if code == 200 and body.get('code') in (0, None):
|
||||
print('✅ 已上传图片到「内部会议纪要」→ 2月20日列')
|
||||
written += 1
|
||||
if not written:
|
||||
print('❌ 上传内部会议图片失败:', code, body)
|
||||
elif not os.path.exists(image_internal):
|
||||
print('⚠️ 内部会议图片不存在:', image_internal)
|
||||
|
||||
if row_party is not None and col_19 is not None and os.path.exists(image_party):
|
||||
range_cell = f'{SHEET_ID}!{_col_letter(col_19)}{row_party}:{_col_letter(col_19)}{row_party}'
|
||||
code, body = write_image_to_cell(token, range_cell, image_party, name='派对今日总结_2月19.png')
|
||||
if code == 200 and body.get('code') in (0, None):
|
||||
print(f'✅ 已上传图片到「派对今日总结」→ 2月19日列({range_cell})')
|
||||
written += 1
|
||||
else:
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_token()
|
||||
if token:
|
||||
code, body = write_image_to_cell(token, range_cell, image_party, name='派对今日总结_2月19.png')
|
||||
if code == 200 and body.get('code') in (0, None):
|
||||
print('✅ 已上传图片到「派对今日总结」→ 2月19日列')
|
||||
written += 1
|
||||
if not written:
|
||||
print('❌ 上传派对总结图片失败:', code, body)
|
||||
elif not os.path.exists(image_party):
|
||||
print('⚠️ 派对总结图片不存在:', image_party)
|
||||
|
||||
if written == 0:
|
||||
sys.exit(1)
|
||||
print('(未发飞书群)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -16,20 +16,28 @@ FEISHU_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TOKEN_FILE = os.path.join(FEISHU_SCRIPT_DIR, '.feishu_tokens.json')
|
||||
WIKI_NODE_OR_SPREADSHEET_TOKEN = os.environ.get('FEISHU_SPREADSHEET_TOKEN', 'wikcnIgAGSNHo0t36idHJ668Gfd')
|
||||
SHEET_ID = os.environ.get('FEISHU_SHEET_ID', '7A3Cy9')
|
||||
# 飞书群机器人 webhook(推送运营报表链接与场次数据)
|
||||
FEISHU_GROUP_WEBHOOK = os.environ.get('FEISHU_GROUP_WEBHOOK', 'https://open.feishu.cn/open-apis/bot/v2/hook/34b762fc-5b9b-4abb-a05a-96c8fb9599f1')
|
||||
OPERATION_REPORT_LINK = 'https://cunkebao.feishu.cn/wiki/wikcnIgAGSNHo0t36idHJ668Gfd?sheet=7A3Cy9'
|
||||
|
||||
# 写入列数:仅前 10 项(比率三项不填,表内公式自动算)
|
||||
EFFECT_COLS = 10
|
||||
|
||||
# 各场效果数据(主题≤12字且含干货与数值、时长、推流、进房…)— 比率不写入
|
||||
# 主题写分析内容最核心干货;来源TXT可写在飞书群消息中
|
||||
ROWS = {
|
||||
'96': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ], # 96场(无记录,占位;有数据后替换)
|
||||
'97': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ], # 97场(无记录,占位)
|
||||
'98': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ], # 98场(无记录,占位)
|
||||
'99': [ '', 116, 16976, 208, 0, 0, 4, 166, 12, 39 ], # 99场(派对已关闭截图)
|
||||
'100': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ], # 100场(无记录,占位)
|
||||
'96': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ], # 96场(无记录,占位)
|
||||
'97': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
'98': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
'99': [ '', 116, 16976, 208, 0, 0, 4, 166, 12, 39 ],
|
||||
'100': [ '', 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
'103': [ '号商几毛卖十几 日销两万', 155, 46749, 545, 7, 34, 1, 8, 13, 47 ],
|
||||
'104': [ 'AI创业最赚钱一月分享', 140, 36221, 367, 7, 49, 0, 0, 11, 38 ],
|
||||
# 105场 2026-02-20:截图 138分钟/403进房/54最高在线/31关注/2礼物/24灵魂力,小助手 人均10min/互动170;推流截图中无填0
|
||||
'105': [ '创业社群AI培训6980 电竞私域', 138, 0, 403, 10, 170, 2, 24, 31, 54 ],
|
||||
}
|
||||
# 场次→按日期列填写时的日期(表头为当月日期 1~31),如 105场 对应 2月20日 → 列名 "20"
|
||||
SESSION_DATE_COLUMN = {'105': '20'} # 105场 填在 2月20日 列下
|
||||
|
||||
|
||||
def load_token():
|
||||
@@ -185,26 +193,45 @@ def _to_cell_value(v):
|
||||
return str(v)
|
||||
|
||||
|
||||
def send_feishu_group_message(webhook_url, text):
|
||||
"""飞书群机器人:发送文本(msg_type=text)。"""
|
||||
if not webhook_url or not text:
|
||||
return False, None
|
||||
payload = {'msg_type': 'text', 'content': {'text': text}}
|
||||
try:
|
||||
r = requests.post(webhook_url, json=payload, timeout=10)
|
||||
return r.status_code == 200, r.json() if r.text else None
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def main():
|
||||
session = (sys.argv[1] if len(sys.argv) > 1 else '104').strip()
|
||||
row = ROWS.get(session)
|
||||
if not row:
|
||||
print('❌ 未知场次,可用: 96, 97, 98, 99, 100, 103, 104')
|
||||
print('❌ 未知场次,可用: 96, 97, 98, 99, 100, 103, 104, 105')
|
||||
sys.exit(1)
|
||||
token = load_token() or refresh_and_load_token()
|
||||
if not token:
|
||||
sys.exit(1)
|
||||
# 只取前 10 项,并按数字类型写入(主题可为空字符串)
|
||||
raw = (row + [None] * EFFECT_COLS)[:EFFECT_COLS]
|
||||
values = [_to_cell_value(raw[0])] + [_to_cell_value(raw[i]) for i in range(1, EFFECT_COLS)]
|
||||
spreadsheet_token = WIKI_NODE_OR_SPREADSHEET_TOKEN
|
||||
sheet_id = SHEET_ID
|
||||
range_read = f"{sheet_id}!A1:Z30"
|
||||
range_read = f"{sheet_id}!A1:AG30"
|
||||
vals, read_code, read_body = read_sheet_range(token, spreadsheet_token, range_read)
|
||||
# 表格结构:第1行表头(2月、1、19),第2行「一、效果数据」+「104场」在某一列,A列是指标名(主题、时长...),数据填在 104场 那一列的 3~15 行
|
||||
# 优先按当天日期列填:表头第1行多为 2月、1、2、…、20、…(日期),105场 填在 2月20日 → 找列 "20"
|
||||
target_col_0based = None
|
||||
if vals and len(vals) >= 2:
|
||||
for row_idx in (1, 0): # 先查第2行再第1行
|
||||
date_col = SESSION_DATE_COLUMN.get(session)
|
||||
if vals and date_col:
|
||||
row0 = vals[0] if len(vals) > 0 else []
|
||||
for col_idx, cell in enumerate(row0):
|
||||
if str(cell).strip() == date_col:
|
||||
target_col_0based = col_idx
|
||||
break
|
||||
# 否则按「x场」列名找
|
||||
if target_col_0based is None and vals and len(vals) >= 2:
|
||||
for row_idx in (1, 0):
|
||||
row_cells = vals[row_idx] if row_idx < len(vals) else []
|
||||
for col_idx, cell in enumerate(row_cells):
|
||||
if f"{session}场" in str(cell).strip():
|
||||
@@ -214,14 +241,37 @@ def main():
|
||||
break
|
||||
if read_code != 200 or (read_body.get('code') not in (0, None)) and not vals:
|
||||
print('⚠️ 读取表格失败:', read_code, read_body.get('msg', read_body))
|
||||
# 发群消息用竖状格式(每行一项,便于阅读)
|
||||
LABELS_GROUP = ['主题', '时长(分钟)', 'Soul推流人数', '进房人数', '人均时长(分钟)', '互动数量', '礼物', '灵魂力', '增加关注', '最高在线']
|
||||
|
||||
def _maybe_send_group(sess, raw_vals):
|
||||
if sess != '105':
|
||||
return
|
||||
lines = [
|
||||
'【Soul 派对运营报表】',
|
||||
f'链接:{OPERATION_REPORT_LINK}',
|
||||
'',
|
||||
'105场(2月20日)已登记:',
|
||||
]
|
||||
for i, label in enumerate(LABELS_GROUP):
|
||||
val = raw_vals[i] if i < len(raw_vals) else ''
|
||||
lines.append(f'{label}:{val}')
|
||||
lines.append('数据来源:soul 派对 105场 20260220.txt')
|
||||
msg = '\n'.join(lines)
|
||||
ok, _ = send_feishu_group_message(FEISHU_GROUP_WEBHOOK, msg)
|
||||
if ok:
|
||||
print('✅ 已同步推送到飞书群(竖状格式)')
|
||||
else:
|
||||
print('⚠️ 飞书群推送失败(请检查 webhook)')
|
||||
|
||||
if target_col_0based is not None:
|
||||
col_letter = _col_letter(target_col_0based)
|
||||
# 竖列写入:T3:T15 一列,values 为 [[v1],[v2],...[v13]]
|
||||
range_col = f"{sheet_id}!{col_letter}3:{col_letter}{2 + len(values)}"
|
||||
values_vertical = [[v] for v in values]
|
||||
code, body = update_sheet_range(token, spreadsheet_token, range_col, values_vertical)
|
||||
if code == 200 and body.get('code') == 0:
|
||||
print(f'✅ 已写入飞书表格:{session}场 效果数据(竖列 {col_letter}3:{col_letter}{2+len(values)},共{len(values)}格)')
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
@@ -229,8 +279,8 @@ def main():
|
||||
code, body = update_sheet_range(token, spreadsheet_token, range_col, values_vertical)
|
||||
if code == 200 and body.get('code') == 0:
|
||||
print(f'✅ 已写入飞书表格:{session}场 效果数据(竖列 {col_letter})')
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
# 单列多行若报 90202(columns of value>range),则逐格写入
|
||||
err = body.get('code')
|
||||
if err == 90202 or (err and 'range' in str(body.get('msg', '')).lower()):
|
||||
all_ok = True
|
||||
@@ -248,11 +298,13 @@ def main():
|
||||
break
|
||||
if all_ok:
|
||||
print(f'✅ 已写入飞书表格:{session}场 效果数据(竖列 {col_letter}3:{col_letter}{2+len(values)} 逐格)')
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
print('❌ 按列更新失败:', code, body)
|
||||
code, body = write_sheet_row(token, spreadsheet_token, sheet_id, values)
|
||||
if code == 200 and (body.get('code') == 0 or body.get('code') is None):
|
||||
print(f'✅ 已追加一行:{session}场 效果数据')
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
@@ -260,6 +312,7 @@ def main():
|
||||
code, body = write_sheet_row(token, spreadsheet_token, sheet_id, values)
|
||||
if code == 200 and (body.get('code') == 0 or body.get('code') is None):
|
||||
print(f'✅ 已追加一行:{session}场 效果数据')
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
print('❌ 写入失败:', code, body)
|
||||
if body.get('code') in (99991663, 99991677):
|
||||
|
||||
@@ -26,13 +26,13 @@ TASKS = [
|
||||
"分布式算力矩阵→三次对话吸收+资产全景+安全加固 📊 (85%)",
|
||||
"全量扫描→33.9万IP防断网跑完+6984验证+1281高价值主机 🔍 (100%)",
|
||||
"Soul派对→101场(2/16)与102场(2/17)纪要+主题迭代 🎙️ (100%)",
|
||||
"安全运维→小型宝塔攻击链处理+SSH加固待办+CKB NAS绑定 🛡️ (70%)",
|
||||
"安全运维→宝塔攻击链处理+SSH加固待办+CKB NAS绑定 🛡️ (70%)",
|
||||
],
|
||||
"n_process": [
|
||||
"【算力矩阵】2/15三次Agent对话吸收→资产清单(公司NAS/家NAS/存客宝/kr宝塔)→PCDN收益模型→规模化测算→部署路线(Docker/chroot)→紧急待办P0-P2",
|
||||
"【全量扫描】2/16 33.9万IP、并发2000防断网→TCP存活8257、协议验证6984、高价值1281→反填04暴力破解→家宽优化SKILL吸收",
|
||||
"【Soul派对】101场(程序员AI工具链×电动车民宿×金融)、102场(过年第一个红包发给谁×人生三贵人)→纪要产出+长图→话题迭代",
|
||||
"【安全】小型宝塔XMRig/后门清理→攻击IP封禁→存客宝/kr宝塔SSH待开→CKB NAS网心云绑定15880802661待执行",
|
||||
"【安全】宝塔XMRig/后门清理→攻击IP封禁→存客宝/kr宝塔SSH待开→CKB NAS网心云绑定15880802661待执行",
|
||||
],
|
||||
"t_thoughts": [
|
||||
"算力矩阵先摸清资产与安全,再规模化;家宽降并发可跑完全程",
|
||||
|
||||
94
02_卡人(水)/水桥_平台对接/飞书管理/运营报表_SKILL.md
Normal file
94
02_卡人(水)/水桥_平台对接/飞书管理/运营报表_SKILL.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
name: 飞书运营报表
|
||||
description: Soul 派对运营报表全流程——截图→填表→发群;会议纪要图片上传;月度统计
|
||||
triggers: 运营报表、派对填表、派对截图填表发群、会议纪要上传、本月运营数据、全部月份统计
|
||||
parent: 飞书管理
|
||||
owner: 水桥
|
||||
group: 水
|
||||
version: "1.0"
|
||||
updated: "2026-02-20"
|
||||
---
|
||||
|
||||
# 飞书运营报表 Skill
|
||||
|
||||
> 截图 → 填写表格 → 发群(竖状格式);会议纪要图片入格;月度统计。
|
||||
|
||||
---
|
||||
|
||||
## 一、全流程:截图 → 填表 → 发群
|
||||
|
||||
| 步骤 | 做什么 | 说明 |
|
||||
|:---|:---|:---|
|
||||
| **1. 截图/数据** | 派对关闭页 + 小助手弹窗 + 可选 TXT | 从截图取:时长、进房、最高在线、关注、礼物、灵魂力、人均时长、互动;主题从 TXT 提炼 ≤12 字 |
|
||||
| **2. 填表** | 在脚本 `ROWS` 里配好该场 10 项数据,按日期列或「x场」列写入 | 见下方「填写规则」 |
|
||||
| **3. 发群** | 写入成功后自动推送到飞书群 webhook | **发群内容必须用竖状格式**(每行一项,不用一串) |
|
||||
|
||||
### 发群格式(竖状)
|
||||
|
||||
发到群里的内容格式示例,**竖状**便于阅读:
|
||||
|
||||
```
|
||||
【Soul 派对运营报表】
|
||||
链接:https://cunkebao.feishu.cn/wiki/wikcnIgAGSNHo0t36idHJ668Gfd?sheet=7A3Cy9
|
||||
|
||||
105场(2月20日)已登记:
|
||||
主题:创业社群AI培训6980 电竞私域
|
||||
时长(分钟):138
|
||||
Soul推流人数:0
|
||||
进房人数:403
|
||||
人均时长(分钟):10
|
||||
互动数量:170
|
||||
礼物:2
|
||||
灵魂力:24
|
||||
增加关注:31
|
||||
最高在线:54
|
||||
数据来源:soul 派对 105场 20260220.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、填写规则(表格内)
|
||||
|
||||
- **只填前 10 项**:主题、时长、Soul推流人数、进房人数、人均时长、互动数量、礼物、灵魂力、增加关注、最高在线
|
||||
- **按数字类型**写入,不填推流进房率、1分钟进多少人、加微率(表内公式自动算)
|
||||
- **主题** ≤12 字,含干货与数值
|
||||
- **按日期列**:表头为 1、2…19、20…,该场对应几号就填在几号列下
|
||||
- 数据竖列写入该列第 3~12 行
|
||||
|
||||
---
|
||||
|
||||
## 三、脚本与命令
|
||||
|
||||
| 脚本 | 用途 |
|
||||
|:---|:---|
|
||||
| `soul_party_to_feishu_sheet.py [场次]` | 写入该场效果数据到运营报表;部分场次写入后自动发群(竖状) |
|
||||
| `feishu_write_minutes_to_sheet.py [内部图] [派对图]` | 内部会议纪要、派对今日总结**图片**上传到对应单元格(不发群) |
|
||||
| `feishu_sheet_monthly_stats.py [1\|2\|all]` | 统计第 1 月 / 第 2 月 / 全部月份运营数据 |
|
||||
|
||||
**路径**:`02_卡人(水)/水桥_平台对接/飞书管理/脚本/`
|
||||
|
||||
```bash
|
||||
# 写入 105 场并发群(竖状)
|
||||
python3 .../脚本/soul_party_to_feishu_sheet.py 105
|
||||
|
||||
# 上传会议纪要图片到单元格
|
||||
python3 .../脚本/feishu_write_minutes_to_sheet.py
|
||||
|
||||
# 本月 / 全部月份统计
|
||||
python3 .../脚本/feishu_sheet_monthly_stats.py 2
|
||||
python3 .../脚本/feishu_sheet_monthly_stats.py all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、配置
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| 运营报表链接 | https://cunkebao.feishu.cn/wiki/wikcnIgAGSNHo0t36idHJ668Gfd?sheet=7A3Cy9 |
|
||||
| Token | 脚本同目录 `.feishu_tokens.json` |
|
||||
| 发群 webhook | 脚本内 `FEISHU_GROUP_WEBHOOK` 或环境变量 |
|
||||
|
||||
---
|
||||
|
||||
**父 Skill**:飞书管理(`SKILL.md`)
|
||||
85
运营中枢/参考资料/iPhone12当Mac扩展屏_操作指南.md
Normal file
85
运营中枢/参考资料/iPhone12当Mac扩展屏_操作指南.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# iPhone 12 当 Mac 扩展屏 — 操作指南
|
||||
|
||||
> 苹果官方「随航」仅支持 iPad,本指南通过**第三方软件**让 iPhone 12 成为 Mac 的扩展屏。
|
||||
> 适用:MacBook(Intel / Apple Silicon)+ iPhone 12,同一 Wi‑Fi 或 USB 连接。
|
||||
|
||||
---
|
||||
|
||||
## 方案一:Duet Display(推荐,体验最好)
|
||||
|
||||
**特点**:延迟低、支持触控、有线/无线均可;**明确支持 iPhone** 作为第二显示器。
|
||||
|
||||
### 1. 下载安装
|
||||
|
||||
| 设备 | 操作 |
|
||||
|------|------|
|
||||
| **Mac** | 打开 [Duet 官网下载页](https://www.duetdisplay.com/zh/onboarding/download-apps-basic),按你的 Mac 类型选:<br>• **Apple Silicon (M1/M2/M3 等)**:<https://updates.duetdisplay.com/AppleSilicon><br>• **Intel Mac**:<https://updates.duetdisplay.com/IntelMac><br>下载后把 Duet 拖到「应用程序」即可。 |
|
||||
| **iPhone 12** | 在 App Store 搜索 **「Duet Display」** 安装(付费应用,约 68–98 元一次性,或含 Pro 订阅)。 |
|
||||
|
||||
### 2. 连接与权限(首次必做)
|
||||
|
||||
1. **数据线连接**(推荐,延迟最低):用 **Lightning 转 USB** 线把 iPhone 12 连到 Mac。
|
||||
2. **Mac 上**:打开 Duet,菜单栏出现 Duet 图标;若提示「添加助手」或信任设备,按提示在 **iPhone 上输入锁屏密码** 完成配对。
|
||||
3. **授予权限**:
|
||||
**系统设置 → 隐私与安全性 → 辅助功能** → 勾选 **Duet**(或 Duet Display)。
|
||||
若系统要求「屏幕录制」也勾选 Duet。
|
||||
4. **无线用法**(可选):同一 Wi‑Fi 下,Mac 与 iPhone 都打开 Duet,在 Duet 里选择「无线」连接(延迟会比有线略高)。
|
||||
|
||||
### 3. 当扩展屏使用
|
||||
|
||||
- 连接成功后,Mac 会把 **iPhone 12 识别为第二块显示器**。
|
||||
- 在 **系统设置 → 显示器** 里可调整「排列」:把 iPhone 放在主屏的左边/右边/上下,拖窗口到 iPhone 上即可当扩展屏用。
|
||||
- 在 Duet 菜单里可切换「**扩展桌面**」或「镜像」,以及分辨率等。
|
||||
|
||||
### 4. 常见问题
|
||||
|
||||
- **不识别 iPhone**:确认线缆可传数据(非仅充电线)、已在 iPhone 上点「信任此电脑」;重启 Duet 或重插线再试。
|
||||
- **卡顿**:优先用 **USB 有线**;关掉其他占带宽的应用。
|
||||
- **权限被收回**:系统更新后若失效,再到「辅助功能」「屏幕录制」里重新勾选 Duet。
|
||||
|
||||
---
|
||||
|
||||
## 方案二:Yam Display / Yam Air(成本更低)
|
||||
|
||||
**特点**:Mac 端免费,iOS 端约 **¥58 一次性**;支持 USB 有线(Yam Display)或无线(Yam Air);**支持 iPhone**。
|
||||
|
||||
### 1. 下载安装
|
||||
|
||||
| 设备 | 操作 |
|
||||
|------|------|
|
||||
| **Mac** | 官网或 Mac 应用商店搜索 **Yam Display**,安装 Mac 版(免费)。 |
|
||||
| **iPhone 12** | App Store 搜索 **Yam Display** 或 **Yam Air** 安装(约 ¥58 买断)。 |
|
||||
|
||||
### 2. 连接与使用
|
||||
|
||||
- **有线**:用 Lightning 数据线连接 iPhone 与 Mac,打开 Mac 端与 iPhone 端 Yam Display,按提示信任设备;Mac 会多出一块「显示器」。
|
||||
- **无线**:使用 **Yam Air**,Mac 与 iPhone 在同一 Wi‑Fi 下,两端打开应用即可配对,iPhone 作为扩展屏。
|
||||
- 在 **系统设置 → 显示器** 中排列两块屏的位置,即可把窗口拖到 iPhone 上。
|
||||
|
||||
### 3. 注意
|
||||
|
||||
- 无线模式下延迟和画质会随网络波动;需要稳定体验建议用 USB 有线。
|
||||
|
||||
---
|
||||
|
||||
## 方案对比(简要)
|
||||
|
||||
| 项目 | Duet Display | Yam Display / Yam Air |
|
||||
|------|--------------|------------------------|
|
||||
| iPhone 支持 | ✅ 支持 | ✅ 支持 |
|
||||
| 价格 | iOS 约 68–98 元起,可选 Pro 订阅 | Mac 免费,iOS 约 ¥58 买断 |
|
||||
| 有线/无线 | 都支持 | Yam 有线 / Yam Air 无线 |
|
||||
| 延迟 | 有线接近「零延迟」 | 有线较好,无线一般 |
|
||||
| 适用 | 追求体验、常当副屏用 | 预算敏感、偶尔当副屏 |
|
||||
|
||||
---
|
||||
|
||||
## 推荐执行顺序(iPhone 12 + 本机 MacBook)
|
||||
|
||||
1. **优先试 Duet Display**:按上面「方案一」在 Mac 与 iPhone 12 装好、用 **USB 线** 连接并给好权限,确认能在「显示器」里看到第二块屏并拖窗口过去。
|
||||
2. 若 Duet 不符合预算或不想付费,再试 **Yam Display(有线)** 或 **Yam Air(无线)**。
|
||||
3. 日常使用:需要低延迟就保持 **有线连接**;临时用一下可用 **无线**(Duet 或 Yam Air)。
|
||||
|
||||
---
|
||||
|
||||
*文档生成:卡若AI · 运营中枢 | 依据公开资料与官网整理,供本机 iPhone 12 当 Mac 扩展屏使用。*
|
||||
201
运营中枢/参考资料/卡若AI执行流程与对话全流程.md
Normal file
201
运营中枢/参考资料/卡若AI执行流程与对话全流程.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 卡若AI 执行流程与对话全流程
|
||||
|
||||
> 一份文档说清:**卡若AI 内部执行流程** + **与你对话时的完整执行与回复流程**。
|
||||
> 版本:1.0 | 更新:2026-02-19
|
||||
|
||||
---
|
||||
|
||||
## 一、总览:两条线
|
||||
|
||||
| 维度 | 内容 |
|
||||
|------|------|
|
||||
| **执行流程** | AI 接到任务后,内部「怎么想、怎么找技能、怎么干、怎么验、怎么收尾」的固定步骤。 |
|
||||
| **对话全流程** | 从你发出一条消息,到 AI 读完上下文、执行、回复(含复盘)的整条对话链路。 |
|
||||
|
||||
二者关系:**对话全流程 = 你在对话里看到的「执行流程」的完整呈现**;每次对话都按同一套执行流程跑一遍,并在回复里按步骤让你看到。
|
||||
|
||||
---
|
||||
|
||||
## 二、卡若AI 内部执行流程(七步)
|
||||
|
||||
以下为 AI 接到任务后**内部必须遵循**的步骤,来源于 `BOOTSTRAP.md` 第四节与 `卡若AI交互流程与强制执行条件.md`。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 卡若AI 内部执行流程(强制) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
你的输入(任务/问题)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1. 启动加载(只读必要的) │
|
||||
│ 读 BOOTSTRAP.md → 读 SKILL_REGISTRY.md → 按需读对应 SKILL.md │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 2. 先思考,并简洁输出在对话框(强制) │
|
||||
│ 目标是什么、该谁干、怎么干、可能卡在哪;结合 5 负责人、14 成员、54 技能 │
|
||||
│ → 把结论用几句话输出,再动手。禁止不思考直接动手。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 3. 技能路由与方案扩展 │
|
||||
│ 查 SKILL_REGISTRY.md 按触发词匹配 → 找到技能路径 → 读 SKILL.md │
|
||||
│ 多技能按 金→水→木→火→土 优先级;可搜索扩展执行方案、验收标准。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 4. 执行 │
|
||||
│ 理解 → 拆解 → 读取上下文 → 按 SKILL 步骤执行 → 每步简短总结 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 5. 反复验证结果(强制) │
|
||||
│ 结果是否与用户一开始的命令/目标匹配? │
|
||||
│ · 匹配 → 进入对话结尾(复盘) │
|
||||
│ · 不匹配 → 回溯 → 搜索(GitHub/Skill/网上) → 再思考 → 再执行 → 再验证 │
|
||||
│ 循环直到达成或明确说明无法达成。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 6. 结果交付 │
|
||||
│ 交付物/结论与目标一致;若无法达成则说明差距、原因、可选下一步。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 7. 对话结尾 = 强制复盘 │
|
||||
│ 每次对话最终回复必须以「卡若复盘」完整块收尾;格式见复盘格式_固定规则 │
|
||||
│ 多轮对话每轮结尾建议带简版复盘(🎯 + ▶)。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
你的输出(结果 + 复盘)
|
||||
|
||||
可选:有文件变更时执行 Gitea 同步;有可沉淀经验时写入 水溪/经验库/待沉淀/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、与你对话时的完整流程(你看到什么)
|
||||
|
||||
从**你发出一条消息**到**收到带复盘的最终回复**,整条对话链路如下;AI 会在回复中按步骤呈现,方便你对照验收。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 与卡若AI 对话的完整执行与回复流程 │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
你:输入任务(例如:「分析电脑情况并优化」)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 1 · 导航与阅读(在回复中会写「已读…」) │
|
||||
│ AI 读取:BOOTSTRAP、SKILL_REGISTRY、本交互流程、与任务相关的 SKILL 等 │
|
||||
│ → 回复里一句话摘要:读了什么、为什么读。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 2 · 思考与扩展(在回复中会写「目标 / 执行方案」) │
|
||||
│ AI 思考:目标、谁干、怎么干、卡点;在已有资料中搜索、扩展子步骤与验收标准 │
|
||||
│ → 回复里写出:目标、执行方案(或「打算怎么干」)。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 3 · 任务分配(在回复中会写「本任务由…执行」) │
|
||||
│ 单技能 → 读对应 SKILL 执行;多技能 → 金→水→木→火→土 依次或并行 │
|
||||
│ → 回复里写出:路由到谁(如金仓/水溪/火炬)或「本步由卡若AI 直接执行」。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 4 · 执行与验证(在回复中按步列出做了什么、每步结果) │
|
||||
│ 按 SKILL 步骤执行;每步简短总结;验证是否与你的目标匹配 │
|
||||
│ → 不通过则回溯、再执行,最多 5 轮。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 5 · 结果交付(在回复中给出交付物或结论) │
|
||||
│ 交付物路径、结论、或「未完全达成」时的差距与下一步。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 6 · 沉淀(可选,若有会注明) │
|
||||
│ 写入开发文档、references 或 水溪/经验库/待沉淀/ 时在回复中注明路径。 │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ 步骤 7 · 对话结尾 = 强制复盘 │
|
||||
│ [卡若复盘](YYYY-MM-DD HH:mm) │
|
||||
│ 🎯 目标·结果·达成率(一行,含百分比) │
|
||||
│ 📌 过程(1 2 3) │
|
||||
│ 💡 反思(1~3 点) │
|
||||
│ 📝 总结 │
|
||||
│ ▶ 下一步执行(含未完成/待跟进项,无则写「无」) │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
你:收到完整回复(结果 + 复盘)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、对照表:执行流程 ↔ 对话中的呈现
|
||||
|
||||
| 内部执行步骤 | 在与你对话中的呈现 |
|
||||
|--------------|--------------------|
|
||||
| 1. 启动加载 | 回复开头「已读 BOOTSTRAP、SKILL_REGISTRY、xxx SKILL」等 |
|
||||
| 2. 先思考并输出 | 回复中「目标:…」「执行方案:…」或「打算怎么干:…」 |
|
||||
| 3. 技能路由与扩展 | 「本任务由 金仓/水溪/… 执行」或「路由到 xxx,读 xxx/SKILL.md」 |
|
||||
| 4. 执行 | 按步列出「①…✓ ②…✓」或「执行了…」 |
|
||||
| 5. 反复验证 | 「验证:结果与目标匹配」或「不匹配,回溯后…」 |
|
||||
| 6. 结果交付 | 交付物路径、结论、或差距与下一步 |
|
||||
| 7. 强制复盘 | 回复末尾的 [卡若复盘] 完整块(🎯📌💡📝▶) |
|
||||
|
||||
简单任务时,AI 可能把「步骤 1+2」合并、「步骤 3+4+5」合并,但**目标结果、交付、复盘**必须有。
|
||||
|
||||
---
|
||||
|
||||
## 五、标准命令(对话中可触发)
|
||||
|
||||
你在对话里说这些,会触发固定动作(见 `BOOTSTRAP.md` 第五节):
|
||||
|
||||
| 你说的大意 | AI 会做 |
|
||||
|------------|--------|
|
||||
| 任何需求/任务 | 查 SKILL_REGISTRY → 找技能 → 读 SKILL.md 执行 |
|
||||
| 复盘 | 按复盘格式输出(每轮可简版 🎯+▶,对话结束必须完整复盘) |
|
||||
| 沉淀 | 有价值经验写入 `02_卡人(水)/水溪_整理归档/经验库/待沉淀/` |
|
||||
| 有文件变更 | 对话结束前执行 `bash 01_卡资(金)/金仓_存储备份/Gitea管理/脚本/自动同步.sh` |
|
||||
| 新项目上线/内容发布/日常运维 | 读 `运营中枢/参考资料/Pipeline执行清单.md` 按步骤执行 |
|
||||
| 报告/导出/生成图片 | 输出到 `/Users/karuo/Documents/卡若Ai的文件夹/` 对应子目录,图片登记到 `图片/图片索引.md` |
|
||||
|
||||
---
|
||||
|
||||
## 六、小结
|
||||
|
||||
- **执行流程**:启动加载 → 先思考并输出 → 技能路由与扩展 → 执行 → 反复验证 → 结果交付 → **强制复盘**(+ 可选沉淀与 Gitea 同步)。
|
||||
- **对话全流程**:你的输入 → AI 按「导航与阅读 → 思考与扩展 → 任务分配 → 执行与验证 → 结果交付 → 沉淀(可选) → **复盘**」在回复中呈现,你看到的是同一套执行流程的完整体现。
|
||||
- **强制**:先思考再动手、结果必须验证、**每次对话结尾必须用卡若复盘收尾**。复盘格式唯一标准:`运营中枢/参考资料/卡若复盘格式_固定规则.md`。
|
||||
|
||||
---
|
||||
|
||||
## 七、相关文件
|
||||
|
||||
| 文件 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| 启动指令 | `BOOTSTRAP.md` | 身份、团队、执行流程、标准命令 |
|
||||
| 技能注册表 | `SKILL_REGISTRY.md` | 按触发词查技能路径 |
|
||||
| 交互流程与强制条件 | `运营中枢/参考资料/卡若AI交互流程与强制执行条件.md` | 六步对接、对话形式、敏感任务协议 |
|
||||
| 复盘格式 | `运营中枢/参考资料/卡若复盘格式_固定规则.md` | 复盘块书写规范 |
|
||||
| 执行流程详细说明 | `运营中枢/参考资料/执行流程详细说明.md` | 统一流程简要索引 |
|
||||
@@ -135,22 +135,21 @@
|
||||
|
||||
| 名称 | IP | 配置 | 用途 | 宝塔面板地址 |
|
||||
|------|-----|------|------|--------------|
|
||||
| 小型宝塔 | 42.194.232.22 | 2核4G 5M | 主力部署(Node 项目) | https://42.194.232.22:9988/ckbpanel |
|
||||
| 存客宝 | 42.194.245.239 | 2核16G 50M | 私域银行业务 | https://42.194.245.239:9988 |
|
||||
| kr宝塔 | 43.139.27.93 | 2核4G 5M | 辅助服务器 | https://43.139.27.93:9988 |
|
||||
| kr宝塔 | 43.139.27.93 | 2核4G 5M | Node 项目主力 | https://43.139.27.93:9988 |
|
||||
|
||||
### SSH 登录(root)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| 密码(通用) | `Zhiqun1984` |
|
||||
| 示例 | `ssh root@42.194.232.22` |
|
||||
| 示例(kr宝塔) | `ssh -p 22022 root@43.139.27.93` |
|
||||
|
||||
### 宝塔面板登录(小型宝塔为例)
|
||||
### 宝塔面板登录(kr宝塔为例)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| 地址 | https://42.194.232.22:9988/ckbpanel |
|
||||
| 地址 | https://43.139.27.93:9988 |
|
||||
| 账号 | `ckb` |
|
||||
| 密码 | `zhiqun1984` |
|
||||
|
||||
@@ -158,7 +157,6 @@
|
||||
|
||||
| 服务器 | API 密钥 |
|
||||
|--------|----------|
|
||||
| 小型宝塔 | `hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd` |
|
||||
| 存客宝 | `TNKjqDv5N1QLOU20gcmGVgr82Z4mXzRi` |
|
||||
| kr宝塔 | `qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT` |
|
||||
|
||||
|
||||
@@ -38,3 +38,4 @@
|
||||
| 2026-02-19 19:40:16 | 🔄 卡若AI 同步 2026-02-19 19:40 | 更新:金仓、水桥平台对接、运营中枢工作台 | 排除 >20MB: 5 个 |
|
||||
| 2026-02-19 20:11:22 | 🔄 卡若AI 同步 2026-02-19 20:11 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 |
|
||||
| 2026-02-20 07:09:16 | 🔄 卡若AI 同步 2026-02-20 07:09 | 更新:金仓、水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 5 个 |
|
||||
| 2026-02-20 07:15:11 | 🔄 卡若AI 同步 2026-02-20 07:15 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 |
|
||||
|
||||
@@ -41,3 +41,4 @@
|
||||
| 2026-02-19 19:40:16 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-19 19:40 | 更新:金仓、水桥平台对接、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-02-19 20:11:22 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-19 20:11 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-02-20 07:09:16 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-20 07:09 | 更新:金仓、水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-02-20 07:15:11 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-20 07:15 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
| 项目 | 配置 | 说明 |
|
||||
|------|------|------|
|
||||
| **CPU** | 2 核 | 与小型宝塔、kr宝塔同规格,算力适中 |
|
||||
| **CPU** | 2 核 | 与 kr宝塔同规格,算力适中 |
|
||||
| **内存** | 16 GB | 三台宝塔中最高,适合跑数据库与多应用 |
|
||||
| **系统盘** | 以控制台/实际挂载为准 | 建议保留 ≥20% 可用空间 |
|
||||
| **操作系统** | 以宝塔/镜像为准 | 常见为 CentOS 7/8 或 TencentOS |
|
||||
@@ -35,7 +35,7 @@
|
||||
| **带宽类型** | 以腾讯云控制台为准 | 可能为包月或按量,影响计费 |
|
||||
| **内网 IP** | 以实例详情为准 | 同地域 CVM 互通走内网 |
|
||||
|
||||
- **与另两台对比**:小型宝塔、kr宝塔均为 5M;存客宝 50M 带宽单价与流量成本明显更高,是消费与优化重点。
|
||||
- **与 kr宝塔对比**:kr宝塔 5M;存客宝 50M 带宽单价与流量成本明显更高,是消费与优化重点。
|
||||
|
||||
### 1.4 宝塔与访问
|
||||
|
||||
|
||||
@@ -39,9 +39,8 @@ python3 "01_卡资(金)/金仓_存储备份/服务器管理/scripts/tencent_
|
||||
|
||||
| 服务器 | IP | 配置 | 带宽 | 用途 |
|
||||
|----------|----------------|-------------|------|----------------|
|
||||
| 小型宝塔 | 42.194.232.22 | 2核4G 5M | 5M | 主力 Node 部署 |
|
||||
| **存客宝** | **42.194.245.239** | **2核16G 50M** | **50M** | **私域银行业务** |
|
||||
| kr宝塔 | 43.139.27.93 | 2核4G 5M | 5M | 辅助/网关 |
|
||||
| kr宝塔 | 43.139.27.93 | 2核4G 5M | 5M | Node 项目/网关 |
|
||||
|
||||
- **存客宝** 是 **50M 带宽**,带宽费或按量流量费通常比 5M 机器高很多,是消费重点排查对象。
|
||||
- 流量/带宽使用情况:
|
||||
@@ -61,7 +60,7 @@ python3 "01_卡资(金)/金仓_存储备份/服务器管理/scripts/tencent_
|
||||
- **建议**:在腾讯云「费用」里看「按产品」明细,重点看「云服务器」「公网网络」;必要时设流量/费用告警。
|
||||
|
||||
3. **多台机器同时跑**
|
||||
- 三台(小型宝塔、存客宝、kr宝塔)都在腾讯云时,月费叠加。存客宝配置最高,通常占比最大。
|
||||
- 两台(存客宝、kr宝塔)都在腾讯云时,月费叠加。存客宝配置最高,通常占比最大。
|
||||
- **建议**:在账单里按实例/项目拆分,确认是哪台、哪项消费涨了。
|
||||
|
||||
4. **新业务或活动**
|
||||
@@ -93,7 +92,7 @@ python3 "01_卡资(金)/金仓_存储备份/服务器管理/scripts/tencent_
|
||||
|
||||
### 5.2 本机已执行的检查(当前结果)
|
||||
|
||||
- **快速检查三台宝塔**:已执行 `脚本/快速检查服务器.py`。结果:小型宝塔 API 连接异常;存客宝、kr宝塔 返回 **IP校验失败**(当前本机 IP 未加入宝塔 API 白名单)。
|
||||
- **快速检查两台宝塔**:已执行 `脚本/快速检查服务器.py`。结果:存客宝、kr宝塔 返回 **IP校验失败**(当前本机 IP 未加入宝塔 API 白名单)。
|
||||
- **SSH 存客宝**:已用 `sshpass` 尝试,连接仍被服务器关闭(可能已禁用密码登录、仅允许密钥或安全策略限制),需你在可登录的环境执行下方命令。
|
||||
|
||||
### 5.3 你需要直接执行的命令(按顺序做)
|
||||
|
||||
Reference in New Issue
Block a user