Metadata-Version: 2.4
Name: clipora
Version: 0.1.1
Summary: CLI workflow for AI-assisted livestream clip extraction
Project-URL: Homepage, https://github.com/Rousseau512/Clipora
Project-URL: Repository, https://github.com/Rousseau512/Clipora
Project-URL: Issues, https://github.com/Rousseau512/Clipora/issues
Keywords: clip extraction,ffmpeg,livestream,video
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Multimedia :: Video
Requires-Python: >=3.11
Requires-Dist: aliyun-python-sdk-core>=2.16.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: faster-whisper>=1.0.3
Requires-Dist: httpx>=0.27.0
Requires-Dist: jinja2>=3.1.4
Requires-Dist: mediapipe>=0.10.14
Requires-Dist: oss2>=2.18.5
Requires-Dist: platformdirs>=4.3.6
Requires-Dist: pydantic>=2.7.0
Requires-Dist: python-multipart>=0.0.12
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: typer>=0.12.3
Requires-Dist: uvicorn>=0.32.0
Description-Content-Type: text/markdown

# Clipora

Clipora 是面向**直播电商输入视频**的 CLI 视频切片工作流。它把本地视频处理成可复查的 job workspace、分析计划和渲染结果。

## 要求

- Python `>=3.11`
- `ffmpeg`，若使用烧录字幕模式，必须包含 `subtitles`/`ass` 滤镜（`libass` 支持）
- 可选：`local` ASR 需要本机 Whisper 环境
- 可选：`analysis.pose_presence.enabled=true` 需要 MediaPipe Pose Landmarker `.task` 模型

## 安装

macOS 建议先安装带 `libass` 的 Homebrew `ffmpeg-full`，否则烧录字幕会报 `No such filter: 'subtitles'`：

```bash
brew install ffmpeg-full
brew unlink ffmpeg
brew link --overwrite --force ffmpeg-full
ffmpeg -hide_banner -filters | rg "subtitles|ass"
```

看到 `subtitles` 和 `ass` 两个视频滤镜后，再安装 Clipora。

已发布包：

```bash
pip install clipora
clipora --help
```

使用 `uv` 安装工具：

```bash
uv tool install clipora
```

源码开发：

```bash
uv sync
uv run clipora --help
```

## 配置

安装版默认配置位置：

- macOS: `~/Library/Application Support/clipora/clipora.yaml`
- Linux: `~/.config/clipora/clipora.yaml`
- Windows: `%APPDATA%/clipora/clipora.yaml`

可先创建默认配置目录并复制示例：

```bash
mkdir -p "$(python - <<'PY'
from clipora.config import get_default_config_path
print(get_default_config_path().parent)
PY
)"
cp clipora.example.yaml "$(python - <<'PY'
from clipora.config import get_default_config_path
print(get_default_config_path())
PY
)"
```

源码仓库用户也可复制示例配置到仓库根目录：

```bash
cp clipora.example.yaml clipora.yaml
```

最小配置：

```yaml
provider:
  base_url: https://api.openai.com/v1
  api_key: your-llm-api-key
  model: gpt-4.1-mini

paths:
  workdir: ./workdir
```

完整字段请参考 `clipora.example.yaml`，常用顶层段包括 `provider`、`paths`、`asr`（`local` 或 `aliyun`）、`analysis`（含 `pose_presence` 子段）、`preprocess`（含 `normalize` 与 `clean` 子段）、`concurrency`（控制 streaming 流水的 analyze / render 并发）、`render`、`render_subtitles`、`render_silence_snap`、`prompt_overrides`、`logging`。旧顶层 `cleaning` 字段仍兼容，写入时会被归一化到 `preprocess.clean`。

配置加载顺序：默认 YAML 文件或 `--config` 指定文件 → 环境变量（形如 `CLIPORA_PROVIDER__BASE_URL`，详见 `src/clipora/config.py` 中的 env 映射）→ CLI / 单次任务覆盖。Web `/config` 保存原始 YAML 值，不写回默认值或环境变量覆盖结果。

字幕字体配置（仅对 `render_subtitles.mode=both` 或 `burned_only` 的烧录字幕生效）：

```yaml
render_subtitles:
  mode: burned_only
  formats: [srt]
  managed_fonts: [圆构黑体, 檎风黑体]
```

- `managed_fonts` 为空时，不使用托管字体，回退到 `font_family_override` 或平台默认中文字体。
- `managed_fonts` 选 1 个时固定使用该字体；选多个时，每个渲染结果会随机挑 1 个托管字体。
- `managed_fonts` 不能与 `font_file` / `fonts_dir` 混用。
- 如果设置 `font_file`，必须同时设置 `font_family_override`。

使用本地字体文件示例：

```yaml
render_subtitles:
  mode: burned_only
  formats: [srt]
  font_family_override: Source Han Sans SC
  font_file: /absolute/path/SourceHanSansSC-Regular.otf
  fonts_dir: /absolute/path/to/font-dir
```

启用姿态检测前先下载 MediaPipe 模型,推荐用 CLI 一步到位（也可以手动 `curl` 下载到 `analysis.pose_presence.model_path` 指向的位置）：

```bash
clipora download-pose-model --config /absolute/path/to/clipora.yaml
```

再写入配置：

```yaml
analysis:
  pose_presence:
    enabled: true
    model_path: ./workdir/models/pose_landmarker_full.task
```

## 使用

源码仓库内可把下面的 `clipora ...` 替换为 `uv run clipora ...`。

完整流程（流式：preprocess 完成后 analyze 与 render 会随 semantic 发现的 item 并发推进）：

```bash
clipora run /absolute/path/to/video.mp4
clipora run /absolute/path/to/video.mp4 --config /absolute/path/to/clipora.yaml
```

本地 Web UI：

```bash
clipora web
clipora web --config /absolute/path/to/clipora.yaml
clipora web --host 0.0.0.0 --port 9000 --config /absolute/path/to/clipora.yaml
```

阶段命令（按顺序：preprocess → semantic-discover → semantic-cluster → analyze → render；`clean` 仍作为 `preprocess` 的隐藏别名兼容老脚本）：

```bash
clipora preprocess /absolute/path/to/video.mp4 --config clipora.yaml
clipora semantic-discover ./workdir/<job-id> --config clipora.yaml
clipora semantic-cluster ./workdir/<job-id> --config clipora.yaml
clipora analyze ./workdir/<job-id> --config clipora.yaml
clipora render ./workdir/<job-id> --config clipora.yaml
```

`preprocess` 会按需对 `.ts/.mts/.m2ts` 容器做 remux 归一化（写入 `preprocess/source_normalized.mp4`，结果可缓存复用），并在启用 `cleaning.enabled` 时移除冻结画面段。所有阶段命令都接受 `--force` 强制重跑（`analyze-item` 例外，每次调用即重跑该 item）。

针对单个 semantic item 重跑分析：

```bash
clipora analyze-item ./workdir/<job-id> --semantic-item-id <id> --config clipora.yaml
```

重渲染已有 plan（既支持完整 `EditPlan`，也支持单个 `ItemEditPlan`），并可临时覆盖字幕配置：

```bash
clipora render ./workdir/<job-id> --plan ./workdir/<job-id>/analysis/edit_plan.json --config clipora.yaml
clipora render ./workdir/<job-id> --plan ./workdir/<job-id>/analysis/items/<item_plan_id>.json --config clipora.yaml
clipora render ./workdir/<job-id> \
  --subtitle-position short_video_safe \
  --subtitle-font-theme short_video_bold \
  --config clipora.yaml
```

其它工具命令：`clipora download-pose-model` 下载姿态模型；`clipora delete-job <job-id>` 删除一个 job 的 workspace 与提交记录。完整命令清单见 `clipora --help`。

## Web UI

- `/`：上传视频、提交 job、查看历史 job
- `/config`：编辑并保存配置文件（支持可视化和源代码两种编辑模式）
- `/jobs/<id>`：查看 job 进度、SSE 实时事件、日志、下载渲染结果，并支持单阶段重跑或停止

页面之上还提供一组 JSON / SSE API（如 `GET /api/jobs/{id}/events`、`POST /api/jobs/{id}/rerun`、`DELETE /api/jobs/{id}` 等）供前端使用，命令行用户一般不需要直接调用。

## 输出

```text
workdir/<job-id>/
  manifest.json
  preprocess/                # 归一化后的 source_normalized.mp4(若触发)
  clean/                     # 冻结画面清理产物(若启用 cleaning)
  semantic/                  # transcript.json + discovered_intervals/window_plans/cluster_plan/semantic_item_set.json
  analysis/
    edit_plan.json           # 整 job 的 EditPlan(契约文件)
    items/<item_plan_id>.json
    frames/, requests/, subtitles/
  renders/items/<item_plan_id>/
    <item_plan_id>.mp4
    <item_plan_id>.srt       # 启用 sidecar 字幕时
    <item_plan_id>.ass       # 烧录字幕时使用的中间产物
    execution_result.json
  logs/pipeline.log

workdir/plans/<plan_id>.json  # 流式 pipeline 写入的可重放 plan 副本
```

`clipora run` 走流式 pipeline，渲染结果按 item 写入 `renders/items/<item_plan_id>/`；整 job 的汇总文件 `renders/execution_result.json` 仅在直接运行 `clipora render <job-dir>`（即批量 render stage）时产出。

## 测试

```bash
uv run pytest -m "not integration and not e2e"
uv run pytest tests/test_web_app.py
uv run pytest tests/test_web_app.py::test_api_config_saves_updated_values
uv run pytest -m integration
uv run pytest -m e2e
```

## 发布

本地构建验证：

```bash
uv build
uvx twine check dist/*
```

发布前同步 `pyproject.toml`、`src/clipora/__init__.py`、git tag 版本号。推送 `v*` tag 触发 `.github/workflows/publish-pypi.yml`，workflow 会跑 fast tests、构建 wheel/sdist、校验运行时资源、跑 fresh-install smoke tests，并通过 PyPI trusted publishing 发布。
