diff --git a/02_卡人(水)/水桥_平台对接/飞书管理/脚本/.feishu_tokens.json b/02_卡人(水)/水桥_平台对接/飞书管理/脚本/.feishu_tokens.json index 0abf1701..2d78a169 100644 --- a/02_卡人(水)/水桥_平台对接/飞书管理/脚本/.feishu_tokens.json +++ b/02_卡人(水)/水桥_平台对接/飞书管理/脚本/.feishu_tokens.json @@ -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" } \ No newline at end of file diff --git a/02_卡人(水)/水桥_平台对接/飞书管理/脚本/soul_party_to_feishu_sheet.py b/02_卡人(水)/水桥_平台对接/飞书管理/脚本/soul_party_to_feishu_sheet.py index 6d90200d..6c92e0ac 100644 --- a/02_卡人(水)/水桥_平台对接/飞书管理/脚本/soul_party_to_feishu_sheet.py +++ b/02_卡人(水)/水桥_平台对接/飞书管理/脚本/soul_party_to_feishu_sheet.py @@ -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) diff --git a/03_卡木(木)/木叶_视频内容/视频切片/SKILL.md b/03_卡木(木)/木叶_视频内容/视频切片/SKILL.md index 6d84b5b6..5eb2b1c5 100644 --- a/03_卡木(木)/木叶_视频内容/视频切片/SKILL.md +++ b/03_卡木(木)/木叶_视频内容/视频切片/SKILL.md @@ -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 做竖屏中段:** diff --git a/03_卡木(木)/木叶_视频内容/视频切片/Soul竖屏切片_SKILL.md b/03_卡木(木)/木叶_视频内容/视频切片/Soul竖屏切片_SKILL.md index d380d994..95de6031 100644 --- a/03_卡木(木)/木叶_视频内容/视频切片/Soul竖屏切片_SKILL.md +++ b/03_卡木(木)/木叶_视频内容/视频切片/Soul竖屏切片_SKILL.md @@ -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` 为切片序号(取所有 `_数字_` 中最小值)。 diff --git a/03_卡木(木)/木叶_视频内容/视频切片/参考资料/竖屏中段裁剪参数说明.md b/03_卡木(木)/木叶_视频内容/视频切片/参考资料/竖屏中段裁剪参数说明.md index 35d08bb8..acd22831 100644 --- a/03_卡木(木)/木叶_视频内容/视频切片/参考资料/竖屏中段裁剪参数说明.md +++ b/03_卡木(木)/木叶_视频内容/视频切片/参考资料/竖屏中段裁剪参数说明.md @@ -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` 时输出文件名为纯标题(无序号、无「竖屏中段」)。 diff --git a/03_卡木(木)/木叶_视频内容/视频切片/脚本/analyze_feishu_ui_crop.py b/03_卡木(木)/木叶_视频内容/视频切片/脚本/analyze_feishu_ui_crop.py new file mode 100755 index 00000000..6d74963f --- /dev/null +++ b/03_卡木(木)/木叶_视频内容/视频切片/脚本/analyze_feishu_ui_crop.py @@ -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() diff --git a/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_enhance.py b/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_enhance.py index b133d2d8..8b2331d2 100644 --- a/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_enhance.py +++ b/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_enhance.py @@ -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) diff --git a/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_vertical_crop.py b/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_vertical_crop.py index cc551a82..9e4560c1 100644 --- a/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_vertical_crop.py +++ b/03_卡木(木)/木叶_视频内容/视频切片/脚本/soul_vertical_crop.py @@ -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 = "_竖屏中段" diff --git a/_Soul运营技能包导出/测试结果报告模板.md b/_Soul运营技能包导出/测试结果报告模板.md new file mode 100644 index 00000000..f529ec48 --- /dev/null +++ b/_Soul运营技能包导出/测试结果报告模板.md @@ -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 diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index be2948ae..219b5002 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -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 个 | diff --git a/运营中枢/工作台/lkdie论坛文风与头像替换说明_20260320.md b/运营中枢/工作台/lkdie论坛文风与头像替换说明_20260320.md new file mode 100644 index 00000000..ead9dd06 --- /dev/null +++ b/运营中枢/工作台/lkdie论坛文风与头像替换说明_20260320.md @@ -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 气质**,与论坛整体「游戏辅助、工作室」语境接近,且非真人肖像,降低版权与隐私风险。 + +--- + +*本文档随发帖实践可继续增补案例句式与反例。* diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index 42fe9417..d88f6a2e 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -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) | diff --git a/运营中枢/工作台/阿猫电脑卡若AI完整测试方案_20260320.md b/运营中枢/工作台/阿猫电脑卡若AI完整测试方案_20260320.md new file mode 100644 index 00000000..49a5a0f6 --- /dev/null +++ b/运营中枢/工作台/阿猫电脑卡若AI完整测试方案_20260320.md @@ -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 +**测试脚本状态**:✅ 已在本机验证通过