clipsmith-ai 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clipsmith_ai-0.2.0/.dockerignore +38 -0
- clipsmith_ai-0.2.0/.env.example +29 -0
- clipsmith_ai-0.2.0/.github/workflows/ci.yml +41 -0
- clipsmith_ai-0.2.0/.github/workflows/e2e-cloud.yml +19 -0
- clipsmith_ai-0.2.0/.github/workflows/e2e.yml +20 -0
- clipsmith_ai-0.2.0/.github/workflows/publish.yml +20 -0
- clipsmith_ai-0.2.0/.github/workflows/release-please.yml +17 -0
- clipsmith_ai-0.2.0/.gitignore +31 -0
- clipsmith_ai-0.2.0/.pre-commit-config.yaml +21 -0
- clipsmith_ai-0.2.0/.release-please-config.json +15 -0
- clipsmith_ai-0.2.0/.release-please-manifest.json +3 -0
- clipsmith_ai-0.2.0/CHANGELOG.md +28 -0
- clipsmith_ai-0.2.0/Dockerfile +22 -0
- clipsmith_ai-0.2.0/LICENSE +21 -0
- clipsmith_ai-0.2.0/PKG-INFO +277 -0
- clipsmith_ai-0.2.0/README.md +221 -0
- clipsmith_ai-0.2.0/clipsmith.spec +76 -0
- clipsmith_ai-0.2.0/config.yaml +83 -0
- clipsmith_ai-0.2.0/docs/architecture.md +326 -0
- clipsmith_ai-0.2.0/docs/cloud.md +294 -0
- clipsmith_ai-0.2.0/docs/commands.md +227 -0
- clipsmith_ai-0.2.0/docs/configuration.md +207 -0
- clipsmith_ai-0.2.0/docs/dev/azure-cloud-setup.md +206 -0
- clipsmith_ai-0.2.0/docs/dev/contributing.md +129 -0
- clipsmith_ai-0.2.0/docs/examples.md +120 -0
- clipsmith_ai-0.2.0/docs/getting-started.md +111 -0
- clipsmith_ai-0.2.0/docs/index.md +55 -0
- clipsmith_ai-0.2.0/examples/01_local_mp4.ipynb +201 -0
- clipsmith_ai-0.2.0/examples/02_local_vod.ipynb +180 -0
- clipsmith_ai-0.2.0/examples/03_local_vod_ollama.ipynb +230 -0
- clipsmith_ai-0.2.0/examples/04_cloud.ipynb +190 -0
- clipsmith_ai-0.2.0/infra/clipsmith-runner-role.json +23 -0
- clipsmith_ai-0.2.0/main.py +12 -0
- clipsmith_ai-0.2.0/mkdocs.yml +42 -0
- clipsmith_ai-0.2.0/pyproject.toml +98 -0
- clipsmith_ai-0.2.0/scripts/build_windows.ps1 +53 -0
- clipsmith_ai-0.2.0/src/clipsmith/__init__.py +6 -0
- clipsmith_ai-0.2.0/src/clipsmith/__main__.py +4 -0
- clipsmith_ai-0.2.0/src/clipsmith/candidates/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/candidates/audio.py +110 -0
- clipsmith_ai-0.2.0/src/clipsmith/candidates/builder.py +214 -0
- clipsmith_ai-0.2.0/src/clipsmith/candidates/math.py +48 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/__init__.py +27 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/clip.py +153 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/cloud.py +259 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/run.py +252 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/setup.py +242 -0
- clipsmith_ai-0.2.0/src/clipsmith/cli/utils.py +35 -0
- clipsmith_ai-0.2.0/src/clipsmith/cloud/__init__.py +0 -0
- clipsmith_ai-0.2.0/src/clipsmith/cloud/azure_runner.py +278 -0
- clipsmith_ai-0.2.0/src/clipsmith/cloud/drive_upload.py +180 -0
- clipsmith_ai-0.2.0/src/clipsmith/cloud/provisioner.py +107 -0
- clipsmith_ai-0.2.0/src/clipsmith/config/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/config/loaders.py +52 -0
- clipsmith_ai-0.2.0/src/clipsmith/config/models.py +85 -0
- clipsmith_ai-0.2.0/src/clipsmith/io/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/io/media.py +24 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/__init__.py +24 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/anthropic_provider.py +80 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/base.py +75 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/ollama_provider.py +50 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/openai_provider.py +68 -0
- clipsmith_ai-0.2.0/src/clipsmith/llm/prompts.py +87 -0
- clipsmith_ai-0.2.0/src/clipsmith/models/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/models/candidates.py +16 -0
- clipsmith_ai-0.2.0/src/clipsmith/models/chat.py +53 -0
- clipsmith_ai-0.2.0/src/clipsmith/models/transcript.py +47 -0
- clipsmith_ai-0.2.0/src/clipsmith/models/twitch.py +31 -0
- clipsmith_ai-0.2.0/src/clipsmith/pipeline.py +192 -0
- clipsmith_ai-0.2.0/src/clipsmith/rendering/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/rendering/captions.py +135 -0
- clipsmith_ai-0.2.0/src/clipsmith/rendering/clipper.py +194 -0
- clipsmith_ai-0.2.0/src/clipsmith/rendering/detect.py +231 -0
- clipsmith_ai-0.2.0/src/clipsmith/selection/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/selection/selector.py +127 -0
- clipsmith_ai-0.2.0/src/clipsmith/settings.py +27 -0
- clipsmith_ai-0.2.0/src/clipsmith/transcription/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/transcription/transcriber.py +235 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/__init__.py +1 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/chat.py +122 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/client.py +150 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/downloader.py +77 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/state.py +31 -0
- clipsmith_ai-0.2.0/src/clipsmith/twitch/watcher.py +59 -0
- clipsmith_ai-0.2.0/tests/conftest.py +30 -0
- clipsmith_ai-0.2.0/tests/e2e/conftest.py +11 -0
- clipsmith_ai-0.2.0/tests/e2e/test_cloud.py +119 -0
- clipsmith_ai-0.2.0/tests/e2e/test_pipeline.py +132 -0
- clipsmith_ai-0.2.0/tests/helpers.py +17 -0
- clipsmith_ai-0.2.0/tests/integration/candidates/test_audio.py +49 -0
- clipsmith_ai-0.2.0/tests/integration/cloud/test_azure_runner.py +273 -0
- clipsmith_ai-0.2.0/tests/integration/cloud/test_drive_upload.py +210 -0
- clipsmith_ai-0.2.0/tests/integration/cloud/test_provisioner.py +175 -0
- clipsmith_ai-0.2.0/tests/integration/conftest.py +11 -0
- clipsmith_ai-0.2.0/tests/integration/llm/test_ollama_provider.py +90 -0
- clipsmith_ai-0.2.0/tests/integration/transcription/test_transcriber.py +22 -0
- clipsmith_ai-0.2.0/tests/integration/twitch/test_client.py +159 -0
- clipsmith_ai-0.2.0/tests/integration/twitch/test_downloader.py +52 -0
- clipsmith_ai-0.2.0/tests/smoke/cli/test_cli.py +90 -0
- clipsmith_ai-0.2.0/tests/smoke/cli/test_cli_cloud.py +261 -0
- clipsmith_ai-0.2.0/tests/smoke/config/test_settings.py +37 -0
- clipsmith_ai-0.2.0/tests/smoke/conftest.py +11 -0
- clipsmith_ai-0.2.0/tests/unit/candidates/test_audio.py +27 -0
- clipsmith_ai-0.2.0/tests/unit/candidates/test_builder.py +207 -0
- clipsmith_ai-0.2.0/tests/unit/conftest.py +11 -0
- clipsmith_ai-0.2.0/tests/unit/models/test_transcript.py +68 -0
- clipsmith_ai-0.2.0/tests/unit/rendering/test_captions.py +149 -0
- clipsmith_ai-0.2.0/tests/unit/rendering/test_clipper.py +188 -0
- clipsmith_ai-0.2.0/tests/unit/selection/test_clip_pick.py +92 -0
- clipsmith_ai-0.2.0/tests/unit/selection/test_selector.py +173 -0
- clipsmith_ai-0.2.0/tests/unit/transcription/test_transcriber.py +96 -0
- clipsmith_ai-0.2.0/tests/unit/twitch/test_state.py +26 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.git
|
|
2
|
+
.github
|
|
3
|
+
.venv
|
|
4
|
+
venv
|
|
5
|
+
__pycache__
|
|
6
|
+
*.pyc
|
|
7
|
+
*.pyo
|
|
8
|
+
.mypy_cache
|
|
9
|
+
.ruff_cache
|
|
10
|
+
.pytest_cache
|
|
11
|
+
.coverage
|
|
12
|
+
dist
|
|
13
|
+
build
|
|
14
|
+
site
|
|
15
|
+
*.egg-info
|
|
16
|
+
|
|
17
|
+
# Runtime artifacts — mounted as volumes, not baked in
|
|
18
|
+
work/
|
|
19
|
+
out/
|
|
20
|
+
state.json
|
|
21
|
+
*.mp4
|
|
22
|
+
*.m4a
|
|
23
|
+
*.ass
|
|
24
|
+
*.srt
|
|
25
|
+
|
|
26
|
+
# Secrets and local config — injected at runtime via env vars
|
|
27
|
+
.env
|
|
28
|
+
.env.example
|
|
29
|
+
|
|
30
|
+
# Dev-only
|
|
31
|
+
tests/
|
|
32
|
+
docs/
|
|
33
|
+
examples/
|
|
34
|
+
scripts/
|
|
35
|
+
mkdocs.yml
|
|
36
|
+
AzureCLI.msi
|
|
37
|
+
clipsmith.spec
|
|
38
|
+
main.py
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# clipsmith secrets — copy this file to .env and fill in your key.
|
|
2
|
+
# Run `clipsmith setup` to do this interactively.
|
|
3
|
+
|
|
4
|
+
# LLM provider key (set the one you use)
|
|
5
|
+
#ANTHROPIC_API_KEY=
|
|
6
|
+
# OPENAI_API_KEY=
|
|
7
|
+
|
|
8
|
+
# Twitch credentials — only needed for `watch` / `run-vod` (not for `process`)
|
|
9
|
+
# TWITCH_CLIENT_ID=
|
|
10
|
+
# TWITCH_CLIENT_SECRET=
|
|
11
|
+
|
|
12
|
+
# Azure — only AZURE_SUBSCRIPTION_ID is required for cloud runs.
|
|
13
|
+
# Storage accounts and file shares are provisioned automatically per run and torn down when done.
|
|
14
|
+
# AZURE_SUBSCRIPTION_ID=
|
|
15
|
+
|
|
16
|
+
# Azure Service Principal — recommended; avoids running as your personal admin account.
|
|
17
|
+
# Run `clipsmith cloud setup-sp` (see docs/cloud.md) to create the SP and get these values.
|
|
18
|
+
# Without these, DefaultAzureCredential falls back to `az login` (your personal account).
|
|
19
|
+
# AZURE_CLIENT_ID=
|
|
20
|
+
# AZURE_CLIENT_SECRET=
|
|
21
|
+
# AZURE_TENANT_ID=
|
|
22
|
+
|
|
23
|
+
# Docker Hub — optional; prevents image pull rate-limit errors on ACI
|
|
24
|
+
# DOCKER_HUB_USERNAME=
|
|
25
|
+
# DOCKER_HUB_PASSWORD=
|
|
26
|
+
|
|
27
|
+
# Google Drive — optional; used to upload finished clips after a cloud run
|
|
28
|
+
# GOOGLE_OAUTH_CLIENT_JSON=
|
|
29
|
+
# GOOGLE_DRIVE_FOLDER_ID=
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
lint:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.11"
|
|
15
|
+
- run: pip install -e ".[dev]" mypy
|
|
16
|
+
- run: ruff check src tests
|
|
17
|
+
- run: mypy src
|
|
18
|
+
|
|
19
|
+
tests:
|
|
20
|
+
needs: lint
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
- run: sudo apt-get install -y ffmpeg
|
|
28
|
+
- run: pip install -e ".[dev]"
|
|
29
|
+
- run: python -m pytest tests/ -q
|
|
30
|
+
|
|
31
|
+
security:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.11"
|
|
38
|
+
- run: pip install --upgrade pip
|
|
39
|
+
- run: pip install -e ".[dev]"
|
|
40
|
+
- run: bandit -r src/ -ll -x tests/
|
|
41
|
+
- run: pip-audit --skip-editable
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: E2E Cloud
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
e2e-cloud:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
env:
|
|
9
|
+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
|
10
|
+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
|
11
|
+
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
|
12
|
+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- run: pip install -e ".[dev,cloud]"
|
|
19
|
+
- run: python -m pytest tests/e2e/test_cloud.py --run-e2e -v
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: E2E
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
e2e:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
env:
|
|
9
|
+
TWITCH_CLIENT_ID: ${{ secrets.TWITCH_CLIENT_ID }}
|
|
10
|
+
TWITCH_CLIENT_SECRET: ${{ secrets.TWITCH_CLIENT_SECRET }}
|
|
11
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
12
|
+
E2E_VOD_ID: ${{ secrets.E2E_VOD_ID }}
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- run: sudo apt-get install -y ffmpeg
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: python -m pytest tests/e2e/ --run-e2e -q
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- "v*.*.*"
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: Release Please
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write
|
|
8
|
+
pull-requests: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
release-please:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: googleapis/release-please-action@v4
|
|
15
|
+
with:
|
|
16
|
+
config-file: .release-please-config.json
|
|
17
|
+
manifest-file: .release-please-manifest.json
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.env
|
|
2
|
+
*-sa.json
|
|
3
|
+
google_oauth_client.json
|
|
4
|
+
~/.clipsmith_drive_token.json
|
|
5
|
+
.pytest-tmp/
|
|
6
|
+
.claude/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.pyc
|
|
11
|
+
*.pyo
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
site/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
|
|
19
|
+
# Pipeline artifacts
|
|
20
|
+
out/
|
|
21
|
+
work/
|
|
22
|
+
state.json
|
|
23
|
+
*.mp4
|
|
24
|
+
*.m4a
|
|
25
|
+
*.ass
|
|
26
|
+
*.srt
|
|
27
|
+
transcript.json
|
|
28
|
+
chat.json
|
|
29
|
+
picks.json
|
|
30
|
+
candidates.json
|
|
31
|
+
.coverage
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.11.10
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: local
|
|
10
|
+
hooks:
|
|
11
|
+
- id: mypy
|
|
12
|
+
name: mypy
|
|
13
|
+
entry: python -m mypy src
|
|
14
|
+
language: system
|
|
15
|
+
pass_filenames: false
|
|
16
|
+
|
|
17
|
+
- id: pytest
|
|
18
|
+
name: pytest
|
|
19
|
+
entry: python -m pytest tests/ -q
|
|
20
|
+
language: system
|
|
21
|
+
pass_filenames: false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"release-type": "python",
|
|
4
|
+
"packages": {
|
|
5
|
+
".": {}
|
|
6
|
+
},
|
|
7
|
+
"changelog-types": [
|
|
8
|
+
{"type": "feat", "section": "Features", "hidden": false},
|
|
9
|
+
{"type": "fix", "section": "Bug Fixes", "hidden": false},
|
|
10
|
+
{"type": "perf", "section": "Performance", "hidden": false},
|
|
11
|
+
{"type": "chore", "section": "Misc", "hidden": true},
|
|
12
|
+
{"type": "docs", "section": "Misc", "hidden": true},
|
|
13
|
+
{"type": "test", "section": "Misc", "hidden": true}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.0](https://github.com/ricardogr07/clipsmith/compare/v0.1.0...v0.2.0) (2026-05-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add --local flag to skip Twitch API calls for offline runs ([f7a2dd1](https://github.com/ricardogr07/clipsmith/commit/f7a2dd1c3662ca8dee8245c612284addb2a7b7cf))
|
|
9
|
+
* add process and setup commands for non-technical users ([78a6b80](https://github.com/ricardogr07/clipsmith/commit/78a6b8087c0a0b34012be5e8375486d515849e6b))
|
|
10
|
+
* add PyInstaller spec, Windows build script, and user README ([ec4ac9a](https://github.com/ricardogr07/clipsmith/commit/ec4ac9aa240beb8d248c526e8f04173e406ec6ac))
|
|
11
|
+
* add reframe=none stream-copy and transcript-sample fallback ([5d2f84c](https://github.com/ricardogr07/clipsmith/commit/5d2f84cf5457d1817b2727f923c9a4bbbc1321e4))
|
|
12
|
+
* PyPI distribution as clipsmith-ai with release-please and OIDC publish ([42673c4](https://github.com/ricardogr07/clipsmith/commit/42673c449d69bd38bb24fe74a13d101d5fcfa428))
|
|
13
|
+
* replace chat_downloader with direct Twitch GQL pagination ([44933e7](https://github.com/ricardogr07/clipsmith/commit/44933e79b628ffead0307672bf26b89aeac8c670))
|
|
14
|
+
* two-path .env discovery and bundled ffmpeg detection ([d10d6b6](https://github.com/ricardogr07/clipsmith/commit/d10d6b6482eeb9aeca4f619cf38a87b9cec9b72d))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* install ffmpeg in tests job; upgrade pip and skip editable in pip-audit ([a570434](https://github.com/ricardogr07/clipsmith/commit/a570434e23aa14608f2e80f7169e97dccc7bf353))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Documentation
|
|
23
|
+
|
|
24
|
+
* add ARCHITECTURE.md with pipeline diagram and module map ([ef554eb](https://github.com/ricardogr07/clipsmith/commit/ef554eb4999dc41e3f9c8032c3363e0ebb08f454))
|
|
25
|
+
* add Artifacts section to architecture.md ([e0a0b37](https://github.com/ricardogr07/clipsmith/commit/e0a0b37d151a0323b631a7d985d464c40f1bc78d))
|
|
26
|
+
* add MkDocs site with Material theme ([0765f6e](https://github.com/ricardogr07/clipsmith/commit/0765f6e9b9849a6b947d9a1e0a7d768476f8e0b3))
|
|
27
|
+
* refresh all docs, add SP setup, replace Colab notebook ([41c9faf](https://github.com/ricardogr07/clipsmith/commit/41c9faf3c0ea76994a00dd83f38a9124e5d2f3d1))
|
|
28
|
+
* refresh architecture, add cloud guide, update commands and configuration ([4b50d2d](https://github.com/ricardogr07/clipsmith/commit/4b50d2d1a7065f8e1484827c4a0580df027f48e2))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
FROM python:3.11-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
4
|
+
ffmpeg \
|
|
5
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
COPY pyproject.toml README.md ./
|
|
10
|
+
COPY src/ src/
|
|
11
|
+
|
|
12
|
+
# Install core pipeline only — cloud/Azure packages are local-CLI-only
|
|
13
|
+
RUN pip install --no-cache-dir -e ".[vision]"
|
|
14
|
+
|
|
15
|
+
# Bake the Whisper model so containers start immediately without downloading it.
|
|
16
|
+
# Uses the "small" model matching the default in config.yaml (transcribe.model).
|
|
17
|
+
# Rebuild the image if you switch to "medium" or "large-v3".
|
|
18
|
+
RUN python -c "from faster_whisper import WhisperModel; WhisperModel('small', device='cpu', compute_type='int8')"
|
|
19
|
+
|
|
20
|
+
VOLUME ["/app/work", "/app/out"]
|
|
21
|
+
|
|
22
|
+
ENTRYPOINT ["clipsmith"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ricardo García Ramírez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clipsmith-ai
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Twitch VOD -> AI-selected vertical clips with burned-in Spanish captions.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ricardogr07/clipsmith
|
|
6
|
+
Project-URL: Repository, https://github.com/ricardogr07/clipsmith
|
|
7
|
+
Project-URL: Documentation, https://ricardogr07.github.io/clipsmith
|
|
8
|
+
Author-email: Ricardo García Ramírez <rgr5882@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,clips,ffmpeg,llm,twitch,vertical-video,whisper
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Topic :: Multimedia :: Video
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: anthropic>=0.40
|
|
21
|
+
Requires-Dist: chat-downloader>=0.2
|
|
22
|
+
Requires-Dist: faster-whisper>=1.0
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: openai>=1.40
|
|
25
|
+
Requires-Dist: pydantic-settings>=2.2
|
|
26
|
+
Requires-Dist: pydantic>=2.6
|
|
27
|
+
Requires-Dist: python-dotenv>=1.0
|
|
28
|
+
Requires-Dist: pyyaml>=6.0
|
|
29
|
+
Requires-Dist: rich>=13.7
|
|
30
|
+
Requires-Dist: twitch-dl>=3.3
|
|
31
|
+
Requires-Dist: typer>=0.12
|
|
32
|
+
Provides-Extra: cloud
|
|
33
|
+
Requires-Dist: azure-identity>=1.16; extra == 'cloud'
|
|
34
|
+
Requires-Dist: azure-mgmt-containerinstance>=10; extra == 'cloud'
|
|
35
|
+
Requires-Dist: azure-mgmt-resource>=23; extra == 'cloud'
|
|
36
|
+
Requires-Dist: azure-mgmt-storage>=21; extra == 'cloud'
|
|
37
|
+
Requires-Dist: azure-storage-file-share>=12; extra == 'cloud'
|
|
38
|
+
Requires-Dist: google-api-python-client>=2; extra == 'cloud'
|
|
39
|
+
Requires-Dist: google-auth-oauthlib>=1; extra == 'cloud'
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: bandit>=1.7; extra == 'dev'
|
|
42
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'dev'
|
|
43
|
+
Requires-Dist: mkdocs>=1.6; extra == 'dev'
|
|
44
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
45
|
+
Requires-Dist: pip-audit>=2.7; extra == 'dev'
|
|
46
|
+
Requires-Dist: pre-commit>=3.7; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest>=9.0.3; extra == 'dev'
|
|
49
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
50
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
51
|
+
Provides-Extra: ollama
|
|
52
|
+
Requires-Dist: ollama>=0.3; extra == 'ollama'
|
|
53
|
+
Provides-Extra: vision
|
|
54
|
+
Requires-Dist: opencv-python-headless>=4.9; extra == 'vision'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# clipsmith
|
|
58
|
+
|
|
59
|
+
Local Twitch → AI clip pipeline. Downloads a VOD, transcribes Spanish audio, ranks moments by chat activity, sends candidates to an LLM, and cuts 9:16 vertical MP4s — optionally with burned-in captions and a stacked webcam/gameplay layout for TikTok / YouTube Shorts.
|
|
60
|
+
|
|
61
|
+
## Prerequisites
|
|
62
|
+
|
|
63
|
+
| Tool | Install |
|
|
64
|
+
|------|---------|
|
|
65
|
+
| Python 3.11+ | python.org or `winget install Python.Python.3` |
|
|
66
|
+
| ffmpeg | `winget install Gyan.FFmpeg` — must be on `PATH` |
|
|
67
|
+
| twitch-dl | bundled via `pip install -e .` |
|
|
68
|
+
| chat-downloader | bundled via `pip install -e .` |
|
|
69
|
+
| faster-whisper | bundled via `pip install -e .` |
|
|
70
|
+
|
|
71
|
+
Optional — webcam auto-detection:
|
|
72
|
+
```sh
|
|
73
|
+
pip install -e ".[vision]" # installs opencv-python-headless
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
git clone https://github.com/ricardogr07/clipsmith
|
|
80
|
+
cd clipsmith
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
### Secrets — `.env`
|
|
87
|
+
|
|
88
|
+
Copy `.env.example` to `.env` and fill in your keys:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
TWITCH_CLIENT_ID=...
|
|
92
|
+
TWITCH_CLIENT_SECRET=...
|
|
93
|
+
ANTHROPIC_API_KEY=... # if using provider: anthropic
|
|
94
|
+
OPENAI_API_KEY=... # if using provider: openai
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Get Twitch credentials at <https://dev.twitch.tv/console> → Register Your Application → OAuth Redirect: `http://localhost`.
|
|
98
|
+
|
|
99
|
+
### Behaviour — `config.yaml`
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
channels:
|
|
103
|
+
- chuyelwuero # Twitch logins to watch
|
|
104
|
+
|
|
105
|
+
llm:
|
|
106
|
+
provider: anthropic # anthropic | openai | ollama
|
|
107
|
+
model_anthropic: claude-sonnet-4-6
|
|
108
|
+
|
|
109
|
+
clip:
|
|
110
|
+
min_seconds: 15
|
|
111
|
+
max_seconds: 30
|
|
112
|
+
|
|
113
|
+
caption:
|
|
114
|
+
enabled: false # set true to burn subtitles into the video
|
|
115
|
+
font: Arial
|
|
116
|
+
font_size: 72 # ASS pts at 1080×1920 PlayRes
|
|
117
|
+
outline: 3
|
|
118
|
+
position: bottom # bottom | middle | top
|
|
119
|
+
|
|
120
|
+
reframe:
|
|
121
|
+
# center | webcam | stacked | none
|
|
122
|
+
mode: none
|
|
123
|
+
# Source-pixel crop for the webcam/face panel [x, y, w, h]
|
|
124
|
+
# Leave null to use center-crop fallback; set once per stream layout.
|
|
125
|
+
webcam_rect: null
|
|
126
|
+
# Source-pixel crop for the gameplay panel (stacked mode only)
|
|
127
|
+
# null = center-crop fallback
|
|
128
|
+
gameplay_rect: null
|
|
129
|
+
# Fraction of 1920px height given to the top (webcam) panel in stacked mode
|
|
130
|
+
# e.g. 0.4 → 768px webcam on top, 1152px gameplay on bottom
|
|
131
|
+
split_ratio: 0.4
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Usage
|
|
135
|
+
|
|
136
|
+
### First-time setup
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
clipsmith setup
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Saves your API key to `.env` and verifies ffmpeg is available.
|
|
143
|
+
|
|
144
|
+
### Process a local MP4
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
clipsmith process path/to/recording.mp4
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Runs the full pipeline — transcribe → score candidates → LLM selection → cut clips. Clips appear in `out/<video_id>/`.
|
|
151
|
+
|
|
152
|
+
Useful flags:
|
|
153
|
+
|
|
154
|
+
| Flag | Effect |
|
|
155
|
+
|------|--------|
|
|
156
|
+
| `--skip-transcribe` | Load cached `transcript.json` |
|
|
157
|
+
| `--captions / --no-captions` | Override caption config |
|
|
158
|
+
| `--reframe / --no-reframe` | Override reframe config |
|
|
159
|
+
| `--provider anthropic\|openai` | Override LLM provider |
|
|
160
|
+
|
|
161
|
+
### Daemon mode
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
clipsmith watch
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Polls every `poll_interval_s` seconds (default 120). When a new archive VOD appears it runs the full pipeline automatically. State is persisted to `state.json` so already-processed VODs are skipped across restarts.
|
|
168
|
+
|
|
169
|
+
### One-off Twitch VOD
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
clipsmith run-vod <video_id>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Useful flags:
|
|
176
|
+
|
|
177
|
+
| Flag | Effect |
|
|
178
|
+
|------|--------|
|
|
179
|
+
| `--skip-download` | Use the existing `.mp4` in `work/<id>/` |
|
|
180
|
+
| `--skip-transcribe` | Load cached `transcript.json` |
|
|
181
|
+
| `--skip-chat` | Load cached `chat.json` |
|
|
182
|
+
| `--skip-select` | Stop after candidates, skip LLM |
|
|
183
|
+
| `--skip-clip` | Stop after picks, skip ffmpeg |
|
|
184
|
+
| `--provider anthropic\|openai` | Override config LLM |
|
|
185
|
+
| `--max-candidates N` | Cap candidates sent to LLM (default 20) |
|
|
186
|
+
|
|
187
|
+
### Re-cut flat clips
|
|
188
|
+
|
|
189
|
+
Re-run only the ffmpeg step from an existing `picks.json` (e.g. after adjusting caption style):
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
clipsmith clip <video_id>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Stacked vertical layout (webcam + gameplay)
|
|
196
|
+
|
|
197
|
+
After reviewing the flat clips, pick the best ones and reframe them into a stacked 9:16 layout — webcam on top, gameplay on bottom:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
clipsmith reframe <video_id> clip_01 clip_04 clip_09
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Output goes to `out/<video_id>/stacked/`. The reframe rects come from `config.yaml`; see the `reframe` section above.
|
|
204
|
+
|
|
205
|
+
**Auto-detecting the webcam rect:**
|
|
206
|
+
|
|
207
|
+
If `reframe.webcam_rect` is not set in `config.yaml`, clipsmith will try to detect the face rectangle automatically using OpenCV (requires `pip install -e ".[vision]"`). The result is cached to `work/<video_id>/webcam_rect.json` and reused on subsequent runs.
|
|
208
|
+
|
|
209
|
+
To run detection manually and write the result directly into `config.yaml`:
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
clipsmith detect-webcam <video_id>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
This samples frames, detects the webcam rectangle, and saves `reframe.webcam_rect` in `config.yaml` automatically — no manual copy-paste needed.
|
|
216
|
+
|
|
217
|
+
### Sanity check
|
|
218
|
+
|
|
219
|
+
```sh
|
|
220
|
+
clipsmith whoami chuyelwuero
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Output
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
work/
|
|
227
|
+
<video_id>/
|
|
228
|
+
<video_id>.mp4 downloaded (or copied) source VOD
|
|
229
|
+
transcript.json faster-whisper segments + word timestamps
|
|
230
|
+
chat.json chat replay
|
|
231
|
+
candidates.json ranked candidate moments
|
|
232
|
+
picks.json LLM-accepted clips with titles and reasons
|
|
233
|
+
webcam_rect.json auto-detected webcam rect (cached, vision only)
|
|
234
|
+
|
|
235
|
+
out/
|
|
236
|
+
<video_id>/
|
|
237
|
+
clip_01_momento_gracioso.mp4 flat 9:16 clip
|
|
238
|
+
clip_01_momento_gracioso.ass sidecar ASS subtitle file
|
|
239
|
+
clip_02_reaccion_epica.mp4
|
|
240
|
+
...
|
|
241
|
+
stacked/
|
|
242
|
+
clip_01_momento_gracioso.mp4 stacked layout (webcam top, gameplay bottom)
|
|
243
|
+
clip_04_reaccion_epica.mp4
|
|
244
|
+
...
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
All clips are 1080×1920 (9:16), 15–30 s, h264/aac, with optional burned-in Spanish karaoke captions.
|
|
248
|
+
|
|
249
|
+
## Pipeline overview
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
watch / run-vod / process
|
|
253
|
+
↓
|
|
254
|
+
downloader (twitch-dl) → work/<id>/<id>.mp4
|
|
255
|
+
↓
|
|
256
|
+
detect-webcam (opencv Haar cascade) → work/<id>/webcam_rect.json [optional]
|
|
257
|
+
↓
|
|
258
|
+
transcribe (faster-whisper) → transcript.json (word timestamps, lang=es)
|
|
259
|
+
↓
|
|
260
|
+
chat (chat-downloader) → chat.json
|
|
261
|
+
↓
|
|
262
|
+
candidates (density + clips + !clip) → candidates.json
|
|
263
|
+
↓
|
|
264
|
+
selector (LLM) → picks.json
|
|
265
|
+
↓
|
|
266
|
+
clipper (ffmpeg + libass) → out/<id>/clip_NN_<title>.mp4
|
|
267
|
+
↓ [manual: clipsmith reframe]
|
|
268
|
+
reframe (ffmpeg filter_complex) → out/<id>/stacked/clip_NN_<title>.mp4
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Development
|
|
272
|
+
|
|
273
|
+
```sh
|
|
274
|
+
pip install -e ".[dev]"
|
|
275
|
+
pip install -e ".[vision]" # optional, for detect-webcam tests
|
|
276
|
+
python -m pytest tests -q
|
|
277
|
+
```
|