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.
Files changed (112) hide show
  1. clipsmith_ai-0.2.0/.dockerignore +38 -0
  2. clipsmith_ai-0.2.0/.env.example +29 -0
  3. clipsmith_ai-0.2.0/.github/workflows/ci.yml +41 -0
  4. clipsmith_ai-0.2.0/.github/workflows/e2e-cloud.yml +19 -0
  5. clipsmith_ai-0.2.0/.github/workflows/e2e.yml +20 -0
  6. clipsmith_ai-0.2.0/.github/workflows/publish.yml +20 -0
  7. clipsmith_ai-0.2.0/.github/workflows/release-please.yml +17 -0
  8. clipsmith_ai-0.2.0/.gitignore +31 -0
  9. clipsmith_ai-0.2.0/.pre-commit-config.yaml +21 -0
  10. clipsmith_ai-0.2.0/.release-please-config.json +15 -0
  11. clipsmith_ai-0.2.0/.release-please-manifest.json +3 -0
  12. clipsmith_ai-0.2.0/CHANGELOG.md +28 -0
  13. clipsmith_ai-0.2.0/Dockerfile +22 -0
  14. clipsmith_ai-0.2.0/LICENSE +21 -0
  15. clipsmith_ai-0.2.0/PKG-INFO +277 -0
  16. clipsmith_ai-0.2.0/README.md +221 -0
  17. clipsmith_ai-0.2.0/clipsmith.spec +76 -0
  18. clipsmith_ai-0.2.0/config.yaml +83 -0
  19. clipsmith_ai-0.2.0/docs/architecture.md +326 -0
  20. clipsmith_ai-0.2.0/docs/cloud.md +294 -0
  21. clipsmith_ai-0.2.0/docs/commands.md +227 -0
  22. clipsmith_ai-0.2.0/docs/configuration.md +207 -0
  23. clipsmith_ai-0.2.0/docs/dev/azure-cloud-setup.md +206 -0
  24. clipsmith_ai-0.2.0/docs/dev/contributing.md +129 -0
  25. clipsmith_ai-0.2.0/docs/examples.md +120 -0
  26. clipsmith_ai-0.2.0/docs/getting-started.md +111 -0
  27. clipsmith_ai-0.2.0/docs/index.md +55 -0
  28. clipsmith_ai-0.2.0/examples/01_local_mp4.ipynb +201 -0
  29. clipsmith_ai-0.2.0/examples/02_local_vod.ipynb +180 -0
  30. clipsmith_ai-0.2.0/examples/03_local_vod_ollama.ipynb +230 -0
  31. clipsmith_ai-0.2.0/examples/04_cloud.ipynb +190 -0
  32. clipsmith_ai-0.2.0/infra/clipsmith-runner-role.json +23 -0
  33. clipsmith_ai-0.2.0/main.py +12 -0
  34. clipsmith_ai-0.2.0/mkdocs.yml +42 -0
  35. clipsmith_ai-0.2.0/pyproject.toml +98 -0
  36. clipsmith_ai-0.2.0/scripts/build_windows.ps1 +53 -0
  37. clipsmith_ai-0.2.0/src/clipsmith/__init__.py +6 -0
  38. clipsmith_ai-0.2.0/src/clipsmith/__main__.py +4 -0
  39. clipsmith_ai-0.2.0/src/clipsmith/candidates/__init__.py +1 -0
  40. clipsmith_ai-0.2.0/src/clipsmith/candidates/audio.py +110 -0
  41. clipsmith_ai-0.2.0/src/clipsmith/candidates/builder.py +214 -0
  42. clipsmith_ai-0.2.0/src/clipsmith/candidates/math.py +48 -0
  43. clipsmith_ai-0.2.0/src/clipsmith/cli/__init__.py +27 -0
  44. clipsmith_ai-0.2.0/src/clipsmith/cli/clip.py +153 -0
  45. clipsmith_ai-0.2.0/src/clipsmith/cli/cloud.py +259 -0
  46. clipsmith_ai-0.2.0/src/clipsmith/cli/run.py +252 -0
  47. clipsmith_ai-0.2.0/src/clipsmith/cli/setup.py +242 -0
  48. clipsmith_ai-0.2.0/src/clipsmith/cli/utils.py +35 -0
  49. clipsmith_ai-0.2.0/src/clipsmith/cloud/__init__.py +0 -0
  50. clipsmith_ai-0.2.0/src/clipsmith/cloud/azure_runner.py +278 -0
  51. clipsmith_ai-0.2.0/src/clipsmith/cloud/drive_upload.py +180 -0
  52. clipsmith_ai-0.2.0/src/clipsmith/cloud/provisioner.py +107 -0
  53. clipsmith_ai-0.2.0/src/clipsmith/config/__init__.py +1 -0
  54. clipsmith_ai-0.2.0/src/clipsmith/config/loaders.py +52 -0
  55. clipsmith_ai-0.2.0/src/clipsmith/config/models.py +85 -0
  56. clipsmith_ai-0.2.0/src/clipsmith/io/__init__.py +1 -0
  57. clipsmith_ai-0.2.0/src/clipsmith/io/media.py +24 -0
  58. clipsmith_ai-0.2.0/src/clipsmith/llm/__init__.py +24 -0
  59. clipsmith_ai-0.2.0/src/clipsmith/llm/anthropic_provider.py +80 -0
  60. clipsmith_ai-0.2.0/src/clipsmith/llm/base.py +75 -0
  61. clipsmith_ai-0.2.0/src/clipsmith/llm/ollama_provider.py +50 -0
  62. clipsmith_ai-0.2.0/src/clipsmith/llm/openai_provider.py +68 -0
  63. clipsmith_ai-0.2.0/src/clipsmith/llm/prompts.py +87 -0
  64. clipsmith_ai-0.2.0/src/clipsmith/models/__init__.py +1 -0
  65. clipsmith_ai-0.2.0/src/clipsmith/models/candidates.py +16 -0
  66. clipsmith_ai-0.2.0/src/clipsmith/models/chat.py +53 -0
  67. clipsmith_ai-0.2.0/src/clipsmith/models/transcript.py +47 -0
  68. clipsmith_ai-0.2.0/src/clipsmith/models/twitch.py +31 -0
  69. clipsmith_ai-0.2.0/src/clipsmith/pipeline.py +192 -0
  70. clipsmith_ai-0.2.0/src/clipsmith/rendering/__init__.py +1 -0
  71. clipsmith_ai-0.2.0/src/clipsmith/rendering/captions.py +135 -0
  72. clipsmith_ai-0.2.0/src/clipsmith/rendering/clipper.py +194 -0
  73. clipsmith_ai-0.2.0/src/clipsmith/rendering/detect.py +231 -0
  74. clipsmith_ai-0.2.0/src/clipsmith/selection/__init__.py +1 -0
  75. clipsmith_ai-0.2.0/src/clipsmith/selection/selector.py +127 -0
  76. clipsmith_ai-0.2.0/src/clipsmith/settings.py +27 -0
  77. clipsmith_ai-0.2.0/src/clipsmith/transcription/__init__.py +1 -0
  78. clipsmith_ai-0.2.0/src/clipsmith/transcription/transcriber.py +235 -0
  79. clipsmith_ai-0.2.0/src/clipsmith/twitch/__init__.py +1 -0
  80. clipsmith_ai-0.2.0/src/clipsmith/twitch/chat.py +122 -0
  81. clipsmith_ai-0.2.0/src/clipsmith/twitch/client.py +150 -0
  82. clipsmith_ai-0.2.0/src/clipsmith/twitch/downloader.py +77 -0
  83. clipsmith_ai-0.2.0/src/clipsmith/twitch/state.py +31 -0
  84. clipsmith_ai-0.2.0/src/clipsmith/twitch/watcher.py +59 -0
  85. clipsmith_ai-0.2.0/tests/conftest.py +30 -0
  86. clipsmith_ai-0.2.0/tests/e2e/conftest.py +11 -0
  87. clipsmith_ai-0.2.0/tests/e2e/test_cloud.py +119 -0
  88. clipsmith_ai-0.2.0/tests/e2e/test_pipeline.py +132 -0
  89. clipsmith_ai-0.2.0/tests/helpers.py +17 -0
  90. clipsmith_ai-0.2.0/tests/integration/candidates/test_audio.py +49 -0
  91. clipsmith_ai-0.2.0/tests/integration/cloud/test_azure_runner.py +273 -0
  92. clipsmith_ai-0.2.0/tests/integration/cloud/test_drive_upload.py +210 -0
  93. clipsmith_ai-0.2.0/tests/integration/cloud/test_provisioner.py +175 -0
  94. clipsmith_ai-0.2.0/tests/integration/conftest.py +11 -0
  95. clipsmith_ai-0.2.0/tests/integration/llm/test_ollama_provider.py +90 -0
  96. clipsmith_ai-0.2.0/tests/integration/transcription/test_transcriber.py +22 -0
  97. clipsmith_ai-0.2.0/tests/integration/twitch/test_client.py +159 -0
  98. clipsmith_ai-0.2.0/tests/integration/twitch/test_downloader.py +52 -0
  99. clipsmith_ai-0.2.0/tests/smoke/cli/test_cli.py +90 -0
  100. clipsmith_ai-0.2.0/tests/smoke/cli/test_cli_cloud.py +261 -0
  101. clipsmith_ai-0.2.0/tests/smoke/config/test_settings.py +37 -0
  102. clipsmith_ai-0.2.0/tests/smoke/conftest.py +11 -0
  103. clipsmith_ai-0.2.0/tests/unit/candidates/test_audio.py +27 -0
  104. clipsmith_ai-0.2.0/tests/unit/candidates/test_builder.py +207 -0
  105. clipsmith_ai-0.2.0/tests/unit/conftest.py +11 -0
  106. clipsmith_ai-0.2.0/tests/unit/models/test_transcript.py +68 -0
  107. clipsmith_ai-0.2.0/tests/unit/rendering/test_captions.py +149 -0
  108. clipsmith_ai-0.2.0/tests/unit/rendering/test_clipper.py +188 -0
  109. clipsmith_ai-0.2.0/tests/unit/selection/test_clip_pick.py +92 -0
  110. clipsmith_ai-0.2.0/tests/unit/selection/test_selector.py +173 -0
  111. clipsmith_ai-0.2.0/tests/unit/transcription/test_transcriber.py +96 -0
  112. 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,3 @@
1
+ {
2
+ ".": "0.2.0"
3
+ }
@@ -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
+ ```