factreel 0.1.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 (62) hide show
  1. factreel-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +27 -0
  2. factreel-0.1.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
  3. factreel-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +16 -0
  4. factreel-0.1.0/.github/pull_request_template.md +6 -0
  5. factreel-0.1.0/.github/workflows/ci.yml +40 -0
  6. factreel-0.1.0/.github/workflows/publish.yml +19 -0
  7. factreel-0.1.0/.gitignore +13 -0
  8. factreel-0.1.0/CHANGELOG.md +18 -0
  9. factreel-0.1.0/CODE_OF_CONDUCT.md +7 -0
  10. factreel-0.1.0/CONTRIBUTING.md +39 -0
  11. factreel-0.1.0/LICENSE +21 -0
  12. factreel-0.1.0/PKG-INFO +178 -0
  13. factreel-0.1.0/README.es.md +120 -0
  14. factreel-0.1.0/README.md +142 -0
  15. factreel-0.1.0/ROADMAP.md +25 -0
  16. factreel-0.1.0/SECURITY.md +8 -0
  17. factreel-0.1.0/docs/configuration.md +156 -0
  18. factreel-0.1.0/docs/demo.gif +0 -0
  19. factreel-0.1.0/docs/providers.md +46 -0
  20. factreel-0.1.0/docs/scheduling.md +34 -0
  21. factreel-0.1.0/docs/youtube.md +21 -0
  22. factreel-0.1.0/pyproject.toml +67 -0
  23. factreel-0.1.0/src/factreel/__init__.py +2 -0
  24. factreel-0.1.0/src/factreel/__main__.py +5 -0
  25. factreel-0.1.0/src/factreel/cli.py +185 -0
  26. factreel-0.1.0/src/factreel/cloudflare.py +70 -0
  27. factreel-0.1.0/src/factreel/config.py +209 -0
  28. factreel-0.1.0/src/factreel/doctor.py +123 -0
  29. factreel-0.1.0/src/factreel/facts.py +128 -0
  30. factreel-0.1.0/src/factreel/images/__init__.py +86 -0
  31. factreel-0.1.0/src/factreel/images/common.py +59 -0
  32. factreel-0.1.0/src/factreel/images/providers.py +194 -0
  33. factreel-0.1.0/src/factreel/lang.py +116 -0
  34. factreel-0.1.0/src/factreel/llm.py +81 -0
  35. factreel-0.1.0/src/factreel/log.py +43 -0
  36. factreel-0.1.0/src/factreel/metadata.py +92 -0
  37. factreel-0.1.0/src/factreel/pipeline.py +95 -0
  38. factreel-0.1.0/src/factreel/render.py +169 -0
  39. factreel-0.1.0/src/factreel/script.py +204 -0
  40. factreel-0.1.0/src/factreel/subtitles.py +108 -0
  41. factreel-0.1.0/src/factreel/templates/en/channel.toml +69 -0
  42. factreel-0.1.0/src/factreel/templates/en/env.example +6 -0
  43. factreel-0.1.0/src/factreel/templates/en/facts.json +61 -0
  44. factreel-0.1.0/src/factreel/templates/en/gitignore +5 -0
  45. factreel-0.1.0/src/factreel/templates/en/music/credits.json +3 -0
  46. factreel-0.1.0/src/factreel/templates/en/queue.txt +2 -0
  47. factreel-0.1.0/src/factreel/templates/es/channel.toml +72 -0
  48. factreel-0.1.0/src/factreel/templates/es/env.example +6 -0
  49. factreel-0.1.0/src/factreel/templates/es/facts.json +61 -0
  50. factreel-0.1.0/src/factreel/templates/es/gitignore +5 -0
  51. factreel-0.1.0/src/factreel/templates/es/music/credits.json +3 -0
  52. factreel-0.1.0/src/factreel/templates/es/queue.txt +2 -0
  53. factreel-0.1.0/src/factreel/tts/__init__.py +67 -0
  54. factreel-0.1.0/src/factreel/tts/providers.py +195 -0
  55. factreel-0.1.0/src/factreel/tts/timing.py +91 -0
  56. factreel-0.1.0/src/factreel/youtube.py +120 -0
  57. factreel-0.1.0/tests/__init__.py +0 -0
  58. factreel-0.1.0/tests/conftest.py +33 -0
  59. factreel-0.1.0/tests/test_facts.py +47 -0
  60. factreel-0.1.0/tests/test_media.py +86 -0
  61. factreel-0.1.0/tests/test_pipeline.py +39 -0
  62. factreel-0.1.0/tests/test_script.py +120 -0
@@ -0,0 +1,27 @@
1
+ name: Bug report / Error
2
+ description: Something doesn't work / Algo no funciona
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what
7
+ attributes:
8
+ label: What happened? / ¿Qué pasó?
9
+ description: Command you ran and what you expected.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: doctor
14
+ attributes:
15
+ label: Output of `factreel doctor`
16
+ render: text
17
+ - type: textarea
18
+ id: log
19
+ attributes:
20
+ label: Log (logs/factreel_YYYY-MM.log), without API keys
21
+ render: text
22
+ - type: input
23
+ id: version
24
+ attributes:
25
+ label: factreel --version, OS and Python version
26
+ validations:
27
+ required: true
@@ -0,0 +1 @@
1
+ blank_issues_enabled: true
@@ -0,0 +1,16 @@
1
+ name: Feature or provider request / Propuesta
2
+ description: Idea, new language, new voice/image provider or uploader
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: idea
7
+ attributes:
8
+ label: What would you like? / ¿Qué te gustaría?
9
+ validations:
10
+ required: true
11
+ - type: checkboxes
12
+ id: help
13
+ attributes:
14
+ label: Contribution
15
+ options:
16
+ - label: I'd like to implement it myself / Me gustaría implementarlo yo
@@ -0,0 +1,6 @@
1
+ ## What and why / Qué y por qué
2
+
3
+ ## Checklist
4
+ - [ ] Tests added or updated (`pytest` passes)
5
+ - [ ] `ruff check .` passes
6
+ - [ ] Docs / CHANGELOG updated if behaviour changed
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os: [ubuntu-latest, windows-latest, macos-latest]
14
+ python: ["3.10", "3.13"]
15
+ runs-on: ${{ matrix.os }}
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python }}
21
+ - name: Install FFmpeg (Linux)
22
+ if: runner.os == 'Linux'
23
+ run: sudo apt-get update && sudo apt-get install -y ffmpeg
24
+ - name: Install FFmpeg (macOS)
25
+ if: runner.os == 'macOS'
26
+ run: brew install ffmpeg
27
+ - name: Install FFmpeg (Windows)
28
+ if: runner.os == 'Windows'
29
+ uses: FedericoCarboni/setup-ffmpeg@v3
30
+ - run: pip install -e ".[dev]"
31
+ - run: ruff check .
32
+ - name: Tests
33
+ shell: bash
34
+ run: |
35
+ set -o pipefail
36
+ pytest -q -rf --tb=line 2>&1 | tee pytest.log || { grep -E "^(FAILED|E |/|.*Error)" pytest.log | head -15 | sed 's/^/::error::/'; ffmpeg -hide_banner -filters 2>/dev/null | grep -E " (ass|xfade|loudnorm) " | sed 's/^/::warning::filter /'; exit 1; }
37
+ - name: End-to-end preview video
38
+ run: |
39
+ factreel init demo --lang es
40
+ factreel make -c demo --offline --voice dummy --no-history
@@ -0,0 +1,19 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write # trusted publishing, no API token needed
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+ - run: pip install build && python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .env
10
+ .factreel/
11
+ client_secrets.json
12
+ *.mp4
13
+ !docs/*.mp4
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/) and the project uses [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.1.0] - 2026-10-20
7
+
8
+ ### Added
9
+ - First public release, extracted from a channel that publishes a Short every day.
10
+ - Fact-grounded script writer for any OpenAI-compatible LLM, with number, repetition and rumour guards,
11
+ a fact-check pass and a facts-only fallback.
12
+ - Voice chain: Edge, ElevenLabs, Cloudflare Aura, system voice, dummy; health tracking.
13
+ - Image chain: Cloudflare FLUX, NVIDIA FLUX, custom command, archive, procedural gradient.
14
+ - Word-by-word ASS subtitles, jitter-free zoom, cross-fades, loudness normalisation, music with credits.
15
+ - Spanish and English templates; `init`, `make`, `topics`, `doctor`, `upload`, `run` commands.
16
+ - Optional YouTube upload with synthetic-media declaration.
17
+ - Works with FFmpeg builds without libass (e.g. Homebrew's `ffmpeg`): the video is rendered without burned
18
+ subtitles and a warning explains how to get a full build.
@@ -0,0 +1,7 @@
1
+ # Code of Conduct
2
+
3
+ This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
4
+
5
+ In short: be kind, assume good intent, welcome newcomers and people of every background and language,
6
+ and keep discussions about the work. Report unacceptable behaviour privately to the maintainer through
7
+ [GitHub](https://github.com/DeadY2J) (or a private security advisory); reports are handled confidentially.
@@ -0,0 +1,39 @@
1
+ # Contributing to FactReel
2
+
3
+ Thanks for helping! Issues and pull requests are welcome **in English or Spanish** (también en español).
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/DeadY2J/factreel
9
+ cd factreel
10
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
11
+ pip install -e ".[dev,youtube]"
12
+ pytest # needs ffmpeg for the end-to-end test (it is skipped otherwise)
13
+ ruff check .
14
+ ```
15
+
16
+ Try your change on a real channel without spending API credits:
17
+
18
+ ```bash
19
+ factreel init /tmp/test-channel --lang es
20
+ factreel make -c /tmp/test-channel --offline --voice dummy --no-history
21
+ ```
22
+
23
+ ## Good first contributions
24
+
25
+ - **A new language**: add an entry to `LANGS` in `src/factreel/lang.py` (prompts, month names, call-to-action
26
+ regex, default Edge voice), a template in `src/factreel/templates/<lang>/` and a test.
27
+ - **A new voice or image provider**: see [docs/providers.md](docs/providers.md).
28
+ - **A new uploader** (TikTok, Instagram Reels…): mirror `src/factreel/youtube.py`.
29
+ - Anything in the [roadmap](ROADMAP.md) or labelled `good first issue`.
30
+
31
+ ## Guidelines
32
+
33
+ - Keep the guarantees: never let the script state something that isn't in the facts, never block a video
34
+ because one optional service is down, never put secrets in config files.
35
+ - New behaviour needs a test. Network calls must be mockable; tests must pass offline.
36
+ - Keep dependencies light: optional features go in an extra (`[project.optional-dependencies]`).
37
+ - Format with `ruff`. One topic per pull request, with a short description of the why.
38
+
39
+ By contributing you agree that your contributions are licensed under the MIT license.
factreel-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jorge Lamelas
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,178 @@
1
+ Metadata-Version: 2.5
2
+ Name: factreel
3
+ Version: 0.1.0
4
+ Summary: Fact-checked faceless short videos (YouTube Shorts, TikTok, Reels) from a list of verified facts: AI script with anti-hallucination guards, voice fallback chain, karaoke subtitles and FFmpeg render.
5
+ Project-URL: Homepage, https://github.com/DeadY2J/factreel
6
+ Project-URL: Issues, https://github.com/DeadY2J/factreel/issues
7
+ Project-URL: Changelog, https://github.com/DeadY2J/factreel/blob/main/CHANGELOG.md
8
+ Author-email: Jorge Lamelas <205297977+DeadY2J@users.noreply.github.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: edge-tts,faceless,fact-checking,ffmpeg,llm,reels,spanish,subtitles,text-to-speech,tiktok,video-automation,youtube-shorts
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Natural Language :: English
17
+ Classifier: Natural Language :: Spanish
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
22
+ Classifier: Topic :: Multimedia :: Video
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: edge-tts>=7.3.1
25
+ Requires-Dist: pillow>=10.0
26
+ Requires-Dist: requests>=2.31
27
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8; extra == 'dev'
30
+ Requires-Dist: ruff>=0.6; extra == 'dev'
31
+ Provides-Extra: youtube
32
+ Requires-Dist: google-api-python-client>=2.100; extra == 'youtube'
33
+ Requires-Dist: google-auth-oauthlib>=1.1; extra == 'youtube'
34
+ Requires-Dist: google-auth>=2.23; extra == 'youtube'
35
+ Description-Content-Type: text/markdown
36
+
37
+ <div align="center">
38
+
39
+ # FactReel 🎬✅
40
+
41
+ **Fact-checked faceless short videos, on autopilot.**
42
+ YouTube Shorts · TikTok · Reels, from a list of verified facts, with free AI services and a fallback for everything.
43
+
44
+ [![CI](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml/badge.svg)](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml)
45
+ [![PyPI](https://img.shields.io/pypi/v/factreel.svg)](https://pypi.org/project/factreel/)
46
+ [![Python](https://img.shields.io/pypi/pyversions/factreel.svg)](https://pypi.org/project/factreel/)
47
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
48
+
49
+ [English](README.md) · [Español](README.es.md)
50
+
51
+ <img src="docs/demo.gif" width="260" alt="FactReel demo: vertical video with word-by-word subtitles">
52
+
53
+ </div>
54
+
55
+ ---
56
+
57
+ Most "AI shorts generators" let a language model make things up. **FactReel doesn't.** You write the facts
58
+ (with sources) once; the AI only turns them into a punchy script, and every script goes through guards that
59
+ reject invented numbers, repeated ideas, unlabelled rumours and anything a second fact-checking pass can't
60
+ find in your facts. Then it narrates it, draws the images, burns karaoke subtitles and renders a vertical
61
+ MP4 ready to upload.
62
+
63
+ It grew out of a real channel that publishes a Short every day unattended, so it is built to **never stop
64
+ on a bad day**: if the voice service, the image API or the script AI is down, the next option in the chain
65
+ takes over.
66
+
67
+ ## Features
68
+
69
+ - 🛡️ **Anti-hallucination script writer**: number whitelist, repetition check, rumour labelling, a
70
+ temperature-0 fact-check pass, and a facts-only fallback that is always correct.
71
+ - 🗣️ **Voice fallback chain**: Microsoft Edge neural voices (free, no key) → ElevenLabs → Cloudflare
72
+ Aura → your OS's offline voice. `factreel doctor` tells you when a service is down and when it is back.
73
+ - 🖼️ **Image fallback chain**: Cloudflare Workers AI FLUX → NVIDIA NIM FLUX → your own generator
74
+ (local GPU, ComfyUI…) → archive of previous images → procedural background that always works offline.
75
+ - 💬 **Word-by-word subtitles** with the spoken word highlighted, synced from the TTS engine or Whisper.
76
+ - 🎞️ **Smooth Ken Burns zoom without jitter** (sub-pixel rendering), cross-fades on scene changes,
77
+ voice normalised to -14 LUFS, optional background music with automatic credits.
78
+ - 🌍 **Spanish and English first-class** (prompts, month names, countdowns). More languages = one dict.
79
+ - 💸 **Free by default**: runs with zero API keys; every paid service is optional and budget-capped.
80
+ - 🔌 **Any OpenAI-compatible LLM**: NVIDIA NIM, OpenRouter, Groq, OpenAI, Ollama, LM Studio, OmniRoute…
81
+ - 📤 **Optional YouTube upload** with the "altered or synthetic content" flag set for you.
82
+ - ✅ **Verifies every render** (resolution, audio, no black screen) before it reaches the upload queue.
83
+
84
+ ## Quick start
85
+
86
+ You need **Python 3.10+** and **[FFmpeg](https://ffmpeg.org/download.html)** on your PATH.
87
+
88
+ ```bash
89
+ pip install factreel
90
+ factreel init my-channel --lang en # or --lang es
91
+ cd my-channel
92
+ factreel doctor # checks FFmpeg, keys and every voice
93
+ factreel make # -> output/20261020_180000_venus_day.mp4 (+ .json/.txt metadata)
94
+ ```
95
+
96
+ That's it: with no keys at all you get a video with the free Edge voice, the facts read as they are and
97
+ offline backgrounds. Add free keys to `.env` to unlock the AI script and AI images:
98
+
99
+ | Key | What it unlocks | Cost |
100
+ | --- | --- | --- |
101
+ | `NVIDIA_API_KEY` ([build.nvidia.com](https://build.nvidia.com)) | AI script + fact check, FLUX images | free credits |
102
+ | `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` | FLUX images, backup voice, exact subtitle timing (Whisper) | 10,000 free neurons/day, capped |
103
+ | `ELEVENLABS_API_KEY` | premium voice | optional |
104
+
105
+ ## How it works
106
+
107
+ ```mermaid
108
+ flowchart LR
109
+ F[facts.json<br/>verified facts + sources] --> T[topic rotation<br/>queue.txt / least used]
110
+ T --> S[AI script]
111
+ S --> G{guards<br/>numbers · repeats<br/>rumours · fact check}
112
+ G -- rejected --> S
113
+ G -- gives up --> FB[facts-only script]
114
+ G -- ok --> V[voice chain]
115
+ FB --> V
116
+ V --> SUB[karaoke subtitles]
117
+ V --> I[image chain]
118
+ SUB --> R[FFmpeg render + verify]
119
+ I --> R
120
+ R --> O[output/*.mp4 + metadata] --> U[YouTube upload]
121
+ ```
122
+
123
+ ## Your facts
124
+
125
+ ```json
126
+ {
127
+ "topics": [
128
+ {
129
+ "id": "venus_day",
130
+ "angle": "a day on Venus is longer than its year",
131
+ "facts": [
132
+ "Venus takes about 243 Earth days to spin once on its axis.",
133
+ "Venus takes about 225 Earth days to orbit the Sun."
134
+ ],
135
+ "sources": ["https://science.nasa.gov/venus/venus-facts/"],
136
+ "hashtags": ["#venus"],
137
+ "weight": 2
138
+ }
139
+ ]
140
+ }
141
+ ```
142
+
143
+ Prefix unconfirmed news with `RUMOR:` and the script will be forced to say so. Put topic ids in
144
+ `queue.txt` to choose what goes out next; otherwise the least used topic is picked (`weight` > 1 = more often).
145
+
146
+ ## Commands
147
+
148
+ | Command | What it does |
149
+ | --- | --- |
150
+ | `factreel init DIR --lang es` | new channel folder from a template |
151
+ | `factreel make [-t TOPIC] [-n 3]` | generate videos into `output/` |
152
+ | `factreel make --offline --voice dummy` | instant preview: no AI, silent voice, offline images |
153
+ | `factreel topics` | topics and how many times each was used |
154
+ | `factreel doctor [--voices --log]` | check everything; `--log` is perfect for a scheduled task |
155
+ | `factreel upload [--privacy unlisted]` | upload pending videos to YouTube (`pip install "factreel[youtube]"`) |
156
+ | `factreel run` | make + upload, for a daily scheduled task |
157
+
158
+ ## Documentation
159
+
160
+ - [Configuration reference](docs/configuration.md): every `channel.toml` option
161
+ - [Providers](docs/providers.md): voices, images, LLMs and how to add your own
162
+ - [YouTube upload](docs/youtube.md): OAuth setup in 5 minutes
163
+ - [Scheduling](docs/scheduling.md): Windows Task Scheduler, cron, GitHub Actions
164
+
165
+ ## Responsible use
166
+
167
+ FactReel declares AI-generated media when uploading, never invents facts on its own, and labels rumours.
168
+ Please keep it that way: cite your sources, respect trademarks and music licences, and don't use it to
169
+ mass-produce misleading content. Platforms penalise low-effort spam; good facts make good videos.
170
+
171
+ ## Contributing
172
+
173
+ Contributions are very welcome, especially new languages, voice/image providers and platform uploaders.
174
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the [roadmap](ROADMAP.md) for good first issues.
175
+
176
+ ## License
177
+
178
+ [MIT](LICENSE) © Jorge Lamelas
@@ -0,0 +1,120 @@
1
+ <div align="center">
2
+
3
+ # FactReel 🎬✅
4
+
5
+ **Vídeos cortos sin cara, con datos verificados y en piloto automático.**
6
+ YouTube Shorts · TikTok · Reels a partir de una lista de hechos verificados, con servicios de IA gratuitos y un plan B para todo.
7
+
8
+ [![CI](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml/badge.svg)](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml)
9
+ [![PyPI](https://img.shields.io/pypi/v/factreel.svg)](https://pypi.org/project/factreel/)
10
+ [![Licencia: MIT](https://img.shields.io/badge/licencia-MIT-green.svg)](LICENSE)
11
+
12
+ [English](README.md) · [Español](README.es.md)
13
+
14
+ <img src="docs/demo.gif" width="260" alt="Demo de FactReel: vídeo vertical con subtítulos palabra a palabra">
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ La mayoría de los generadores de Shorts con IA dejan que el modelo se invente cosas. **FactReel no.** Tú
21
+ escribes los hechos (con sus fuentes) una vez; la IA solo los convierte en un guion con gancho, y cada guion
22
+ pasa por controles que rechazan cifras inventadas, ideas repetidas, rumores sin avisar y cualquier cosa que
23
+ una segunda pasada de verificación no encuentre en tus hechos. Después lo narra, genera las imágenes, pone
24
+ subtítulos tipo karaoke y renderiza un MP4 vertical listo para subir.
25
+
26
+ Nace de un canal real que publica un Short cada día sin intervención, así que está hecho para **no pararse
27
+ nunca por un mal día**: si se cae la voz, la API de imágenes o la IA del guion, entra la siguiente opción.
28
+
29
+ ## Qué incluye
30
+
31
+ - 🛡️ **Guionista con controles anti-invenciones**: lista blanca de cifras, detección de repeticiones,
32
+ rumores etiquetados, verificación a temperatura 0 y un guion de reserva solo con los hechos, siempre correcto.
33
+ - 🗣️ **Cadena de voces**: voces neuronales de Microsoft Edge (gratis, sin clave) → ElevenLabs → Cloudflare
34
+ Aura → la voz sin conexión de tu sistema. `factreel doctor` te avisa cuando un servicio cae y cuando vuelve.
35
+ - 🖼️ **Cadena de imágenes**: FLUX en Cloudflare Workers AI → FLUX en NVIDIA NIM → tu propio generador
36
+ (GPU local, ComfyUI…) → archivo de imágenes anteriores → fondo procedural que siempre funciona sin internet.
37
+ - 💬 **Subtítulos palabra a palabra** con la palabra que suena resaltada, sincronizados con la voz o con Whisper.
38
+ - 🎞️ **Zoom Ken Burns suave y sin temblor** (render subpíxel), fundidos entre escenas, voz normalizada a
39
+ -14 LUFS y música de fondo opcional con créditos automáticos.
40
+ - 🌍 **Español e inglés de serie** (prompts, meses, cuentas atrás). Otro idioma = un diccionario más.
41
+ - 💸 **Gratis por defecto**: funciona sin ninguna clave; todo lo de pago es opcional y con tope de gasto.
42
+ - 🔌 **Cualquier LLM compatible con OpenAI**: NVIDIA NIM, OpenRouter, Groq, OpenAI, Ollama, LM Studio, OmniRoute…
43
+ - 📤 **Subida a YouTube opcional** marcando el contenido como "alterado o sintético", como exige YouTube.
44
+ - ✅ **Comprueba cada vídeo** (resolución, audio, sin pantalla negra) antes de dejarlo en la cola de subida.
45
+
46
+ ## Empezar
47
+
48
+ Necesitas **Python 3.10+** y **[FFmpeg](https://ffmpeg.org/download.html)** en el PATH.
49
+
50
+ ```bash
51
+ pip install factreel
52
+ factreel init mi-canal --lang es
53
+ cd mi-canal
54
+ factreel doctor # comprueba FFmpeg, claves y cada voz
55
+ factreel make # -> output/20261020_180000_dia_venus.mp4 (+ metadatos .json/.txt)
56
+ ```
57
+
58
+ Sin ninguna clave ya sale un vídeo con la voz gratuita de Edge, los hechos leídos tal cual y fondos sin
59
+ conexión. Añade claves gratuitas en `.env` para tener guion e imágenes con IA:
60
+
61
+ | Clave | Qué activa | Coste |
62
+ | --- | --- | --- |
63
+ | `NVIDIA_API_KEY` ([build.nvidia.com](https://build.nvidia.com)) | guion con IA + verificación, imágenes FLUX | créditos gratis |
64
+ | `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` | imágenes FLUX, voz de reserva, tiempos exactos de subtítulos (Whisper) | 10.000 neurons gratis al día, con tope |
65
+ | `ELEVENLABS_API_KEY` | voz premium | opcional |
66
+
67
+ ## Tus hechos
68
+
69
+ ```json
70
+ {
71
+ "topics": [
72
+ {
73
+ "id": "dia_venus",
74
+ "angle": "en Venus un día dura más que un año",
75
+ "facts": [
76
+ "Venus tarda unos 243 días terrestres en dar una vuelta sobre sí mismo.",
77
+ "Venus tarda unos 225 días terrestres en dar una vuelta al Sol."
78
+ ],
79
+ "sources": ["https://science.nasa.gov/venus/venus-facts/"],
80
+ "hashtags": ["#venus"],
81
+ "weight": 2
82
+ }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ Empieza por `RUMOR:` las noticias sin confirmar y el guion tendrá que decirlo. Pon ids de temas en
88
+ `queue.txt` para elegir qué sale después; si no, se elige el tema menos usado (`weight` > 1 = más a menudo).
89
+
90
+ ## Comandos
91
+
92
+ | Comando | Qué hace |
93
+ | --- | --- |
94
+ | `factreel init CARPETA --lang es` | crea un canal desde una plantilla |
95
+ | `factreel make [-t TEMA] [-n 3]` | genera vídeos en `output/` |
96
+ | `factreel make --offline --voice dummy` | vista previa al instante: sin IA, voz muda, imágenes sin conexión |
97
+ | `factreel topics` | temas y cuántas veces se ha usado cada uno |
98
+ | `factreel doctor [--voices --log]` | lo comprueba todo; `--log` es ideal para una tarea programada |
99
+ | `factreel upload [--privacy unlisted]` | sube los vídeos pendientes a YouTube (`pip install "factreel[youtube]"`) |
100
+ | `factreel run` | genera y sube, para la tarea programada diaria |
101
+
102
+ ## Documentación
103
+
104
+ - [Configuración](docs/configuration.md) · [Proveedores](docs/providers.md) · [Subida a YouTube](docs/youtube.md) · [Programar tareas](docs/scheduling.md) (en inglés)
105
+
106
+ ## Uso responsable
107
+
108
+ FactReel declara el contenido generado con IA al subirlo, no se inventa datos y etiqueta los rumores.
109
+ Mantenlo así: cita tus fuentes, respeta marcas y licencias de música y no lo uses para producir en masa
110
+ contenido engañoso. Las plataformas penalizan el spam; buenos datos hacen buenos vídeos.
111
+
112
+ ## Contribuir
113
+
114
+ ¡Las contribuciones son muy bienvenidas!, sobre todo idiomas nuevos, proveedores de voz e imagen y
115
+ subidas a otras plataformas. Mira [CONTRIBUTING.md](CONTRIBUTING.md) y la [hoja de ruta](ROADMAP.md).
116
+ Puedes escribir las issues y los PR en español o en inglés.
117
+
118
+ ## Licencia
119
+
120
+ [MIT](LICENSE) © Jorge Lamelas
@@ -0,0 +1,142 @@
1
+ <div align="center">
2
+
3
+ # FactReel 🎬✅
4
+
5
+ **Fact-checked faceless short videos, on autopilot.**
6
+ YouTube Shorts · TikTok · Reels, from a list of verified facts, with free AI services and a fallback for everything.
7
+
8
+ [![CI](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml/badge.svg)](https://github.com/DeadY2J/factreel/actions/workflows/ci.yml)
9
+ [![PyPI](https://img.shields.io/pypi/v/factreel.svg)](https://pypi.org/project/factreel/)
10
+ [![Python](https://img.shields.io/pypi/pyversions/factreel.svg)](https://pypi.org/project/factreel/)
11
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
12
+
13
+ [English](README.md) · [Español](README.es.md)
14
+
15
+ <img src="docs/demo.gif" width="260" alt="FactReel demo: vertical video with word-by-word subtitles">
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ Most "AI shorts generators" let a language model make things up. **FactReel doesn't.** You write the facts
22
+ (with sources) once; the AI only turns them into a punchy script, and every script goes through guards that
23
+ reject invented numbers, repeated ideas, unlabelled rumours and anything a second fact-checking pass can't
24
+ find in your facts. Then it narrates it, draws the images, burns karaoke subtitles and renders a vertical
25
+ MP4 ready to upload.
26
+
27
+ It grew out of a real channel that publishes a Short every day unattended, so it is built to **never stop
28
+ on a bad day**: if the voice service, the image API or the script AI is down, the next option in the chain
29
+ takes over.
30
+
31
+ ## Features
32
+
33
+ - 🛡️ **Anti-hallucination script writer**: number whitelist, repetition check, rumour labelling, a
34
+ temperature-0 fact-check pass, and a facts-only fallback that is always correct.
35
+ - 🗣️ **Voice fallback chain**: Microsoft Edge neural voices (free, no key) → ElevenLabs → Cloudflare
36
+ Aura → your OS's offline voice. `factreel doctor` tells you when a service is down and when it is back.
37
+ - 🖼️ **Image fallback chain**: Cloudflare Workers AI FLUX → NVIDIA NIM FLUX → your own generator
38
+ (local GPU, ComfyUI…) → archive of previous images → procedural background that always works offline.
39
+ - 💬 **Word-by-word subtitles** with the spoken word highlighted, synced from the TTS engine or Whisper.
40
+ - 🎞️ **Smooth Ken Burns zoom without jitter** (sub-pixel rendering), cross-fades on scene changes,
41
+ voice normalised to -14 LUFS, optional background music with automatic credits.
42
+ - 🌍 **Spanish and English first-class** (prompts, month names, countdowns). More languages = one dict.
43
+ - 💸 **Free by default**: runs with zero API keys; every paid service is optional and budget-capped.
44
+ - 🔌 **Any OpenAI-compatible LLM**: NVIDIA NIM, OpenRouter, Groq, OpenAI, Ollama, LM Studio, OmniRoute…
45
+ - 📤 **Optional YouTube upload** with the "altered or synthetic content" flag set for you.
46
+ - ✅ **Verifies every render** (resolution, audio, no black screen) before it reaches the upload queue.
47
+
48
+ ## Quick start
49
+
50
+ You need **Python 3.10+** and **[FFmpeg](https://ffmpeg.org/download.html)** on your PATH.
51
+
52
+ ```bash
53
+ pip install factreel
54
+ factreel init my-channel --lang en # or --lang es
55
+ cd my-channel
56
+ factreel doctor # checks FFmpeg, keys and every voice
57
+ factreel make # -> output/20261020_180000_venus_day.mp4 (+ .json/.txt metadata)
58
+ ```
59
+
60
+ That's it: with no keys at all you get a video with the free Edge voice, the facts read as they are and
61
+ offline backgrounds. Add free keys to `.env` to unlock the AI script and AI images:
62
+
63
+ | Key | What it unlocks | Cost |
64
+ | --- | --- | --- |
65
+ | `NVIDIA_API_KEY` ([build.nvidia.com](https://build.nvidia.com)) | AI script + fact check, FLUX images | free credits |
66
+ | `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` | FLUX images, backup voice, exact subtitle timing (Whisper) | 10,000 free neurons/day, capped |
67
+ | `ELEVENLABS_API_KEY` | premium voice | optional |
68
+
69
+ ## How it works
70
+
71
+ ```mermaid
72
+ flowchart LR
73
+ F[facts.json<br/>verified facts + sources] --> T[topic rotation<br/>queue.txt / least used]
74
+ T --> S[AI script]
75
+ S --> G{guards<br/>numbers · repeats<br/>rumours · fact check}
76
+ G -- rejected --> S
77
+ G -- gives up --> FB[facts-only script]
78
+ G -- ok --> V[voice chain]
79
+ FB --> V
80
+ V --> SUB[karaoke subtitles]
81
+ V --> I[image chain]
82
+ SUB --> R[FFmpeg render + verify]
83
+ I --> R
84
+ R --> O[output/*.mp4 + metadata] --> U[YouTube upload]
85
+ ```
86
+
87
+ ## Your facts
88
+
89
+ ```json
90
+ {
91
+ "topics": [
92
+ {
93
+ "id": "venus_day",
94
+ "angle": "a day on Venus is longer than its year",
95
+ "facts": [
96
+ "Venus takes about 243 Earth days to spin once on its axis.",
97
+ "Venus takes about 225 Earth days to orbit the Sun."
98
+ ],
99
+ "sources": ["https://science.nasa.gov/venus/venus-facts/"],
100
+ "hashtags": ["#venus"],
101
+ "weight": 2
102
+ }
103
+ ]
104
+ }
105
+ ```
106
+
107
+ Prefix unconfirmed news with `RUMOR:` and the script will be forced to say so. Put topic ids in
108
+ `queue.txt` to choose what goes out next; otherwise the least used topic is picked (`weight` > 1 = more often).
109
+
110
+ ## Commands
111
+
112
+ | Command | What it does |
113
+ | --- | --- |
114
+ | `factreel init DIR --lang es` | new channel folder from a template |
115
+ | `factreel make [-t TOPIC] [-n 3]` | generate videos into `output/` |
116
+ | `factreel make --offline --voice dummy` | instant preview: no AI, silent voice, offline images |
117
+ | `factreel topics` | topics and how many times each was used |
118
+ | `factreel doctor [--voices --log]` | check everything; `--log` is perfect for a scheduled task |
119
+ | `factreel upload [--privacy unlisted]` | upload pending videos to YouTube (`pip install "factreel[youtube]"`) |
120
+ | `factreel run` | make + upload, for a daily scheduled task |
121
+
122
+ ## Documentation
123
+
124
+ - [Configuration reference](docs/configuration.md): every `channel.toml` option
125
+ - [Providers](docs/providers.md): voices, images, LLMs and how to add your own
126
+ - [YouTube upload](docs/youtube.md): OAuth setup in 5 minutes
127
+ - [Scheduling](docs/scheduling.md): Windows Task Scheduler, cron, GitHub Actions
128
+
129
+ ## Responsible use
130
+
131
+ FactReel declares AI-generated media when uploading, never invents facts on its own, and labels rumours.
132
+ Please keep it that way: cite your sources, respect trademarks and music licences, and don't use it to
133
+ mass-produce misleading content. Platforms penalise low-effort spam; good facts make good videos.
134
+
135
+ ## Contributing
136
+
137
+ Contributions are very welcome, especially new languages, voice/image providers and platform uploaders.
138
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the [roadmap](ROADMAP.md) for good first issues.
139
+
140
+ ## License
141
+
142
+ [MIT](LICENSE) © Jorge Lamelas