🔄 卡若AI 同步 2026-03-20 16:08 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"access_token": "u-e_yzrY5Mh5eF_.Y8PKbaMtlh14HxghqpWMGaIQ40235J",
|
||||
"refresh_token": "ur-ew8WjjPF9e1HoSim4iMK8Qlh1A11ghOpq0GaZwg0260F",
|
||||
"access_token": "u-dFTTY7qHFbSHNUsIRa4NqClh1ez1ghohVMGaZxk0274E",
|
||||
"refresh_token": "ur-ePrUCxaTV8ipHNjZ.XICSYlh3A11ghOjr0GaVwk0271J",
|
||||
"name": "飞书用户",
|
||||
"auth_time": "2026-03-20T11:02:06.903826"
|
||||
}
|
||||
@@ -98,6 +98,7 @@ TEAM_MEETING_LINKS = {
|
||||
'124': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcne7k3msifq',
|
||||
'126': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcng991jg3114b2nj99548d',
|
||||
'127': 'https://cunkebao.feishu.cn/minutes/obcnhxs8usi8c7n27a9f66ux',
|
||||
'129': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjbn178iy6919od4119ww',
|
||||
}
|
||||
|
||||
# 小程序当日运营数据:日期号 → {访问次数, 访客, 交易金额},填表时自动写入对应日期列
|
||||
@@ -410,12 +411,15 @@ def main():
|
||||
print('❌ 无法获取飞书 Token,请先运行 auto_log.py 完成授权')
|
||||
sys.exit(1)
|
||||
raw = (row + [None] * EFFECT_COLS)[:EFFECT_COLS]
|
||||
# 推流人数(索引2,表格第5行)为 0 或 None 时留空不填,有数值才填
|
||||
# 推流人数(索引2,表格第5行)为 0 或 None 时跳过不填,保留原值
|
||||
# 注意:values数组长度必须保持EFFECT_COLS,但推流人数位置写入时需跳过
|
||||
def _cell(i):
|
||||
if i == 2 and (raw[i] == 0 or raw[i] is None):
|
||||
return ''
|
||||
return None # 返回None表示跳过该列,不覆盖原有值
|
||||
return _to_cell_value(raw[i])
|
||||
values = [_cell(i) for i in range(EFFECT_COLS)]
|
||||
# 记录推流人数位置,写入时跳过
|
||||
skip_push_index = 2 if (raw[2] == 0 or raw[2] is None) else None
|
||||
spreadsheet_token = WIKI_NODE_OR_SPREADSHEET_TOKEN
|
||||
month = SESSION_MONTH.get(session, 2)
|
||||
sheet_id = get_sheet_id_by_month(token, spreadsheet_token, month)
|
||||
@@ -494,14 +498,48 @@ def main():
|
||||
|
||||
if target_col_0based is not None:
|
||||
col_letter = _col_letter(target_col_0based)
|
||||
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 == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
if token:
|
||||
code, body = update_sheet_range(token, spreadsheet_token, range_col, values_vertical)
|
||||
if code == 200 and body.get('code') == 0:
|
||||
# 推流人数为None时,使用逐格写入方式,跳过推流人数行(保留原值)
|
||||
if skip_push_index is not None:
|
||||
# 使用逐格写入,跳过推流人数行
|
||||
all_ok = True
|
||||
for r in range(3, 3 + len(values)):
|
||||
val_idx = r - 3
|
||||
if val_idx == skip_push_index:
|
||||
continue # 跳过推流人数行,保留原值
|
||||
one_cell = f"{sheet_id}!{col_letter}{r}"
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[val_idx]]])
|
||||
if code != 200 or body.get('code') not in (0, None):
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
if token:
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[val_idx]]])
|
||||
if code != 200 or body.get('code') not in (0, None):
|
||||
all_ok = False
|
||||
print('❌ 写入单元格失败:', one_cell, code, body)
|
||||
break
|
||||
if all_ok:
|
||||
ok, msg = _verify_write(spreadsheet_token, sheet_id, col_letter, values, token)
|
||||
if ok:
|
||||
print(f'✅ 已写入飞书表格:{session}场 效果数据(竖列 {col_letter} 逐格,推流人数保留原值),校验通过')
|
||||
_write_session_label(token, spreadsheet_token, sheet_id, col_letter, session)
|
||||
_write_miniprogram_extra(token, spreadsheet_token, sheet_id, vals, date_col, col_letter, month=month)
|
||||
_write_party_video_link(token, spreadsheet_token, sheet_id, vals, col_letter, session)
|
||||
_write_team_meeting_link(token, spreadsheet_token, sheet_id, vals, col_letter, session)
|
||||
_maybe_send_group(session, raw)
|
||||
return
|
||||
print(f'⚠️ 逐格写入成功但校验未通过:{msg}')
|
||||
else:
|
||||
print('❌ 逐格写入失败')
|
||||
else:
|
||||
# 推流人数有值,使用批量写入
|
||||
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 == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
if token:
|
||||
code, body = update_sheet_range(token, spreadsheet_token, range_col, values_vertical)
|
||||
if code == 200 and body.get('code') == 0:
|
||||
ok, msg = _verify_write(spreadsheet_token, sheet_id, col_letter, values, token)
|
||||
if ok:
|
||||
print(f'✅ 已写入飞书表格:{session}场 效果数据(竖列 {col_letter}3:{col_letter}{2+len(values)},共{len(values)}格),校验通过')
|
||||
@@ -516,13 +554,17 @@ def main():
|
||||
if err == 90202 or (err and 'range' in str(body.get('msg', '')).lower()):
|
||||
all_ok = True
|
||||
for r in range(3, 3 + len(values)):
|
||||
val_idx = r - 3
|
||||
# 推流人数(索引2,行号5)为None时跳过写入,保留原值
|
||||
if val_idx == skip_push_index and values[val_idx] is None:
|
||||
continue
|
||||
one_cell = f"{sheet_id}!{col_letter}{r}"
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[r - 3]]])
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[val_idx]]])
|
||||
if code != 200 or body.get('code') not in (0, None):
|
||||
if code == 401 or body.get('code') in (99991677, 99991663):
|
||||
token = refresh_and_load_token()
|
||||
if token:
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[r - 3]]])
|
||||
code, body = update_sheet_range(token, spreadsheet_token, one_cell, [[values[val_idx]]])
|
||||
if code != 200 or body.get('code') not in (0, None):
|
||||
all_ok = False
|
||||
print('❌ 写入单元格失败:', one_cell, code, body)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
name: 视频切片
|
||||
description: Soul派对视频切片 + 快速混剪 + 切片动效包装(片头/片尾/程序化)+ 剪映思路借鉴(智能剪口播/镜头分割)。触发词含视频剪辑、切片发布、快速混剪、切片动效包装、程序化包装、片头片尾。
|
||||
group: 木
|
||||
triggers: 视频剪辑、切片发布、字幕烧录、**快速混剪、混剪预告、快剪串联、切片动效包装、程序化包装、片头片尾、批量封面、视频包装**、镜头切分、场景检测
|
||||
triggers: 视频剪辑、切片发布、字幕烧录、全画面标定、竖屏裁剪、飞书录屏白边、**快速混剪、混剪预告、快剪串联、切片动效包装、程序化包装、片头片尾、批量封面、视频包装**、镜头切分、场景检测
|
||||
owner: 木叶
|
||||
version: "1.3"
|
||||
updated: "2026-03-03"
|
||||
version: "1.4"
|
||||
updated: "2026-03-20"
|
||||
---
|
||||
|
||||
# 视频切片
|
||||
@@ -128,22 +128,40 @@ python3 soul_enhance.py -c clips/ -l highlights_from_chapter.json -t transcript.
|
||||
|
||||
- **主题来源**:章节 .md 按 `---` 分块,每块一个主题;文件名由 batch_clip 按 `前缀_序号_标题` 生成(标题仅保留中文与安全字符)。
|
||||
|
||||
### Soul 竖屏成片(横版源 → 竖屏中段去白边)
|
||||
### Soul 竖屏成片(横版源 → 全画面标定竖条)
|
||||
|
||||
**约定**:以后剪辑 Soul 视频,成片统一做「竖屏中段」裁剪:横版 1920×1080 只保留中间竖条并去掉左右白边,输出 498×1080 竖屏。
|
||||
**约定**:成片统一 **498×1080**。裁剪参数必须以 **1920×1080 全画面** 为准标定,避免右侧吃进飞书/桌面**白底**,并保证**整段深色小程序界面**完整入画。
|
||||
|
||||
#### 全画面参数(当前默认,与 `soul_enhance.py` / `soul_vertical_crop.py` 一致)
|
||||
|
||||
| 步骤 | 说明 |
|
||||
|------|------|
|
||||
| 源 | 横版 1920×1080(soul_enhance 输出) |
|
||||
| 1 | 取竖条 608×1080,起点 **x=483**(相对画面左) |
|
||||
| 2 | 裁掉左侧白边 60px、右侧白边 50px → 内容区宽 498 |
|
||||
| 输出 | **498×1080** 竖屏,仅内容窗口 |
|
||||
| 源 | 横版 1920×1080(封面字幕叠在横版上,最后再裁竖屏) |
|
||||
| 0(标定) | 对原片按时长 **20%**(或 50%)截 **全画面** JPG,用脚本算深色区左右界(见下) |
|
||||
| 1 | `crop=568:1080:508:0`:取**最长连续深色列**对应竖条(本场约 x∈[508,1076),不含右侧白边) |
|
||||
| 2 | `crop=498:1080:35:0`:在 **568 宽内水平居中**取 498,界面左右都保留 |
|
||||
| 叠加 | 横版上封面/字幕 **x=543**(508+35,与旧链 483+60 对齐,避免错位) |
|
||||
| 输出 | **498×1080** 竖屏 |
|
||||
|
||||
**每场若窗口位置变了**,不要用猜的 x;先截全画面再跑:
|
||||
|
||||
```bash
|
||||
cd 03_卡木(木)/木叶_视频内容/视频切片/脚本
|
||||
# 全画面截图 或 原片自动抽帧
|
||||
python3 analyze_feishu_ui_crop.py "/path/to/全画面.jpg"
|
||||
# 或
|
||||
python3 analyze_feishu_ui_crop.py "/path/to/原片.mp4" --at 0.2
|
||||
```
|
||||
|
||||
将输出的 `CROP_VF` 传给:`python3 soul_enhance.py ... --vertical --crop-vf '...'`(`OVERLAY_X` 脚本会一并打印;也可用 `--overlay-x` 覆盖)。
|
||||
|
||||
详见:`参考资料/竖屏中段裁剪参数说明.md`、`脚本/analyze_feishu_ui_crop.py`。
|
||||
|
||||
**FFmpeg 一条命令(固定参数):**
|
||||
|
||||
```bash
|
||||
# 单文件。输入为 1920×1080 的 enhanced 成片
|
||||
ffmpeg -y -i "输入_enhanced.mp4" -vf "crop=608:1080:483:0,crop=498:1080:60:0" -c:a copy "输出_竖屏中段.mp4"
|
||||
ffmpeg -y -i "输入_enhanced.mp4" -vf "crop=568:1080:508:0,crop=498:1080:35:0" -c:a copy "输出_竖屏中段.mp4"
|
||||
```
|
||||
|
||||
**批量对某目录下所有 \*_enhanced.mp4 做竖屏中段:**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
name: Soul竖屏切片
|
||||
description: Soul 派对视频→竖屏成片(498×1080),剪辑→成片两文件夹,MLX 转录→高光识别→batch_clip→soul_enhance(封面+动态字幕同步+去语助词+纠错+违禁词)→visual_enhance v8(苹果毛玻璃浮层+Logo+场次号+段落总结)。可选 LTX AI 生成内容/Retake 重剪。支持基因胶囊打包。
|
||||
triggers: Soul竖屏切片、视频切片、热点切片、竖屏成片、派对切片、LTX、AI生成视频、Retake重剪、字幕优化、字幕同步
|
||||
description: Soul 派对视频→竖屏成片(498×1080),剪辑→成片两文件夹;竖屏裁剪以全画面 1920×1080 标定(analyze_feishu_ui_crop.py),默认深色带 crop=568@508+居中498、无右侧白边。MLX 转录→高光→batch_clip→soul_enhance(封面+字幕同步+逐字可选+去语助词+纠错+违禁词)→visual_enhance v8 可选。LTX/基因胶囊可选。
|
||||
triggers: Soul竖屏切片、视频切片、热点切片、竖屏成片、派对切片、全画面标定、竖屏裁剪、白边、飞书录屏、LTX、AI生成视频、Retake重剪、字幕优化、字幕同步、逐字字幕
|
||||
owner: 木叶
|
||||
group: 木
|
||||
version: "1.3"
|
||||
updated: "2026-03-13"
|
||||
version: "1.4"
|
||||
updated: "2026-03-20"
|
||||
---
|
||||
|
||||
# Soul 竖屏切片 · 专用 Skill
|
||||
@@ -46,6 +46,24 @@ updated: "2026-03-13"
|
||||
- **batch_clip**:输出到 `clips/`
|
||||
- **soul_enhance -o 成片/ --vertical --title-only**:**文件名 = 封面标题 = highlights 的 title**(去杠:`:|、—、/` 等替换为空格),名字与标题一致、无序号无杠;字幕烧录(随语音走动);完整去语助词;竖屏裁剪直出到 `成片/`
|
||||
|
||||
### 3.1 全画面参数(必做约定)
|
||||
|
||||
竖屏 **裁剪链必须以全画面 1920×1080 为基准**,不能用「凭感觉收窄竖条」替代。
|
||||
|
||||
1. **为什么要全画面标定**:飞书录屏右侧常为**桌面白底**;旧式固定 `483+608` 会裁到白边。正确做法是:在全画面上找**小程序深色主体的左右边界**,先取**整段宽 W**,再在 W 内**居中**裁 498。
|
||||
2. **当前默认**(`soul_enhance.py` 内建):`crop=568:1080:508:0,crop=498:1080:35:0`,`OVERLAY_X=543`。与 `analyze_feishu_ui_crop.py` 对 **127 场全画面 20% 帧** 测算一致。
|
||||
3. **新场次 / 布局变了**:截一帧全画面(或 `--at 0.2` 从 mp4 抽帧),执行:
|
||||
|
||||
```bash
|
||||
cd 脚本
|
||||
python3 analyze_feishu_ui_crop.py "/path/to/全画面.jpg"
|
||||
# 或 python3 analyze_feishu_ui_crop.py "/path/to/原片.mp4" --at 0.2
|
||||
```
|
||||
|
||||
把打印的 `CROP_VF` 传给成片命令:`--crop-vf 'crop=...'`(可选 `--overlay-x` 与脚本输出一致)。
|
||||
|
||||
4. **逐字渐显字幕**(可选):`--typewriter-subs`,同一条字幕时间内前缀逐字加长,更跟读。
|
||||
|
||||
---
|
||||
|
||||
## 四、高光与切片(30 秒~300 秒)
|
||||
@@ -84,8 +102,8 @@ updated: "2026-03-13"
|
||||
|
||||
| 步骤 | 滤镜 |
|
||||
|------|------|
|
||||
| 1 | crop=608:1080:483:0 |
|
||||
| 2 | crop=498:1080:60:0 |
|
||||
| 1 | crop=568:1080:508:0(整段深色小程序主体,不含右侧桌面白边) |
|
||||
| 2 | crop=498:1080:35:0(568 内水平居中取 498) |
|
||||
|
||||
**输出**:498×1080 竖屏。
|
||||
|
||||
@@ -103,6 +121,8 @@ python3 batch_clip.py -i "原视频.mp4" -l highlights.json -o clips/ -p soul112
|
||||
**3. 成片(竖屏+封面+字幕+去语助词,直出到 成片/)**
|
||||
```bash
|
||||
python3 soul_enhance.py -c clips/ -l highlights.json -t transcript.srt -o 成片/ --vertical --title-only --force-burn-subs
|
||||
# 可选:逐字字幕 + 本场全画面重算的裁剪(见 3.1)
|
||||
python3 soul_enhance.py -c clips/ -l highlights.json -t transcript.srt -o 成片/ --vertical --title-only --force-burn-subs --typewriter-subs --crop-vf "crop=568:1080:508:0,crop=498:1080:35:0"
|
||||
```
|
||||
|
||||
**前缀命名注意**:`-p soul119` 这类带场次号的前缀会产生 `soul119_01_xxx.mp4`,`soul_enhance` 会正确识别 `01` 为切片序号(取所有 `_数字_` 中最小值)。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Soul 竖屏中段裁剪参数说明
|
||||
|
||||
> 与 **视频切片** Skill「Soul 竖屏成片」一致,以后剪辑 Soul 视频统一用此参数。
|
||||
> 与 **视频切片 / Soul竖屏切片** Skill 一致。**参数来源**:以 **全画面**(1920×1080)截帧做列亮度分析(`脚本/analyze_feishu_ui_crop.py`),取最长深色列区间为第一步 `crop` 宽度,再居中裁 498;下列数值为当前飞书+小程序布局下的默认结果。
|
||||
|
||||
## 源与输出
|
||||
|
||||
@@ -8,18 +8,22 @@
|
||||
- **需求**:保留画面中间竖条(手机内容区),去左右白边
|
||||
- **输出**:**498×1080** 竖屏
|
||||
|
||||
## 当前固定参数(已微调)
|
||||
## 当前固定参数(2026-03-20 起:白边修正)
|
||||
|
||||
飞书横屏录屏里,小程序**深色区域**右缘外常为桌面白底。应用 **整段深色宽度** 再居中裁 498,避免右侧露白。
|
||||
|
||||
| 步骤 | 滤镜 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | crop=608:1080:483:0 | 从横版取竖条 608 宽,起点 x=483 |
|
||||
| 2 | crop=498:1080:60:0 | 裁掉左侧白边 60px、右侧 50px,内容宽 498 |
|
||||
| 输出 | 498×1080 | 仅内容窗口 |
|
||||
| 1 | crop=568:1080:508:0 | 取深色主体竖条(宽约 568,起点 x=508,止于约 1076,不含右侧白区) |
|
||||
| 2 | crop=498:1080:35:0 | 在 568 内水平居中取 498 |
|
||||
| 输出 | 498×1080 | 完整界面入画、左右无桌面白边 |
|
||||
|
||||
**校验**:对原片按时长 **20%** 截一帧全画面,用脚本 `脚本/analyze_feishu_ui_crop.py` 可对任意场次重算 `crop`(布局变化时)。
|
||||
|
||||
**一条命令:**
|
||||
|
||||
```bash
|
||||
ffmpeg -y -i "输入_enhanced.mp4" -vf "crop=608:1080:483:0,crop=498:1080:60:0" -c:a copy "输出_竖屏中段.mp4"
|
||||
ffmpeg -y -i "输入_enhanced.mp4" -vf "crop=568:1080:508:0,crop=498:1080:35:0" -c:a copy "输出_竖屏中段.mp4"
|
||||
```
|
||||
|
||||
**批量:** 使用 `脚本/soul_vertical_crop.py --dir clips_enhanced目录`。加 `--title-only` 时输出文件名为纯标题(无序号、无「竖屏中段」)。
|
||||
|
||||
121
03_卡木(木)/木叶_视频内容/视频切片/脚本/analyze_feishu_ui_crop.py
Executable file
121
03_卡木(木)/木叶_视频内容/视频切片/脚本/analyze_feishu_ui_crop.py
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
从飞书/Soul 录屏的一帧全画面(1920×1080)估计「深色小程序主体」左右边界,
|
||||
输出两段 crop + overlay_x,保证界面整段入画、尽量不夹右侧白底。
|
||||
|
||||
用法:
|
||||
python3 analyze_feishu_ui_crop.py /path/to/frame.jpg
|
||||
python3 analyze_feishu_ui_crop.py /path/to/video.mp4 --at 0.2
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def load_frame(path: Path, at_ratio: float | None) -> np.ndarray:
|
||||
path = path.resolve()
|
||||
if path.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp"}:
|
||||
return np.asarray(Image.open(path).convert("RGB"), dtype=np.float32)
|
||||
if at_ratio is None:
|
||||
at_ratio = 0.2
|
||||
dur = float(
|
||||
subprocess.check_output(
|
||||
[
|
||||
"ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
str(path),
|
||||
],
|
||||
text=True,
|
||||
).strip()
|
||||
)
|
||||
t = max(0.0, dur * at_ratio)
|
||||
raw = subprocess.check_output(
|
||||
[
|
||||
"ffmpeg",
|
||||
"-v",
|
||||
"error",
|
||||
"-ss",
|
||||
f"{t:.3f}",
|
||||
"-i",
|
||||
str(path),
|
||||
"-frames:v",
|
||||
"1",
|
||||
"-f",
|
||||
"image2pipe",
|
||||
"-vcodec",
|
||||
"png",
|
||||
"-",
|
||||
]
|
||||
)
|
||||
from io import BytesIO
|
||||
|
||||
return np.asarray(Image.open(BytesIO(raw)).convert("RGB"), dtype=np.float32)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("input", type=Path, help="全画面截图 jpg/png 或视频 mp4")
|
||||
ap.add_argument("--at", type=float, default=None, help="视频取样比例 0~1,默认 0.2")
|
||||
args = ap.parse_args()
|
||||
|
||||
arr = load_frame(args.input, args.at)
|
||||
h, w, _ = arr.shape
|
||||
gray = 0.299 * arr[:, :, 0] + 0.587 * arr[:, :, 1] + 0.114 * arr[:, :, 2]
|
||||
col_mean = gray.mean(axis=0)
|
||||
|
||||
win = 31
|
||||
pad = win // 2
|
||||
kernel = np.ones(win) / win
|
||||
smooth = np.convolve(np.pad(col_mean, (pad, pad), mode="edge"), kernel, mode="valid")
|
||||
|
||||
dark = smooth < 105
|
||||
best = (0, 0)
|
||||
i = 0
|
||||
while i < w:
|
||||
if not dark[i]:
|
||||
i += 1
|
||||
continue
|
||||
j = i
|
||||
while j < w and dark[j]:
|
||||
j += 1
|
||||
if j - i > best[1] - best[0]:
|
||||
best = (i, j)
|
||||
i = j
|
||||
L0, R0 = best
|
||||
if R0 - L0 < 200:
|
||||
print("未找到足够宽的深色带,请换一帧或检查分辨率", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 右缘:深色带结束后出现的持续高亮(白底)
|
||||
right = R0
|
||||
for x in range(R0, min(R0 + 500, w)):
|
||||
if smooth[x] > 195 and col_mean[x] > 200 and x + 5 < w and smooth[x : x + 5].min() > 185:
|
||||
right = x
|
||||
break
|
||||
|
||||
# 严格包络:只用最长深色块 [L0,R0),避免把右侧灰白过渡算进画面(用户要求无白边)
|
||||
L = max(0, L0)
|
||||
W_strict = R0 - L0
|
||||
if W_strict < 498:
|
||||
print(f"深色带宽度 {W_strict} < 498,需 scale 或换源", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
inner = (W_strict - 498) // 2
|
||||
ox = L + inner
|
||||
vf = f"crop={W_strict}:1080:{L}:0,crop=498:1080:{inner}:0"
|
||||
print(f"# {w}x{h} 最长深色列区间 [{L0},{R0}) 宽={W_strict};白底高亮约从 x>={right} 起")
|
||||
print(f"CROP_VF={vf!r}")
|
||||
print(f"OVERLAY_X={ox}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -57,10 +57,77 @@ SILENCE_THRESHOLD = -40 # 静音阈值(dB)
|
||||
SILENCE_MIN_DURATION = 0.5 # 最短静音时长(秒)
|
||||
|
||||
# Soul 竖屏裁剪(与 soul_vertical_crop 一致,成片直出用)
|
||||
CROP_VF = "crop=608:1080:483:0,crop=498:1080:60:0"
|
||||
# 竖屏成片时封面/字幕用此尺寸,叠在横版上的 x 位置(与 crop 后保留区域对齐)
|
||||
# 飞书录屏典型布局:深色小程序主体约在 x∈[508,1076],右缘外为桌面白底。
|
||||
# 旧参数 483+608=1091 会吃进右侧白边;现改为「整段深色界面入画 + 居中取 498」。
|
||||
CROP_VF = "crop=568:1080:508:0,crop=498:1080:35:0"
|
||||
# 竖屏成片时封面/字幕用此尺寸,叠在横版上的 x 位置(与 crop 后保留区域左缘一致)
|
||||
VERTICAL_W, VERTICAL_H = 498, 1080
|
||||
OVERLAY_X = 543 # 1920 下保留区域左缘:483+60
|
||||
OVERLAY_X = 543 # 508+35,与历史 483+60 对齐,避免封面/字幕错位
|
||||
|
||||
|
||||
def _overlay_x_from_crop_vf(crop_vf: str):
|
||||
"""从两段 crop 解析字幕/封面叠在横版上的 x:crop=W:1080:X:0,crop=498:1080:Y:0 → X+Y"""
|
||||
m = re.match(
|
||||
r"crop=\d+:1080:(\d+):0,crop=498:1080:(\d+):0",
|
||||
(crop_vf or "").strip().replace(" ", ""),
|
||||
)
|
||||
if m:
|
||||
return int(m.group(1)) + int(m.group(2))
|
||||
return None
|
||||
|
||||
|
||||
def build_typewriter_subtitle_images(
|
||||
subtitles,
|
||||
temp_dir,
|
||||
out_w,
|
||||
out_h,
|
||||
cover_duration,
|
||||
min_step_sec=0.05,
|
||||
max_steps_per_line=28,
|
||||
):
|
||||
"""
|
||||
将每条字幕拆成多帧:同一时间段内前缀逐字(逐段)变长,读起来更顺、更像跟读语音。
|
||||
长句按步数上限均分字符,避免单条 concat 段过多。
|
||||
"""
|
||||
sub_images = []
|
||||
img_idx = 0
|
||||
for sub in subtitles:
|
||||
safe_text = improve_subtitle_punctuation(sub["text"])
|
||||
if not safe_text or not safe_text.strip():
|
||||
continue
|
||||
s, e = float(sub["start"]), float(sub["end"])
|
||||
s = max(s, cover_duration)
|
||||
if s >= e - 0.02:
|
||||
continue
|
||||
dur = e - s
|
||||
chars = list(safe_text)
|
||||
n = len(chars)
|
||||
if n <= 1:
|
||||
img_path = os.path.join(temp_dir, f"sub_{img_idx:04d}.png")
|
||||
create_subtitle_image(safe_text, out_w, out_h, img_path)
|
||||
sub_images.append({"path": img_path, "start": s, "end": e})
|
||||
img_idx += 1
|
||||
continue
|
||||
# 步数:不超过 max_steps,且每步至少 min_step_sec(极短句仍保证可见)
|
||||
num_steps = min(max_steps_per_line, n)
|
||||
num_steps = max(2, num_steps)
|
||||
step_dur = dur / num_steps
|
||||
if step_dur < min_step_sec:
|
||||
num_steps = max(2, int(dur / min_step_sec))
|
||||
step_dur = dur / num_steps
|
||||
for step in range(1, num_steps + 1):
|
||||
end_char = max(1, int(round(n * step / num_steps)))
|
||||
end_char = min(end_char, n)
|
||||
partial = "".join(chars[:end_char])
|
||||
t0 = s + (step - 1) * step_dur
|
||||
t1 = s + step * step_dur if step < num_steps else e
|
||||
if t1 <= t0 + 0.001:
|
||||
continue
|
||||
img_path = os.path.join(temp_dir, f"sub_{img_idx:04d}.png")
|
||||
create_subtitle_image(partial, out_w, out_h, img_path)
|
||||
sub_images.append({"path": img_path, "start": t0, "end": t1})
|
||||
img_idx += 1
|
||||
return sub_images
|
||||
|
||||
# 繁转简(OpenCC 优先,否则用映射)
|
||||
_OPENCC = None
|
||||
@@ -1017,8 +1084,12 @@ def _parse_clip_index(filename: str) -> int:
|
||||
|
||||
|
||||
def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_path,
|
||||
force_burn_subs=False, skip_subs=False, vertical=False):
|
||||
"""增强单个切片。vertical=True 时最后裁成竖屏 498x1080 直出成片。"""
|
||||
force_burn_subs=False, skip_subs=False, vertical=False,
|
||||
crop_vf=None, overlay_x=None, typewriter_subs=False):
|
||||
"""增强单个切片。vertical=True 时最后裁成竖屏 498x1080 直出成片。
|
||||
crop_vf / overlay_x:场次取景微调(先截 20% 帧对一下小程序黑框再填)。
|
||||
typewriter_subs:同一条字幕时间内前缀逐字渐显(更跟口型)。
|
||||
"""
|
||||
|
||||
print(f" 输入: {os.path.basename(clip_path)}", flush=True)
|
||||
|
||||
@@ -1041,7 +1112,13 @@ def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_pa
|
||||
|
||||
# 竖屏成片:封面/字幕按 498x1080 做,叠在裁切区域,文字与字幕在竖屏上完整且居中
|
||||
out_w, out_h = (VERTICAL_W, VERTICAL_H) if vertical else (width, height)
|
||||
overlay_pos = f"{OVERLAY_X}:0" if vertical else "0:0"
|
||||
vf_use = (crop_vf or CROP_VF).strip() if vertical else CROP_VF
|
||||
ox = overlay_x
|
||||
if vertical and ox is None and crop_vf:
|
||||
ox = _overlay_x_from_crop_vf(crop_vf)
|
||||
if vertical and ox is None:
|
||||
ox = OVERLAY_X
|
||||
overlay_pos = f"{int(ox)}:0" if vertical else "0:0"
|
||||
|
||||
# 1. 生成封面
|
||||
print(f" [1/5] 封面生成中…", flush=True)
|
||||
@@ -1117,13 +1194,18 @@ def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_pa
|
||||
sys.stdout.flush()
|
||||
subtitles = []
|
||||
else:
|
||||
print(f" ✓ 字幕解析 ({len(subtitles)}条),将烧录为随语音走动的字幕", flush=True)
|
||||
for i, sub in enumerate(subtitles):
|
||||
img_path = os.path.join(temp_dir, f'sub_{i:04d}.png')
|
||||
# 应用违禁词替换 + 标点优化(让字幕更清晰、安全)
|
||||
safe_text = improve_subtitle_punctuation(sub['text'])
|
||||
create_subtitle_image(safe_text, out_w, out_h, img_path)
|
||||
sub_images.append({'path': img_path, 'start': sub['start'], 'end': sub['end']})
|
||||
mode = "逐字渐显" if typewriter_subs else "随语音走动"
|
||||
print(f" ✓ 字幕解析 ({len(subtitles)}条),将烧录为{mode}字幕", flush=True)
|
||||
if typewriter_subs:
|
||||
sub_images = build_typewriter_subtitle_images(
|
||||
subtitles, temp_dir, out_w, out_h, cover_duration
|
||||
)
|
||||
else:
|
||||
for i, sub in enumerate(subtitles):
|
||||
img_path = os.path.join(temp_dir, f'sub_{i:04d}.png')
|
||||
safe_text = improve_subtitle_punctuation(sub['text'])
|
||||
create_subtitle_image(safe_text, out_w, out_h, img_path)
|
||||
sub_images.append({'path': img_path, 'start': sub['start'], 'end': sub['end']})
|
||||
if sub_images:
|
||||
print(f" ✓ 字幕图片 ({len(sub_images)}张)", flush=True)
|
||||
|
||||
@@ -1250,7 +1332,7 @@ def enhance_clip(clip_path, output_path, highlight_info, temp_dir, transcript_pa
|
||||
if vertical:
|
||||
r = subprocess.run([
|
||||
'ffmpeg', '-y', '-i', current_video,
|
||||
'-vf', CROP_VF, '-c:a', 'copy', output_path
|
||||
'-vf', vf_use, '-c:a', 'copy', output_path
|
||||
], capture_output=True, text=True)
|
||||
if r.returncode == 0 and os.path.exists(output_path):
|
||||
print(f" ✓ 竖屏裁剪完成", flush=True)
|
||||
@@ -1280,6 +1362,22 @@ def main():
|
||||
parser.add_argument("--title-only", action="store_true", help="输出文件名为纯标题(无序号、无_enhanced),与 --vertical 搭配用于成片")
|
||||
parser.add_argument("--skip-subs", action="store_true", help="跳过字幕烧录(原片已有字幕时用)")
|
||||
parser.add_argument("--force-burn-subs", action="store_true", help="强制烧录字幕(忽略检测)")
|
||||
parser.add_argument(
|
||||
"--crop-vf",
|
||||
default="",
|
||||
help="竖屏时覆盖裁剪链,如 crop=560:1080:465:0,crop=498:1080:31:0(先对原片 20%% 时长处截帧对齐小程序黑框)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--overlay-x",
|
||||
type=int,
|
||||
default=-1,
|
||||
help="竖屏时封面/字幕在 1920 横版上的叠加 x;默认 -1 表示用全局或从 --crop-vf 解析",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--typewriter-subs",
|
||||
action="store_true",
|
||||
help="字幕在同一条时间内前缀逐字渐显(更通顺、更跟读)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
clips_dir = Path(args.clips) if args.clips else CLIPS_DIR
|
||||
@@ -1302,7 +1400,17 @@ def main():
|
||||
print("="*60)
|
||||
print("🎬 Soul切片增强" + ("(成片竖屏直出)" if vertical else ""))
|
||||
print("="*60)
|
||||
print(f"功能: 封面+字幕+加速10%+去语气词" + ("+竖屏498x1080" if vertical else ""))
|
||||
crop_vf_arg = (getattr(args, "crop_vf", "") or "").strip()
|
||||
overlay_x_arg = getattr(args, "overlay_x", -1)
|
||||
overlay_x_arg = None if overlay_x_arg < 0 else overlay_x_arg
|
||||
typewriter = getattr(args, "typewriter_subs", False)
|
||||
print(
|
||||
f"功能: 封面+字幕+加速10%+去语气词"
|
||||
+ ("+竖屏498x1080" if vertical else "")
|
||||
+ ("+逐字字幕" if typewriter else "")
|
||||
)
|
||||
if vertical and crop_vf_arg:
|
||||
print(f"取景: --crop-vf {crop_vf_arg}")
|
||||
print(f"输入: {clips_dir}")
|
||||
print(f"输出: {output_dir}" + ("(成片,文件名=标题)" if title_only else ""))
|
||||
print("="*60)
|
||||
@@ -1338,10 +1446,19 @@ def main():
|
||||
|
||||
temp_dir = tempfile.mkdtemp(prefix='enhance_')
|
||||
try:
|
||||
if enhance_clip(str(clip_path), str(output_path), highlight_info, temp_dir, str(transcript_path),
|
||||
force_burn_subs=getattr(args, 'force_burn_subs', False),
|
||||
skip_subs=getattr(args, 'skip_subs', False),
|
||||
vertical=getattr(args, 'vertical', False)):
|
||||
if enhance_clip(
|
||||
str(clip_path),
|
||||
str(output_path),
|
||||
highlight_info,
|
||||
temp_dir,
|
||||
str(transcript_path),
|
||||
force_burn_subs=getattr(args, "force_burn_subs", False),
|
||||
skip_subs=getattr(args, "skip_subs", False),
|
||||
vertical=getattr(args, "vertical", False),
|
||||
crop_vf=crop_vf_arg or None,
|
||||
overlay_x=overlay_x_arg,
|
||||
typewriter_subs=typewriter,
|
||||
):
|
||||
success_count += 1
|
||||
finally:
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 固定参数(与 SKILL 一致)
|
||||
CROP_VF = "crop=608:1080:483:0,crop=498:1080:60:0"
|
||||
CROP_VF = "crop=568:1080:508:0,crop=498:1080:35:0"
|
||||
OUT_SUFFIX = "_竖屏中段"
|
||||
|
||||
|
||||
|
||||
128
_Soul运营技能包导出/测试结果报告模板.md
Normal file
128
_Soul运营技能包导出/测试结果报告模板.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 卡若AI 在阿猫 Mac 上的测试结果报告
|
||||
|
||||
> **测试日期**:2026-03-XX
|
||||
> **测试人**:阿猫(婼瑄)
|
||||
> **测试环境**:macOS 15.7.4,Cursor IDE
|
||||
|
||||
---
|
||||
|
||||
## 一、测试执行
|
||||
|
||||
### 测试脚本输出
|
||||
|
||||
```bash
|
||||
# 请粘贴完整测试脚本输出
|
||||
bash test_karuo_ai_on_amiao.sh
|
||||
```
|
||||
|
||||
**输出内容**:
|
||||
```
|
||||
[在此粘贴完整输出]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、功能验证结果
|
||||
|
||||
### ✅ 核心功能
|
||||
|
||||
- [ ] 卡若AI 目录存在
|
||||
- [ ] BOOTSTRAP.md 存在
|
||||
- [ ] SKILL_REGISTRY.md 存在
|
||||
- [ ] .cursor/rules/karuo-ai.mdc 存在
|
||||
|
||||
### ✅ Agent Skills
|
||||
|
||||
- [ ] soul-operation-report(Soul 运营报表)
|
||||
- [ ] soul-party-project(Soul 项目管理)
|
||||
- [ ] 其他 Skills:_____ 个
|
||||
|
||||
### ✅ 飞书功能
|
||||
|
||||
- [ ] 飞书管理 SKILL.md 存在
|
||||
- [ ] 运营报表 SKILL 存在
|
||||
- [ ] write_today_three_focus.py 可执行
|
||||
- [ ] send_review_to_feishu_webhook.py 可执行
|
||||
|
||||
### ✅ 自主对话测试
|
||||
|
||||
在 Cursor 中测试:
|
||||
|
||||
1. **测试1:写飞书日志**
|
||||
- 触发词:`写飞书日志`
|
||||
- 结果:[ ] 成功 [ ] 失败
|
||||
- 备注:___________
|
||||
|
||||
2. **测试2:运营报表**
|
||||
- 触发词:`运营报表`
|
||||
- 结果:[ ] 成功 [ ] 失败
|
||||
- 备注:___________
|
||||
|
||||
3. **测试3:会议纪要**
|
||||
- 触发词:`会议纪要`
|
||||
- 结果:[ ] 成功 [ ] 失败
|
||||
- 备注:___________
|
||||
|
||||
---
|
||||
|
||||
## 三、使用的模型/模式
|
||||
|
||||
### Cursor 模型信息
|
||||
|
||||
**模型名称**:_________________
|
||||
|
||||
**获取方式**:
|
||||
- [ ] Cursor Settings → Models
|
||||
- [ ] 配置文件:`~/.cursor/User/settings.json`
|
||||
- [ ] 在 Cursor 中询问得到
|
||||
|
||||
**配置内容**(如从 settings.json):
|
||||
```json
|
||||
[粘贴相关配置]
|
||||
```
|
||||
|
||||
### Agent 模式
|
||||
|
||||
- [ ] 默认模式
|
||||
- [ ] 其他模式:___________
|
||||
|
||||
---
|
||||
|
||||
## 四、Python 环境
|
||||
|
||||
**Python 版本**:_________________
|
||||
|
||||
**已安装依赖**:
|
||||
- [ ] requests
|
||||
- [ ] openpyxl
|
||||
- [ ] paramiko
|
||||
- [ ] 其他:___________
|
||||
|
||||
---
|
||||
|
||||
## 五、问题与备注
|
||||
|
||||
### 遇到的问题
|
||||
|
||||
1. ___________
|
||||
2. ___________
|
||||
|
||||
### 解决方案
|
||||
|
||||
1. ___________
|
||||
2. ___________
|
||||
|
||||
---
|
||||
|
||||
## 六、测试结论
|
||||
|
||||
- [ ] **完全可用**:所有功能正常,可以自主对话和飞书操作
|
||||
- [ ] **部分可用**:核心功能正常,部分功能需调整
|
||||
- [ ] **不可用**:存在关键问题,需要修复
|
||||
|
||||
**详细说明**:
|
||||
_________________________________________________
|
||||
|
||||
---
|
||||
|
||||
**测试完成时间**:2026-03-XX XX:XX:XX
|
||||
@@ -402,3 +402,4 @@
|
||||
| 2026-03-20 11:26:44 | 🔄 卡若AI 同步 2026-03-20 11:26 | 更新:Cursor规则、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-20 11:27:30 | 🔄 卡若AI 同步 2026-03-20 11:27 | 更新:水溪整理归档、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-20 12:22:19 | 🔄 卡若AI 同步 2026-03-20 12:22 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||
| 2026-03-20 13:39:57 | 🔄 卡若AI 同步 2026-03-20 12:40 | 更新:水桥平台对接 | 排除 >20MB: 11 个 |
|
||||
|
||||
45
运营中枢/工作台/lkdie论坛文风与头像替换说明_20260320.md
Normal file
45
运营中枢/工作台/lkdie论坛文风与头像替换说明_20260320.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# lkdie(老坑爹)论坛 · 文风观察与发帖优化备忘
|
||||
|
||||
> 日期:2026-03-20。基于「老坑爹的茶馆」列表页与版规可见内容的归纳,供后续发帖对齐社区习惯。
|
||||
|
||||
## 一、整体文风(茶馆 / 掘金向)
|
||||
|
||||
1. **标题**
|
||||
- 经历向、IP 向多用 **《》** 书名式标题,如《我的第一台电脑》《影响力是未来货币》。
|
||||
- 方法论/系列常用 **序号 + 主题**,如「一、游戏掘金之成交」「二、游戏掘金之万能赚钱公式」。
|
||||
- 工具/技术向可用 **【标签】** 前缀,如「【掘金向】…」,与列表里的类型标签(掘金计划 / 私域流量 / 元宇宙)呼应。
|
||||
|
||||
2. **正文**
|
||||
- **口语 + 干货**:短句多,少「论文腔」;先交代场景(为啥写、给谁看),再上步骤或清单。
|
||||
- **与版块的连接**:茶馆版规强调网游相关经历、工作室、出金思路;纯技术文建议开头一两段挂钩「流量/站点/内容变现」,避免像外站搬运。
|
||||
- **排版**:Discuz 常用 `[b]粗体[/b]`、数字序号、分段;避免 GBK 无法编码的特殊符号(如部分 Unicode 项目符号)。
|
||||
|
||||
3. **版规提醒(发帖前自检)**
|
||||
- 投稿区说明:真实原创、字数、审核节奏等以版顶公告为准。
|
||||
- 涉灰产、外挂操作细节勿写;技术 SEO / 工具链保持 **白帽与合规** 表述。
|
||||
|
||||
## 二、对你上一篇 Go + SEO 文的优化方向(已按此思路改帖)
|
||||
|
||||
- 标题偏「站长手记」,弱化教科书感。
|
||||
- 开头从「做站、做内容、做论坛」共性问题切入,再落到 Go 与 SEO。
|
||||
- 保留技术点(canonical、sitemap、日志、CWV),但改成 **清单 + 人话**。
|
||||
- 结尾点题:和 Discuz 论坛站长可迁移的部分,避免只像博客技术文。
|
||||
|
||||
## 三、头像替换说明(为何无法在此自动改)
|
||||
|
||||
1. **当前机制**
|
||||
- 头像走 UCenter:`uc_server/avatar.php?uid=…`;设置页为 **`camera.swf`(Flash)+ 加密参数**,非标准 `multipart/form-data` 图片接口。
|
||||
2. **自动化限制**
|
||||
- 本机脚本请求 `avatar.php` 曾返回 **403**(多为反爬/Referer/防盗链策略),无法在对话里替你完成「上传并生效」闭环。
|
||||
3. **请你本地操作(推荐)**
|
||||
- 浏览器登录论坛 → **设置 → 修改头像**(`home.php?mod=spacecp&ac=avatar`)。
|
||||
- 若 Flash 不可用:可换 **支持 HTML5 上传的浏览器/内核**,或请 **站长/UCenter 后台** 代为上传。
|
||||
4. **已准备的文件(本地路径)**
|
||||
- `卡若Ai的文件夹/图片/lkdie_avatar_好人难做_180.png`(180×180,适合直接上传)
|
||||
- 同目录 `lkdie_avatar_好人难做_20260320.png`(原尺寸,可自行再裁)
|
||||
|
||||
风格说明:偏 **复古像素 / 游戏 HUD 气质**,与论坛整体「游戏辅助、工作室」语境接近,且非真人肖像,降低版权与隐私风险。
|
||||
|
||||
---
|
||||
|
||||
*本文档随发帖实践可继续增补案例句式与反例。*
|
||||
@@ -405,3 +405,4 @@
|
||||
| 2026-03-20 11:26:44 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-20 11:26 | 更新:Cursor规则、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-20 11:27:30 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-20 11:27 | 更新:水溪整理归档、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-20 12:22:19 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-20 12:22 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
| 2026-03-20 13:39:57 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-20 12:40 | 更新:水桥平台对接 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||
|
||||
271
运营中枢/工作台/阿猫电脑卡若AI完整测试方案_20260320.md
Normal file
271
运营中枢/工作台/阿猫电脑卡若AI完整测试方案_20260320.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# 阿猫电脑卡若AI完整测试方案(2026-03-20)
|
||||
|
||||
> **目标**:确保阿猫 Mac 上的卡若AI(Cursor)完全可用,可通过飞书操作,支持自主对话,并报告使用的模型/模式
|
||||
|
||||
---
|
||||
|
||||
## 一、测试方案概述
|
||||
|
||||
由于 SSH 连接不稳定(`macbook.quwanzhi.com:22203` 频繁断开),采用 **iCloud 同步 + 本地测试脚本** 方案。
|
||||
|
||||
### ✅ 已准备内容
|
||||
|
||||
1. **测试脚本**:`_Soul运营技能包导出/test_karuo_ai_on_amiao.sh`
|
||||
- 自动检测卡若AI路径
|
||||
- 检查核心文件、Agent Skills、飞书功能
|
||||
- 验证 Python 环境
|
||||
- 检测 Cursor 模型配置
|
||||
- **已在本机验证通过**
|
||||
|
||||
2. **使用说明**:`_Soul运营技能包导出/阿猫电脑测试说明.md`
|
||||
- 详细测试步骤
|
||||
- 功能验证清单
|
||||
- 问题排查指南
|
||||
|
||||
3. **结果模板**:`_Soul运营技能包导出/测试结果报告模板.md`
|
||||
- 标准化测试报告格式
|
||||
|
||||
---
|
||||
|
||||
## 二、阿猫侧执行步骤
|
||||
|
||||
### 步骤1:等待 iCloud 同步
|
||||
|
||||
确保以下文件已同步到阿猫 Mac:
|
||||
- `卡若AI/_Soul运营技能包导出/test_karuo_ai_on_amiao.sh`
|
||||
- `卡若AI/_Soul运营技能包导出/阿猫电脑测试说明.md`
|
||||
|
||||
**检查方法**:
|
||||
```bash
|
||||
ls -la "$HOME/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄/卡若AI/_Soul运营技能包导出/"
|
||||
```
|
||||
|
||||
### 步骤2:运行测试脚本
|
||||
|
||||
在阿猫 Mac 终端执行:
|
||||
|
||||
```bash
|
||||
bash "$HOME/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄/卡若AI/_Soul运营技能包导出/test_karuo_ai_on_amiao.sh"
|
||||
```
|
||||
|
||||
**预期输出**(参考本机测试结果):
|
||||
```
|
||||
==========================================
|
||||
卡若AI 完整功能测试(阿猫 Mac)
|
||||
==========================================
|
||||
|
||||
✅ 找到卡若AI: [路径]
|
||||
【2/8】检查核心文件...
|
||||
✅ BOOTSTRAP.md
|
||||
✅ SKILL_REGISTRY.md
|
||||
✅ .cursor/rules/karuo-ai.mdc
|
||||
【3/8】检查 Cursor Agent Skills...
|
||||
✅ 找到 2 个 Agent Skills
|
||||
- soul-party-project
|
||||
- soul-operation-report
|
||||
【4/8】检查飞书相关功能...
|
||||
✅ SKILL.md
|
||||
✅ 运营报表_SKILL.md
|
||||
【5/8】检查飞书脚本...
|
||||
✅ write_today_three_focus.py 可执行
|
||||
✅ send_review_to_feishu_webhook.py 可执行
|
||||
【6/8】检查 Python 环境...
|
||||
✅ Python 3.x
|
||||
✅ requests
|
||||
✅ paramiko
|
||||
✅ openpyxl
|
||||
【7/8】检查 Cursor IDE...
|
||||
✅ Cursor 已安装
|
||||
【8/8】测试自主对话能力...
|
||||
✅ 测试文件创建成功
|
||||
【9/9】检测 Cursor 模型配置...
|
||||
[模型信息]
|
||||
|
||||
==========================================
|
||||
测试总结
|
||||
==========================================
|
||||
✅ 卡若AI 在阿猫 Mac 上配置完整,可以正常使用
|
||||
```
|
||||
|
||||
### 步骤3:在 Cursor 中测试自主对话
|
||||
|
||||
1. **打开 Cursor IDE**
|
||||
2. **File → Open Folder** → 选择卡若AI目录
|
||||
3. **测试触发词**:
|
||||
|
||||
```
|
||||
写飞书日志
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
运营报表
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
会议纪要
|
||||
```
|
||||
|
||||
**验证**:卡若AI 应能识别并执行对应技能。
|
||||
|
||||
### 步骤4:查看使用的模型
|
||||
|
||||
**方法1:Cursor Settings**
|
||||
1. 按 `Cmd + ,` 打开设置
|
||||
2. 搜索 **"Models"** 或 **"model"**
|
||||
3. 查看当前使用的模型
|
||||
|
||||
**方法2:配置文件**
|
||||
```bash
|
||||
cat "$HOME/.cursor/User/settings.json" | grep -i "model" | head -5
|
||||
```
|
||||
|
||||
**方法3:在 Cursor 中询问**
|
||||
```
|
||||
你使用的是什么模型?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、预期测试结果
|
||||
|
||||
### ✅ 成功标志
|
||||
|
||||
| 项目 | 预期结果 |
|
||||
|:---|:---|
|
||||
| **核心文件** | 3/3 完整 |
|
||||
| **Agent Skills** | ≥ 2 个(soul-operation-report, soul-party-project) |
|
||||
| **飞书功能** | 3/3 可用 |
|
||||
| **Python 环境** | Python 3.x + 关键依赖 |
|
||||
| **Cursor IDE** | 已安装 |
|
||||
| **自主对话** | 能识别触发词并执行 |
|
||||
| **模型信息** | 显示具体模型名称或"Cursor 默认" |
|
||||
|
||||
### 📊 本机测试结果(参考)
|
||||
|
||||
```
|
||||
卡若AI路径: /Users/karuo/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄/卡若AI
|
||||
核心文件: 3/3
|
||||
Agent Skills: 2 个
|
||||
飞书技能: 3/3
|
||||
|
||||
✅ 卡若AI 在阿猫 Mac 上配置完整,可以正常使用
|
||||
|
||||
【模型信息】
|
||||
使用模型: Cursor 默认模型(通常为 Claude Sonnet 或 GPT-4)
|
||||
提示: 可在 Cursor Settings → Models 查看当前使用的模型
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、模型/模式说明
|
||||
|
||||
### Cursor 默认模型
|
||||
|
||||
Cursor 通常使用以下模型之一:
|
||||
- **Claude Sonnet**(Anthropic)
|
||||
- **GPT-4**(OpenAI)
|
||||
- **GPT-4 Turbo**
|
||||
|
||||
### 查看方式
|
||||
|
||||
1. **Cursor Settings → Models**:最直观
|
||||
2. **配置文件**:`~/.cursor/User/settings.json` 中的 `cursor.general.model`
|
||||
3. **对话询问**:在 Cursor 中直接问"你使用的是什么模型?"
|
||||
|
||||
### Agent 模式
|
||||
|
||||
Cursor 的 Agent 模式通常为:
|
||||
- **默认模式**:根据上下文自动选择
|
||||
- **Composer 模式**:代码生成与编辑
|
||||
- **Chat 模式**:对话与问答
|
||||
|
||||
---
|
||||
|
||||
## 五、功能验证清单
|
||||
|
||||
### ✅ 核心功能
|
||||
- [ ] 卡若AI 目录存在
|
||||
- [ ] BOOTSTRAP.md 存在
|
||||
- [ ] SKILL_REGISTRY.md 存在
|
||||
- [ ] .cursor/rules/karuo-ai.mdc 存在
|
||||
|
||||
### ✅ Agent Skills(Cursor 入口)
|
||||
- [ ] soul-operation-report(Soul 运营报表)
|
||||
- [ ] soul-party-project(Soul 项目管理)
|
||||
|
||||
### ✅ 飞书操作功能
|
||||
- [ ] 飞书管理 SKILL.md
|
||||
- [ ] 运营报表 SKILL
|
||||
- [ ] write_today_three_focus.py(写飞书日志)
|
||||
- [ ] send_review_to_feishu_webhook.py(复盘发群)
|
||||
|
||||
### ✅ 自主对话能力
|
||||
- [ ] 在 Cursor 中识别"写飞书日志"
|
||||
- [ ] 在 Cursor 中识别"运营报表"
|
||||
- [ ] 在 Cursor 中识别"会议纪要"
|
||||
|
||||
---
|
||||
|
||||
## 六、问题排查
|
||||
|
||||
### ❌ 找不到卡若AI目录
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 检查 iCloud 同步状态
|
||||
ls -la "$HOME/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄/"
|
||||
ls -la "$HOME/Library/Mobile Documents/com~apple~CloudDocs/婼瑄/"
|
||||
```
|
||||
|
||||
### ❌ Cursor 未安装
|
||||
|
||||
**解决**:下载安装 Cursor
|
||||
- 官网:https://cursor.sh
|
||||
- 或从已挂载的 DMG 安装
|
||||
|
||||
### ❌ Python 依赖缺失
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
pip3 install requests openpyxl paramiko
|
||||
```
|
||||
|
||||
### ❌ 飞书功能不可用
|
||||
|
||||
**检查**:
|
||||
1. 飞书 Token 是否配置(见 `运营中枢/工作台/00_账号与API索引.md`)
|
||||
2. 脚本权限:`chmod +x *.py`
|
||||
|
||||
---
|
||||
|
||||
## 七、测试完成后反馈
|
||||
|
||||
请阿猫将以下信息反馈给卡若:
|
||||
|
||||
1. **测试脚本完整输出**(复制粘贴)
|
||||
2. **使用的模型**(从 Cursor Settings 或测试脚本输出)
|
||||
3. **功能可用性**:
|
||||
- [ ] 核心文件完整
|
||||
- [ ] Agent Skills 可用
|
||||
- [ ] 飞书功能可用
|
||||
- [ ] 自主对话正常
|
||||
4. **遇到的问题**(如有)
|
||||
|
||||
---
|
||||
|
||||
## 八、文件位置
|
||||
|
||||
| 文件 | 路径 |
|
||||
|:---|:---|
|
||||
| 测试脚本 | `卡若AI/_Soul运营技能包导出/test_karuo_ai_on_amiao.sh` |
|
||||
| 使用说明 | `卡若AI/_Soul运营技能包导出/阿猫电脑测试说明.md` |
|
||||
| 结果模板 | `卡若AI/_Soul运营技能包导出/测试结果报告模板.md` |
|
||||
|
||||
---
|
||||
|
||||
**创建时间**:2026-03-20 12:55
|
||||
**测试脚本状态**:✅ 已在本机验证通过
|
||||
Reference in New Issue
Block a user