🔄 卡若AI 同步 2026-03-20 16:08 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个

This commit is contained in:
2026-03-20 16:08:47 +08:00
parent 63c5618b11
commit 241d139ea9
13 changed files with 824 additions and 56 deletions

View File

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

View File

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

View File

@@ -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×1080soul_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 做竖屏中段:**

View File

@@ -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:0568 内水平居中取 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` 为切片序号(取所有 `_数字_` 中最小值)。

View File

@@ -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` 时输出文件名为纯标题(无序号、无「竖屏中段」)。

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

View File

@@ -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 解析字幕/封面叠在横版上的 xcrop=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)

View File

@@ -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 = "_竖屏中段"

View File

@@ -0,0 +1,128 @@
# 卡若AI 在阿猫 Mac 上的测试结果报告
> **测试日期**2026-03-XX
> **测试人**:阿猫(婼瑄)
> **测试环境**macOS 15.7.4Cursor IDE
---
## 一、测试执行
### 测试脚本输出
```bash
# 请粘贴完整测试脚本输出
bash test_karuo_ai_on_amiao.sh
```
**输出内容**
```
[在此粘贴完整输出]
```
---
## 二、功能验证结果
### ✅ 核心功能
- [ ] 卡若AI 目录存在
- [ ] BOOTSTRAP.md 存在
- [ ] SKILL_REGISTRY.md 存在
- [ ] .cursor/rules/karuo-ai.mdc 存在
### ✅ Agent Skills
- [ ] soul-operation-reportSoul 运营报表)
- [ ] soul-party-projectSoul 项目管理)
- [ ] 其他 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

View File

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

View 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 气质**,与论坛整体「游戏辅助、工作室」语境接近,且非真人肖像,降低版权与隐私风险。
---
*本文档随发帖实践可继续增补案例句式与反例。*

View File

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

View File

@@ -0,0 +1,271 @@
# 阿猫电脑卡若AI完整测试方案2026-03-20
> **目标**:确保阿猫 Mac 上的卡若AICursor完全可用可通过飞书操作支持自主对话并报告使用的模型/模式
---
## 一、测试方案概述
由于 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查看使用的模型
**方法1Cursor 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 SkillsCursor 入口)
- [ ] soul-operation-reportSoul 运营报表)
- [ ] soul-party-projectSoul 项目管理)
### ✅ 飞书操作功能
- [ ] 飞书管理 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
**测试脚本状态**:✅ 已在本机验证通过