🔄 卡若AI 同步 2026-02-20 17:38 | 更新:金仓、水桥平台对接、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 5 个

This commit is contained in:
2026-02-20 17:38:36 +08:00
parent 63d2b15ad3
commit a8e3511393
26 changed files with 1204 additions and 161 deletions

View File

@@ -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离线需本地检查 |

View File

@@ -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 扫码绑定(需先修复镜像拉取)

View File

@@ -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": ""},
]

View File

@@ -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"},

View File

@@ -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,19 +35,18 @@ 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
存客宝: 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
| 端口 | 项目名 | 类型 | 域名 | 状态 |
|------|--------|------|------|------|

View File

@@ -8,50 +8,7 @@
| 用途 | 端口 | 说明 |
|----------|-------|------|
| 宝塔面板 | 9988 | 三台宝塔统一 |
| SSHkr宝塔/存客宝) | 22022 或 22 | 小型宝塔已改为 22022kr宝塔 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 | 通配符证书 |
---
| SSHkr宝塔/存客宝) | 22022 或 22 | kr宝塔 SSH=22022 |
## kr宝塔 (43.139.27.93)

View File

@@ -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"

View File

@@ -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. 找到 {项目名称},点击【重启】")

View File

@@ -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"

View File

@@ -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",
}

View File

@@ -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` | 本机→NASmacOS VM 流畅度优化 | `./scripts/` | 需本机与 NAS 同网 |
| `optimize_macos_vm_on_nas.sh` | **NAS 上直接执行**macOS VM 流畅度优化(外网推荐) | `./scripts/` | SSH 登录 NAS 后运行 |
| `nas_status.sh` | 一键检查NAS状态内存/磁盘/容器/端口) | `./scripts/` | `./scripts/nas_status.sh` |

View 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」"

View File

@@ -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 列指标名、各列为日期/场次,数据写入该场次列的第 312 行(竖列) |
| **主题** | 从聊天/TXT 提炼,**≤12 字**含干货与数值 |
| **按日期列** | 表头第 1 行为日期 1、2…19、20…该场对应日期如 2月20日则填在「20」列下 |
| **竖列写入** | A 列为指标名,数据写入该日期/场次列的第 312 行 |
### 一键写入
---
```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规范、四象限分类、**写入完成后自动打开飞书日志页面**、**运营报表子技能(截图→填表→发群竖状格式、会议纪要图片上传、月度统计)**

View File

@@ -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"
}

View 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()

View 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_imagebody 为 JSONimage 为整数数组(字节流)。
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()

View File

@@ -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):

View File

@@ -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": [
"算力矩阵先摸清资产与安全,再规模化;家宽降并发可跑完全程",

View 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…该场对应几号就填在几号列下
- 数据竖列写入该列第 312 行
---
## 三、脚本与命令
| 脚本 | 用途 |
|:---|:---|
| `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`

View File

@@ -0,0 +1,85 @@
# iPhone 12 当 Mac 扩展屏 — 操作指南
> 苹果官方「随航」仅支持 iPad本指南通过**第三方软件**让 iPhone 12 成为 Mac 的扩展屏。
> 适用MacBookIntel / Apple Silicon+ iPhone 12同一 WiFi 或 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」** 安装(付费应用,约 6898 元一次性,或含 Pro 订阅)。 |
### 2. 连接与权限(首次必做)
1. **数据线连接**(推荐,延迟最低):用 **Lightning 转 USB** 线把 iPhone 12 连到 Mac。
2. **Mac 上**:打开 Duet菜单栏出现 Duet 图标;若提示「添加助手」或信任设备,按提示在 **iPhone 上输入锁屏密码** 完成配对。
3. **授予权限**
**系统设置 → 隐私与安全性 → 辅助功能** → 勾选 **Duet**(或 Duet Display
若系统要求「屏幕录制」也勾选 Duet。
4. **无线用法**(可选):同一 WiFi 下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 在同一 WiFi 下两端打开应用即可配对iPhone 作为扩展屏。
-**系统设置 → 显示器** 中排列两块屏的位置,即可把窗口拖到 iPhone 上。
### 3. 注意
- 无线模式下延迟和画质会随网络波动;需要稳定体验建议用 USB 有线。
---
## 方案对比(简要)
| 项目 | Duet Display | Yam Display / Yam Air |
|------|--------------|------------------------|
| iPhone 支持 | ✅ 支持 | ✅ 支持 |
| 价格 | iOS 约 6898 元起,可选 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 扩展屏使用。*

View 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
│ 💡 反思13 点) │
│ 📝 总结 │
│ ▶ 下一步执行(含未完成/待跟进项,无则写「无」) │
└─────────────────────────────────────────────────────────────────────────┘
你:收到完整回复(结果 + 复盘)
```
---
## 四、对照表:执行流程 ↔ 对话中的呈现
| 内部执行步骤 | 在与你对话中的呈现 |
|--------------|--------------------|
| 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` | 统一流程简要索引 |

View File

@@ -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` |

View File

@@ -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 个 |

View File

@@ -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) |

View File

@@ -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 宝塔与访问

View File

@@ -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 你需要直接执行的命令(按顺序做)