How MoneyPrinterTurbo Generates Video Scripts with LLMs: Architecture and Implementation
MoneyPrinterTurbo generates video scripts by orchestrating task management, prompt engineering, and provider-agnostic API calls across 15+ LLM backends, followed by aggressive markdown sanitization and intelligent retry logic.
MoneyPrinterTurbo is an open-source automated video creation platform that transforms text subjects into complete video scripts using Large Language Models. The system implements a clean separation of concerns between high-level task orchestration and low-level LLM interaction, enabling support for diverse providers like OpenAI, Azure, Ollama, and Gemini through a unified interface. Understanding how MoneyPrinterTurbo handles script generation with LLMs reveals a robust pipeline designed for reliability and extensibility.
Task Orchestration and Entry Points
The script generation workflow begins in app/services/task.py, where the start function initiates the video creation pipeline. When processing a new request, the system checks whether a script already exists; if not, it delegates to the LLM service layer by invoking generate_script with the video subject, target language, and desired paragraph count.
This orchestration layer abstracts the complexity of LLM interaction, allowing the task manager to focus on coordinating subsequent steps like term extraction, audio generation, and video composition. The generated script is ultimately persisted to script.json and optionally returned to callers such as the Streamlit web interface in webui/Main.py.
Prompt Engineering and Provider Configuration
In app/services/llm.py, the generate_script function constructs a deterministic system prompt that instructs the model to act as a Video Script Generator. The prompt explicitly demands raw text output without markdown formatting, titles, or meta-information, injecting the user's video subject, paragraph count, and optional language constraints.
Provider selection is driven by the llm_provider configuration key defined in config.example.toml, defaulting to openai if unspecified. The architecture supports extensive provider diversity including OpenAI, Azure, Ollama, Moonshot, G4F, Pollinations, Gemini, Cloudflare, Ernie, Qwen, DeepSeek, and ModelScope, each configurable with distinct API keys, base URLs, and model parameters.
LLM API Integration and Response Handling
The LLM service implements provider-specific request patterns while maintaining a unified response interface. For the default OpenAI path, the code initializes an OpenAI client with configured credentials and executes chat.completions.create to retrieve the script content.
Alternative providers follow adapted request flows; for instance, Pollinations uses raw requests.post calls to REST endpoints. Regardless of the provider, all branches funnel the model's response into a content variable for downstream processing, ensuring the task layer receives consistent string output regardless of backend implementation.
Response Sanitization and Paragraph Structuring
Raw LLM outputs often contain unwanted formatting artifacts that disrupt video generation. The format_response function in app/services/llm.py implements aggressive text cleaning that strips asterisks, hash symbols, bracketed markdown links, and parenthesized URLs from the generated content.
After sanitization, the system splits the cleaned text on double line-breaks to segment the script into discrete paragraphs matching the requested count. This post-processing ensures the final script contains only plain text suitable for voice synthesis and subtitle generation, removing any structural noise introduced by the LLM.
Retry Logic and Error Resilience
MoneyPrinterTurbo implements defensive retry mechanisms to handle transient LLM failures and provider-specific quota limitations. The generation loop attempts up to _max_retries (5 attempts by default) when encountering empty responses or specific error messages.
The system specifically detects quota exhaustion errors—identified by the Chinese string "当日额度已消耗完" (daily quota exhausted)—and treats these as retryable conditions. This resilience ensures script generation completes successfully even under provider instability or rate limiting, automatically cycling through retry attempts before surfacing failures to the user.
Practical Implementation Examples
Direct Script Generation via LLM Service
For standalone script generation without full video processing, import the LLM service directly:
from app.services import llm
subject = "The impact of cryptocurrency on modern finance"
script = llm.generate_script(
video_subject=subject,
language="en",
paragraph_number=3
)
print(script)
This invocation constructs the prompt, communicates with the configured provider (defaulting to OpenAI), and returns sanitized paragraph text ready for display or storage.
Full Pipeline Orchestration with Early Termination
To execute the complete workflow while stopping after script generation:
from app.services import task
from app.models.schema import VideoParams
params = VideoParams(
video_subject="How money influences society",
voice_name="en-US-AndrewNeural",
video_language="en",
paragraph_number=2,
)
result = task.start(task_id="my_task_001", params=params, stop_at="script")
print("Generated script:", result["script"])
The stop_at="script" parameter instructs task.start to halt execution after the LLM returns content, returning the same cleaned text available through the direct service call while demonstrating integration with the broader video creation architecture.
Summary
- Task orchestration in
app/services/task.pycoordinates script generation through thestartfunction, checking for existing scripts before invoking LLM services. - Prompt construction in
app/services/llm.pygenerates deterministic system instructions that enforce raw text output without markdown artifacts. - Provider abstraction supports 15+ backends including OpenAI, Azure, Gemini, and Ollama through configurable
llm_providersettings inconfig.example.toml. - Response sanitization via
format_responseremoves asterisks, hashes, links, and URLs, then segments text into paragraphs using double line-break delimiters. - Retry resilience implements 5-attempt retry logic with specific handling for quota exhaustion errors (
"当日额度已消耗完"). - Integration flexibility allows both direct LLM service calls and full pipeline orchestration with early termination via
stop_at="script".
Frequently Asked Questions
What LLM providers does MoneyPrinterTurbo support?
MoneyPrinterTurbo supports over 15 LLM providers including OpenAI, Azure OpenAI, Ollama, Moonshot, G4F, Pollinations, Gemini, Cloudflare Workers AI, Baidu Ernie, Alibaba Qwen, DeepSeek, and ModelScope. Provider selection is controlled by the llm_provider configuration key in config.example.toml, with each provider supporting distinct API endpoints, authentication methods, and model specifications.
How does MoneyPrinterTurbo clean LLM responses for video use?
The system employs the format_response function in app/services/llm.py to strip markdown syntax including asterisks, hash symbols, bracketed links, and parenthesized URLs from raw LLM output. After cleaning, the function splits text on double line-breaks to isolate paragraphs, ensuring the final script contains only plain text compatible with text-to-speech engines and subtitle rendering.
Can I customize the script generation prompt?
While the current implementation in app/services/llm.py uses a static system prompt defining the Video Script Generator role, advanced users can modify the prompt template directly in the source code. The prompt explicitly requests raw text without markdown and incorporates variables for video subject, paragraph count, and language constraints, allowing straightforward customization for specific tone or style requirements.
What happens when an LLM provider fails or returns empty responses?
MoneyPrinterTurbo implements a retry mechanism that attempts script generation up to 5 times (_max_retries) when receiving empty responses or encountering provider errors. The system specifically recognizes quota exhaustion messages (e.g., "当日额度已消耗完") as retryable conditions, automatically reattempting generation before propagating persistent failures to the calling task layer or web interface.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →