chore: import upstream snapshot with attribution
Deploy Documentation / deploy (push) Failing after 1s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:19:20 +08:00
commit 7d6672c63e
314 changed files with 46257 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
{
"name": "Pixelle-Video Codespace",
"image": "mcr.microsoft.com/devcontainers/python:1-3.11",
"forwardPorts": [8501],
"postCreateCommand": ".devcontainer/postCreate.sh",
"postStartCommand": ".devcontainer/postStart.sh",
"remoteUser": "vscode"
}
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
set -uo pipefail
echo "[devcontainer] Running postCreate tasks..."
cd /workspaces/Pixelle-Video
# ============================================================================
# System Dependencies Installation
# ============================================================================
export DEBIAN_FRONTEND=noninteractive
# Remove problematic Yarn repository if it exists
echo "[devcontainer] Removing problematic repositories..."
sudo rm -f /etc/apt/sources.list.d/yarn.sources 2>/dev/null || true
sudo rm -f /etc/apt/sources.list.d/yarn.list 2>/dev/null || true
# Update package lists
echo "[devcontainer] Updating package lists..."
sudo apt-get update -y || {
echo "[devcontainer] Warning: apt-get update had issues, continuing anyway..."
true
}
# Install system packages needed by the project
echo "[devcontainer] Installing system packages..."
sudo apt-get install -y --no-install-recommends \
ffmpeg \
fontconfig \
fonts-liberation \
fonts-noto-cjk \
wget \
xdg-utils \
ca-certificates || true
# Verify installation
echo "[devcontainer] Verifying system packages..."
echo "[devcontainer] Chinese fonts (sample):"
fc-list :lang=zh | head -n 10 || true
# ============================================================================
# Python Dependencies Installation
# ============================================================================
# Install uv package manager
echo "[devcontainer] Installing uv package manager..."
pip install uv --quiet
# Install Python dependencies with uv
echo "[devcontainer] Installing Python dependencies with uv..."
uv sync --frozen
# Install Playwright browser (Chromium for HTML template rendering)
echo "[devcontainer] Installing Playwright Chromium browser..."
uv run playwright install --with-deps chromium || true
echo "[devcontainer] postCreate complete. Streamlit will start automatically via postStart.sh"
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
echo "[devcontainer] postStart: launching Pixelle-Video Web UI in background..."
cd /workspaces/Pixelle-Video
# Set Streamlit config for headless mode and proper port binding
export STREAMLIT_SERVER_PORT=8501
export STREAMLIT_SERVER_ADDRESS=0.0.0.0
export STREAMLIT_SERVER_HEADLESS=true
export STREAMLIT_LOGGER_LEVEL=info
export UV_LINK_MODE=copy
# Start the web UI in background so the forwarded port is ready
nohup bash start_web.sh > /tmp/pixelle_streamlit.log 2>&1 &
WEB_PID=$!
echo "[devcontainer] Streamlit started with PID $WEB_PID (logs: /tmp/pixelle_streamlit.log)"
# Wait briefly for startup and show success message
sleep 3
if ps -p $WEB_PID > /dev/null 2>&1; then
echo ""
echo "✅ Pixelle-Video Web UI is launching on port 8501"
echo "🌐 The URL will be available shortly (usually within 5-10 seconds)"
echo ""
else
echo ""
echo "⚠️ Warning: Process may have exited. Check logs with: tail -f /tmp/pixelle_streamlit.log"
echo ""
fi
echo "Common commands:"
echo "1. View logs:"
echo " tail -f /tmp/pixelle_streamlit.log"
echo "2. Stop service:"
echo " pkill -f 'streamlit run web/app.py'"
echo "3. Restart service:"
echo " pkill -f 'streamlit run web/app.py' && nohup bash start_web.sh > /tmp/pixelle_streamlit.log 2>&1 &"
echo "4. Check port usage:"
echo " lsof -i:8501"
echo "5. View processes:"
echo " ps aux | grep streamlit"
echo ""
echo "For more help, see README or run 'ps aux | grep streamlit'."
+71
View File
@@ -0,0 +1,71 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
*.egg
# Virtual environments
.venv/
venv/
ENV/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Git
.git/
.gitignore
.gitattributes
# Documentation
docs/*
!docs/images/
!docs/FAQ*.md
*.md
!README.md
# Plans and development files
plans/
repositories/
examples/
# Test files
test_*.py
tests/
*.log
# Output and temporary files
output/*
!output/.gitkeep
temp/
*.tmp
# User data (will be mounted)
data/users/*
!data/.gitkeep
# Config (will be mounted)
config.yaml
config.yaml.bak
config.example.yaml
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Misc
*.bak
restart_web.sh
start_web.sh
+45
View File
@@ -0,0 +1,45 @@
name: Deploy Documentation
on:
push:
branches:
- main
paths:
- 'docs/**'
- 'mkdocs.yml'
- '.github/workflows/docs.yml'
workflow_dispatch: # Allow manual trigger
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for git-revision-date-localized plugin
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements-docs.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements-docs.txt
- name: Build and deploy documentation
run: mkdocs gh-deploy --force
+76
View File
@@ -0,0 +1,76 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
ENV/
env/
.venv/
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.cursorrules
.cursorignore
.kiro/
# OS
.DS_Store
Thumbs.db
# Config files with sensitive data
config.yaml
config.yaml.bak
*.yaml.bak
.env
# Logs
*.log
# Test outputs
test_outputs/
*.mp3
*.wav
*.bak
test_*.py
!bgm/default.mp3
# Temp files
temp/
tmp/
.cache/
# MkDocs build output
site/
data
output
plans/
examples/
repositories/
*.out
+77
View File
@@ -0,0 +1,77 @@
# Pixelle-Video Docker Image
# Based on Python 3.11 slim for smaller image size
FROM python:3.11-slim
# Build arguments for mirror configuration
# USE_CN_MIRROR: whether to use China mirrors (true/false)
ARG USE_CN_MIRROR=false
# Set working directory
WORKDIR /app
# Replace apt sources with China mirrors if needed
# Debian 12 uses DEB822 format in /etc/apt/sources.list.d/debian.sources
RUN if [ "$USE_CN_MIRROR" = "true" ]; then \
sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources && \
sed -i 's|security.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources; \
fi
# Install system dependencies
# - curl: for health checks and downloads
# - ffmpeg: for video/audio processing
# - fonts-noto-cjk: for CJK character support
RUN apt-get update && apt-get install -y \
curl \
ffmpeg \
fonts-noto-cjk \
&& rm -rf /var/lib/apt/lists/*
# Install uv package manager
# For China: use pip to install uv from mirror (faster and more stable)
# For International: use official installer script
RUN if [ "$USE_CN_MIRROR" = "true" ]; then \
pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple/ uv; \
else \
curl -LsSf https://astral.sh/uv/install.sh | sh; \
fi
ENV PATH="/root/.local/bin:$PATH"
RUN uv --version
# Copy dependency files and source code for building
# Note: pixelle_video is needed for hatchling to build the package
COPY pyproject.toml uv.lock README.md ./
COPY pixelle_video ./pixelle_video
# Create virtual environment and install dependencies
# Use -i flag to specify mirror when USE_CN_MIRROR=true
RUN export UV_HTTP_TIMEOUT=300 && \
uv venv && \
if [ "$USE_CN_MIRROR" = "true" ]; then \
uv pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple; \
else \
uv pip install -e .; \
fi && \
uv run playwright install --with-deps chromium
# Copy rest of application code
COPY api ./api
COPY web ./web
COPY bgm ./bgm
COPY templates ./templates
COPY workflows ./workflows
COPY resources ./resources
COPY docs/images ./docs/images
COPY docs/FAQ*.md ./docs/
# Create output, data and temp directories
RUN mkdir -p /app/output /app/data /app/temp
# Expose ports
# 8000: API service
# 8501: Web UI service
EXPOSE 8000 8501
# Default command (can be overridden in docker-compose)
CMD ["uv", "run", "python", "api/app.py"]
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+150
View File
@@ -0,0 +1,150 @@
Copyright (C) 2025 AIDC-AI
This project incorporates components from the Open Source Software below.
The original copyright notices and the licenses under which we received such components are set forth below for informational purposes.
Open Source Software Licensed under the MIT-CMU License:
--------------------------------------------------------------------
1. pillow 11.3.0
Terms of the MIT-CMU:
--------------------------------------------------------------------
By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read, understood, and will comply with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the copyright holder not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Open Source Software Licensed under the BSD-3-Clause License:
--------------------------------------------------------------------
1. httpx 0.28.1 https://pypi.org/project/httpx
copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Terms of the BSD-3-Clause:
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Open Source Software Licensed under the Apache-2.0 License:
--------------------------------------------------------------------
1. streamlit 1.40.0 https://pypi.org/project/streamlit
Copyright 2018 Adrien Treuille
Copyright 2018 Streamlit Inc. All rights reserved.
Copyright 2008 Google Inc. All rights reserved.
2. openai 2.6.0
3. python-multipart 0.0.20 https://pypi.org/project/python-multipart
Copyright (c) 2010 by Armin Ronacher.
Copyright 2012; Andrew Dunham
4. ffmpeg-python 0.2.0 https://pypi.org/project/ffmpeg-python
Copyright 2017 Karl Kroening
Terms of the Apache-2.0:
--------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Open Source Software Licensed under the MIT License:
--------------------------------------------------------------------
1. fastmcp 2.0.0 https://pypi.org/project/fastmcp
2. pyyaml 6.0.0
3. comfykit 0.1.6
4. certifi 2025.10.5
5. playwright 1.58.0 https://pypi.org/project/playwright
Copyright (c) Microsoft Corporation
6. edge-tts 7.2.3
7. fastapi 0.115.0 https://pypi.org/project/fastapi
Copyright (c) 2018 Sebasti n Ram rez
Copyright (c) 2018 Sebasti..n Ram..rez
Copyright (c) 2018 Sebasti10n Ram.:rez
8. pydantic 2.0.0
9. loguru 0.7.0 https://pypi.org/project/loguru
Copyright (c) 2017
Terms of the MIT:
--------------------------------------------------------------------
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+476
View File
@@ -0,0 +1,476 @@
<h1 align="center">🎬 Pixelle-Video —— AI 全自动短视频引擎</h1>
<p align="center"><a href="README_EN.md">English</a> | <b>中文</b></p>
<p align="center">
<a href="https://www.bilibili.com/video/BV1WzyGBnEVp/?vd_source=e7e7d4ca8db9a18c80f17a24a6582fca" target="_blank"><img src="https://img.shields.io/badge/🎥 视频教程-EA4C89" alt="视频教程"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/releases" target="_blank"><img src="https://img.shields.io/badge/📦 Windows包-50C878" alt="Windows整合包"></a>
<a href="https://aidc-ai.github.io/Pixelle-Video/zh" target="_blank"><img src="https://img.shields.io/badge/📘 使用文档-4A90E2" alt="使用文档"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/stargazers"><img src="https://img.shields.io/github/stars/AIDC-AI/Pixelle-Video.svg" alt="Stargazers"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/issues"><img src="https://img.shields.io/github/issues/AIDC-AI/Pixelle-Video.svg" alt="Issues"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/network/members"><img src="https://img.shields.io/github/forks/AIDC-AI/Pixelle-Video.svg" alt="Forks"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/blob/main/LICENSE"><img src="https://img.shields.io/github/license/AIDC-AI/Pixelle-Video.svg" alt="License"></a>
</p>
https://github.com/user-attachments/assets/a42e7457-fcc8-40da-83fc-784c45a8b95d
<br/>
只需输入一个 **主题**Pixelle-Video 就能自动完成:
- ✍️ 撰写视频文案
- 🎨 生成 AI 配图/视频
- 🗣️ 合成语音解说
- 🎵 添加背景音乐
- 🎬 一键合成视频
**零门槛,零剪辑经验**,让视频创作成为一句话的事!
## 🖥️ Web 界面预览
![Web UI界面](resources/webui.png)
## 📋 最近更新
-**2026-06-01**: 新增直连 API 媒体模型配置,支持在 WebUI 中配置图像/视频模型供应商、Base URL 与代理开关
-**2026-01-26**: 新增「动作迁移」模块,上传参考视频和图片进行动作迁移
-**2026-01-14**: 新增「数字人口播」和「图生视频」流水线,新增多语言 TTS 音色支持
-**2026-01-06**: 新增 RunningHub 48G 显存机器调用支持
-**2025-12-28**: 支持 RunningHub 并发限制可配置,优化 LLM 返回结构化数据的逻辑
-**2025-12-17**: 支持 ComfyUI API Key 配置,支持 Nano Banana 模型调用,API 接口支持模板自定义参数
-**2025-12-10**: 侧边栏内置 FAQ,锁定 edge-tts 版本修复 TTS 服务不稳定问题
-**2025-12-08**: 支持固定脚本多种分割方式(段落/行/句子),优化模板选择交互逻辑支持直接预览选择
-**2025-12-06**: 修复视频生成 API 返回 URL 路径处理,支持跨平台兼容
-**2025-12-05**: 新增 Windows 整合包下载,优化图片与视频反推工作流
-**2025-12-04**: 新增「自定义素材」功能,支持用户上传自己的照片和视频,AI 智能分析生成脚本
-**2025-11-18**: 优化 RunningHub 服务调用支持并行处理,新增历史记录页面,支持批量创建视频任务
## ✨ 功能亮点
-**全自动生成** - 输入主题,自动生成完整视频
-**AI 智能文案** - 根据主题智能创作解说词,无需自己写脚本
-**AI 生成配图** - 每句话都配上精美的 AI 插图
-**AI 生成视频** - 支持使用 AI 视频生成模型(如 WAN 2.1)创建动态视频内容
-**直连模型 API** - 可直接调用 DashScope、OpenAI、Seedream、Seedance、Kling 等图像/视频生成服务
-**AI 生成语音** - 支持 Edge-TTS、Index-TTS 等众多主流 TTS 方案
-**背景音乐** - 支持添加 BGM,让视频更有氛围
-**视觉风格** - 多种模板可选,打造独特视频风格
-**灵活尺寸** - 支持竖屏、横屏等多种视频尺寸
-**多种 AI 模型** - 支持 GPT、通义千问、DeepSeek、Ollama 等
-**原子能力灵活组合** - 支持 ComfyUI / RunningHub 工作流,也支持直连 API 模型,可按需替换图像、视频、TTS、VLM 等能力
## 📊 视频生成流程
Pixelle-Video 采用模块化设计,整个视频生成流程清晰简洁:
![视频生成流程图](resources/flow.png)
从输入文本到最终视频输出,整个流程简洁清晰:**文案生成 → 配图规划 → 逐帧处理 → 视频合成**
每个环节都支持灵活定制,可选择不同的 AI 模型、音频引擎、视觉风格等,满足个性化创作需求。
## 🎬 视频示例
以下是使用 Pixelle-Video 生成的实际案例,展示了不同主题和风格的视频效果:
### 📱 扩展模块视频展示
<table>
<tr>
<td width="33%">
<h3>👤 数字人口播</h3>
<video src="https://github.com/user-attachments/assets/7c122563-c2e0-4dcd-a73c-25ba1d4fa2dd" controls width="100%"></video>
<p align="center"><b>韩语数字人口播</b></p>
</td>
<td width="33%">
<h3>🖼️ 图生视频</h3>
<video src="https://github.com/user-attachments/assets/5b4eef17-07d0-4bde-9748-2ed68cc9888e" controls width="100%"></video>
<p align="center"><b>卡通视频</b></p>
</td>
<td width="33%">
<h3>💃 动作迁移</h3>
<video src="https://github.com/user-attachments/assets/7b1240bc-e965-434c-b343-118ec4793d4f" controls width="100%"></video>
<p align="center"><b>跳舞小猫</b></p>
</td>
</tr>
</table>
### 📱 竖屏视频展示
<table>
<tr>
<td width="33%">
<h3>🌄 人文纪实类 - 视频默认模版</h3>
<video src="https://github.com/user-attachments/assets/e6716c1d-78de-453d-84c2-10873c8c595f" controls width="100%"></video>
<p align="center"><b>旅行路上的风景让人流连忘返</b></p>
</td>
<td width="33%">
<h3>🔍 文化解构类 - 视频默认模版</h3>
<video src="https://github.com/user-attachments/assets/f5de75f6-135a-4ab4-9f5f-079f649764d5" controls width="100%"></video>
<p align="center"><b>Santa ID</b></p>
</td>
<td width="33%">
<h3>🔭 科学思辨类 - 视频默认模版</h3>
<video src="https://github.com/user-attachments/assets/ceb8b0df-8331-4e1f-88e7-db5b295a1c1d" controls width="100%"></video>
<p align="center"><b>为什么我们还没有找到外星文明?</b></p>
</td>
</tr>
<tr>
<td width="33%">
<h3>🌱 个人成长类 - 克隆音色</h3>
<video src="https://github.com/user-attachments/assets/1bad9a49-df83-4905-9cc8-9a7640e9c7d8" controls width="100%"></video>
<p align="center"><b>如何提升自己</b></p>
</td>
<td width="33%">
<h3>🧠 深度思考类 - 默认模板</h3>
<video src="https://github.com/user-attachments/assets/663b705a-2aea-44bc-b266-4bb27aa255a8" controls width="100%"></video>
<p align="center"><b>如何理解反脆弱</b></p>
</td>
<td width="33%">
<h3>🏯 历史文化类 - 固定画面</h3>
<video src="https://github.com/user-attachments/assets/56e0a018-fa99-47eb-a97f-fc2fa8915724" controls width="100%"></video>
<p align="center"><b>资治通鉴</b></p>
</td>
</tr>
<tr>
<td width="33%">
<h3>☀️ 情感类 - 克隆音色</h3>
<video src="https://github.com/user-attachments/assets/4687df95-dd21-4a7b-b01e-f33a7b646644" controls width="100%"></video>
<p align="center"><b>冬日暖阳</b></p>
</td>
<td width="33%">
<h3>📜 小说解说类 - 自创脚本</h3>
<video src="https://github.com/user-attachments/assets/d354465e-3fa8-40b4-93e9-61ad75ef0697" controls width="100%"></video>
<p align="center"><b>斗破苍穹</b></p>
</td>
<td width="33%">
<h3>🧬 知识科普类 - Qwen生图</h3>
<video src="https://github.com/user-attachments/assets/8ac21768-41ce-4d41-acdd-e3dd3eb9725a" controls width="100%"></video>
<p align="center"><b>养生知识</b></p>
</td>
</tr>
</table>
### 🖥️ 横屏视频展示
<table>
<tr>
<td width="50%">
<h3>💰 副业赚钱 - 电影模板</h3>
<video src="https://github.com/user-attachments/assets/c9209d4e-73a6-4b82-aaad-cf102248c9e2" controls width="100%"></video>
<p align="center"><b>副业赚钱</b></p>
</td>
<td width="50%">
<h3>🏛️ 历史解说 - 自定义模板</h3>
<video src="https://github.com/user-attachments/assets/a767c452-d5f1-4cff-bb34-b80fff0d4c3e" controls width="100%"></video>
<p align="center"><b>资治通鉴启示录</b></p>
</td>
</tr>
</table>
> 💡 **提示**: 这些视频都是通过输入一个主题关键词,由 AI 全自动生成的,无需任何视频剪辑经验!
<div id="tutorial-start" />
## 🚀 快速开始
### 🪟 Windows 一键整合包(推荐 Windows 用户使用)
**无需安装 Python、uv 或 ffmpeg,一键开箱即用!**
👉 **[下载 Windows 一键整合包](https://github.com/AIDC-AI/Pixelle-Video/releases/latest)**
1. 下载最新的 Windows 一键整合包并解压
2. 双击运行 `start.bat` 启动 Web 界面
3. 浏览器会自动打开 http://localhost:8501
4. 在「⚙️ 系统配置」中配置 LLM API 和图像生成服务
5. 开始生成视频!
> 💡 **提示**: 整合包已包含所有依赖,无需手动安装任何环境。首次使用只需配置 API 密钥即可。
### 从源码安装(适合 macOS / Linux 用户或需要自定义的用户)
#### 前置环境依赖
在开始之前,需要先安装 Python 包管理器 `uv` 和视频处理工具 `ffmpeg`
##### 安装 uv
请访问 uv 官方文档查看适合你系统的安装方法:
👉 **[uv 安装指南](https://docs.astral.sh/uv/getting-started/installation/)**
安装完成后,在终端中运行 `uv --version` 验证安装成功。
##### 安装 ffmpeg
**macOS**
```bash
brew install ffmpeg
```
**Ubuntu / Debian**
```bash
sudo apt update
sudo apt install ffmpeg
```
**Windows**
- 下载地址:https://ffmpeg.org/download.html
- 下载后解压,将 `bin` 目录添加到系统环境变量 PATH 中
安装完成后,在终端中运行 `ffmpeg -version` 验证安装成功。
#### 第一步:下载项目
```bash
git clone https://github.com/AIDC-AI/Pixelle-Video.git
cd Pixelle-Video
```
#### 第二步:启动 Web 界面
```bash
# 使用 uv 运行(推荐,会自动安装依赖)
uv run streamlit run web/app.py
```
浏览器会自动打开 http://localhost:8501
#### 第三步:在 Web 界面配置
首次使用时,展开「⚙️ 系统配置」面板,填写:
- **LLM 配置**: 选择 AI 模型(如通义千问、GPT 等)并填入 API Key
- **ComfyUI / RunningHub 配置**: 如需使用工作流生成图片、视频或语音,配置本地 ComfyUI 地址或 RunningHub API Key
- **API 媒体模型配置**: 如需直连图像/视频模型,配置 DashScope、OpenAI、ARK、Kling 等供应商的 API Key、Base URL 和代理选项
配置好后点击「保存配置」,就可以开始生成视频了!
<div id="tutorial-end" />
## 💻 使用方法
打开 Web 界面后,你会看到三栏布局,下面详细讲解每个部分:
### ⚙️ 系统配置(首次必填)
首次使用时需要配置,点击展开「⚙️ 系统配置」面板:
#### 1. LLM 配置(大语言模型)
用于生成视频文案的 AI。
**快速选择预设**
- 通过下拉菜单选择预设模型(通义千问、GPT-4o、DeepSeek 等)
- 选择后会自动填充 base_url 和 model
- 点击「🔑 获取 API Key」链接去注册并获取密钥
**手动配置**
- API Key: 填入你的密钥
- Base URL: API 地址
- Model: 模型名称
#### 2. ComfyUI / RunningHub 配置
用于通过 ComfyUI 工作流生成视频配图、视频片段或语音。
**本地部署(推荐)**
- ComfyUI URL: 本地 ComfyUI 服务地址(默认 http://127.0.0.1:8188
- 点击「测试连接」确认服务可用
**云端部署**
- RunningHub API Key: 云端图像生成服务的密钥
#### 3. API 媒体模型配置
用于不依赖 ComfyUI/RunningHub,直接调用模型供应商的图像、视频或素材分析能力。
**支持的供应商**
- OpenAI / GPT Image:用于 GPT 图像生成模型
- DashScope / Wan / HappyHorse:用于通义万象图像、视频生成
- Volcengine ARK / Seedream / Seedance:用于字节 Seedream 图像和 Seedance 视频生成
- Kling AI / 可灵:用于可灵视频生成
**可配置项**
- API Key / Access Key / Secret Key:模型供应商鉴权信息
- Base URL:模型服务地址,WebUI 会提供官方默认地址
- 本地代理:如 `http://127.0.0.1:9090`
- 启用代理:每个供应商可单独选择是否走本地代理
- 打印模型请求参数:调试用,会在终端打印发送给模型的 prompt、模型名和输入文件路径
> 💡 如果你只使用 ComfyUI 或 RunningHub,可以不填写 API 媒体模型配置;如果你选择 `api/...` 工作流,则需要配置对应供应商的密钥。
配置完成后点击「保存配置」。
### 📝 内容输入(左侧栏)
#### 生成模式
- **AI 生成内容**: 输入主题,AI 自动创作文案
- 适合:想快速生成视频,让 AI 写稿
- 例如:「为什么要养成阅读习惯」
- **固定文案内容**: 直接输入完整文案,跳过 AI 创作
- 适合:已有现成文案,直接生成视频
#### 背景音乐(BGM
- **无 BGM**: 纯人声解说
- **内置音乐**: 选择预置的背景音乐(如 default.mp3
- **自定义音乐**: 将你的音乐文件(MP3/WAV 等)放到 `bgm/` 文件夹
- 点击「试听 BGM」可以预览音乐
### 🎤 语音设置(中间栏)
#### TTS 工作流
- 从下拉菜单选择 TTS 工作流(支持 Edge-TTS、Index-TTS 等)
- 系统会自动扫描 `workflows/` 文件夹中的 TTS 工作流
- 如果懂 ComfyUI,可以自定义 TTS 工作流
#### 参考音频(可选)
- 上传参考音频文件用于声音克隆(支持 MP3/WAV/FLAC 等格式)
- 适用于支持声音克隆的 TTS 工作流(如 Index-TTS
- 上传后可以直接试听
#### 预览功能
- 输入测试文本,点击「预览语音」即可试听效果
- 支持使用参考音频进行预览
### 🎨 视觉设置(中间栏)
#### 图像生成
决定 AI 生成什么风格的配图。
**ComfyUI 工作流**
- 从下拉菜单选择图像生成工作流
- 支持本地部署(selfhost)和云端(RunningHub)工作流
- 也支持选择 `api/...` 直连图像模型工作流(需先在系统配置中填写对应供应商密钥)
- 默认使用 `image_flux.json`
- 如果懂 ComfyUI,可以放自己的工作流到 `workflows/` 文件夹
**图像尺寸**
- 设置生成图像的宽度和高度(单位:像素)
- 默认 1024x1024,可根据需要调整
- 注意:不同的模型对尺寸有不同的限制
**提示词前缀(Prompt Prefix**
- 控制图像的整体风格(语言需要是英文的)
- 例如:Minimalist black-and-white matchstick figure style illustration, clean lines, simple sketch style
- 点击「预览风格」可以测试效果
#### 视频模板
决定视频画面的布局和设计。
**模板命名规范**
- `static_*.html`: 静态模板(无需AI生成媒体,纯文字样式)
- `image_*.html`: 图片模板(使用AI生成的图片作为背景)
- `video_*.html`: 视频模板(使用AI生成的视频作为背景)
**使用方法**
- 从下拉菜单选择模板,按尺寸分组显示(竖屏/横屏/方形)
- 点击「预览模板」可以自定义参数测试效果
- 如果懂 HTML,可以在 `templates/` 文件夹创建自己的模板
- 🔗 [查看所有模板效果图](https://aidc-ai.github.io/Pixelle-Video/zh/user-guide/templates/#_3)
#### API 视频生成
当选择支持动态视频的模板或扩展工作流时,可以使用直连 API 视频模型生成片段。
- 支持 DashScope Wan / HappyHorse、Kling、Seedance 等视频模型
- 支持按模型能力显示分辨率、画幅比例、时长、水印、原生音频等参数
- 支持网络下载重试与内容审核失败后的提示词中性化重试
- 在「自定义素材」工作流中,API 视频片段会尽量根据旁白音频时长生成,并使用相邻片段信息提升连贯性
### 🎬 生成视频(右侧栏)
#### 生成按钮
- 配置好所有参数后,点击「🎬 生成视频」
- 会显示实时进度(生成文案 → 生成配图 → 合成语音 → 合成视频)
- 生成完成后自动显示视频预览
#### 进度显示
- 实时显示当前步骤
- 例如:「分镜 3/5 - 生成插图」
#### 视频预览
- 生成完成后自动播放
- 显示视频时长、文件大小、分镜数等信息
- 视频文件保存在 `output/` 文件夹
### ❓ 常见问题
**Q: 第一次使用需要多久?**
A: 生成时长取决于视频分镜数量、网络状况和 AI 推理速度,通常几分钟内即可完成。
**Q: 视频效果不满意怎么办?**
A: 可以尝试:
1. 更换 LLM 模型(不同模型文案风格不同)
2. 调整图像尺寸和提示词前缀(改变配图风格)
3. 更换 TTS 工作流或上传参考音频(改变语音效果)
4. 尝试不同的视频模板和尺寸
**Q: 费用大概多少?**
A: **本项目完全支持免费运行!**
- **完全免费方案**: LLM 使用 Ollama(本地运行)+ ComfyUI 本地部署 = 0 元
- **推荐方案**: LLM 使用通义千问(成本极低,性价比高)+ ComfyUI 本地部署
- **云端方案**: LLM 使用 OpenAI + 图像使用 RunningHub(费用较高但无需本地环境)
**选择建议**:本地有显卡建议完全免费方案,否则推荐使用通义千问(性价比高)
## 🤝 参考项目
Pixelle-Video 的设计受到以下优秀开源项目的启发:
- [Pixelle-MCP](https://github.com/AIDC-AI/Pixelle-MCP) - ComfyUI MCP 服务器,让 AI 助手直接调用 ComfyUI
- [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo) - 优秀的视频生成工具
- [NarratoAI](https://github.com/linyqh/NarratoAI) - 影视解说自动化工具
- [MoneyPrinterPlus](https://github.com/ddean2009/MoneyPrinterPlus) - 视频创作平台
- [ComfyKit](https://github.com/puke3615/ComfyKit) - ComfyUI 工作流封装库
感谢这些项目的开源精神!🙏
## 💬 社区交流
扫描下方二维码加入我们的社区,获取最新动态和技术支持:
| 微信群 | Discord 社区 |
| ---- | ---- |
| <img src="resources/wechat.png" alt="微信交流群" width="250" /> | <img src="resources/discord.png" alt="Discord 社区" width="250" /> |
## 📢 反馈与支持
- 🐛 **遇到问题**: 提交 [Issue](https://github.com/AIDC-AI/Pixelle-Video/issues)
- 💡 **功能建议**: 提交 [Feature Request](https://github.com/AIDC-AI/Pixelle-Video/issues)
-**给个 Star**: 如果这个项目对你有帮助,欢迎给个 Star 支持一下!
## 📝 许可证
本项目采用 Apache 2.0 许可证,详情请查看 [LICENSE](LICENSE) 文件。
## 📚 系列工作
| 框架图 | 论文信息 |
|:---:|---|
| <img src="https://github.com/HITsz-TMG/VideoClaw/blob/main/FilmAgent-pics/framework.png" width="420" alt="FilmAgent framework"/> | **[SIGGRAPH Asia 2024] FilmAgent: Automating Virtual Film Production Through a Multi-Agent Collaborative Framework**<br>*Zhenran Xu, Longyue Wang, Jifang Wang, Zhouyi Li, Senbao Shi, Xue Yang, Yiyu Wang, Baotian Hu, Jun Yu, Min Zhang*<br>[[Paper](https://arxiv.org/pdf/2501.12909)] [[GitHub](https://github.com/HITsz-TMG/VideoClaw/blob/main/FilmAgent)] |
| <img src="https://github.com/HITsz-TMG/Anim-Director/blob/main/Anim-Director/assets/visualeg.png" width="420" alt="Anim-Director result"/> | **[SIGGRAPH Asia 2024] Anim-Director: A Large Multimodal Model Powered Agent for Controllable Animation Video Generation**<br>*Yunxin Li, Haoyuan Shi, Baotian Hu, Longyue Wang, Jiashun Zhu, Jinyi Xu, Zhen Zhao, Min Zhang*<br>[[Paper](https://doi.org/10.1145/3680528.3687688)] [[GitHub](https://github.com/HITsz-TMG/Anim-Director/tree/main/Anim-Director)] |
| <img src="https://github.com/AIDC-AI/ComfyUI-Copilot/blob/main/assets/Framework-v3.png" width="420" alt="Anim-Director result"/> | **[ACL 2025] ComfyUI-Copilot: An Intelligent Assistant for Automated Workflow Development**<br>*Zhenran Xu, Xue Yang, Yiyu Wang, Qingli Hu, Zijiao Wu, Longyue Wang, Weihua Luo, Kaifu Zhang, Baotian Hu, Min Zhang*<br>[[Paper](https://aclanthology.org/2025.acl-demo.61/)] [[GitHub](https://github.com/AIDC-AI/ComfyUI-Copilot)] |
| <img src="https://raw.githubusercontent.com/HITsz-TMG/Anim-Director/main/AniMaker/assets/pipeline.png" width="420" alt="AniMaker pipeline"/> | **[SIGGRAPH Asia 2025] AniMaker: Multi-Agent Animated Storytelling with MCTS-Driven Clip Generation**<br>*Haoyuan Shi, Yunxin Li, Xinyu Chen, Longyue Wang, Baotian Hu, Min Zhang*<br>[[Paper](https://doi.org/10.1145/3757377.3764009)] [[GitHub](https://github.com/HITsz-TMG/Anim-Director/tree/main/AniMaker)] |
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=AIDC-AI/Pixelle-Video&type=Date)](https://star-history.com/#AIDC-AI/Pixelle-Video&Date)
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`ATH-MaaS/Pixelle-Video`
- 原始仓库:https://github.com/ATH-MaaS/Pixelle-Video
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+469
View File
@@ -0,0 +1,469 @@
<h1 align="center">🎬 Pixelle-Video —— AI Fully Automated Short Video Engine</h1>
<p align="center"><b>English</b> | <a href="README.md">中文</a></p>
<p align="center">
<a href="https://www.youtube.com/watch?v=uUkx-lRxLjc" target="_blank"><img src="https://img.shields.io/badge/🎥 Video%20Tutorial-EA4C89" alt="Video Tutorial"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/releases" target="_blank"><img src="https://img.shields.io/badge/📦 Windows-50C878" alt="Windows Package"></a>
<a href="https://aidc-ai.github.io/Pixelle-Video" target="_blank"><img src="https://img.shields.io/badge/📘 Documentation-4A90E2" alt="Documentation"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/stargazers"><img src="https://img.shields.io/github/stars/AIDC-AI/Pixelle-Video.svg" alt="Stargazers"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/issues"><img src="https://img.shields.io/github/issues/AIDC-AI/Pixelle-Video.svg" alt="Issues"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/network/members"><img src="https://img.shields.io/github/forks/AIDC-AI/Pixelle-Video.svg" alt="Forks"></a>
<a href="https://github.com/AIDC-AI/Pixelle-Video/blob/main/LICENSE"><img src="https://img.shields.io/github/license/AIDC-AI/Pixelle-Video.svg" alt="License"></a>
</p>
https://github.com/user-attachments/assets/a42e7457-fcc8-40da-83fc-784c45a8b95d
Just input a **topic**, and Pixelle-Video will automatically:
- ✍️ Write video script
- 🎨 Generate AI images/videos
- 🗣️ Synthesize voice narration
- 🎵 Add background music
- 🎬 Create video with one click
**Zero threshold, zero editing experience** - Make video creation as simple as typing a sentence!
## 🖥️ Web Interface Preview
![Web UI Interface](resources/webui_en.png)
## 📋 Recent Updates
-**2026-06-01**: Added direct API media model configuration in WebUI, including image/video provider credentials, Base URLs, and per-provider proxy toggles
-**2026-01-26**: Added the Motion Transfer pipeline — upload a reference video and an image to transfer motion.
-**2026-01-14**: Added "Digital Human" and "Image-to-Video" pipelines, multi-language TTS voices support
-**2026-01-06**: Added RunningHub 48G VRAM machine support
-**2025-12-28**: Configurable RunningHub concurrency limit, improved LLM structured data response handling
-**2025-12-17**: Added ComfyUI API Key configuration, Nano Banana model support, API template custom parameters
-**2025-12-10**: Built-in FAQ in sidebar, fixed edge-tts version to resolve TTS service instability
-**2025-12-08**: Support multiple script split modes (paragraph/line/sentence), improved template selection with direct preview
-**2025-12-06**: Fixed video generation API URL path handling with cross-platform compatibility
-**2025-12-05**: Added Windows all-in-one package download, optimized image and video analysis workflows
-**2025-12-04**: New "Custom Media" feature - upload your photos/videos with AI-powered analysis and script generation
-**2025-11-18**: Parallel processing for RunningHub, added history page, batch video task creation support
## ✨ Key Features
-**Fully Automatic Generation** - Input a topic, automatically generate complete video
-**AI Smart Copywriting** - Intelligently create narration based on topic, no need to write scripts yourself
-**AI Generated Images** - Each sentence comes with beautiful AI illustrations
-**AI Generated Videos** - Support AI video generation models (like WAN 2.1) to create dynamic video content
-**Direct Model APIs** - Directly call image/video generation services from DashScope, OpenAI, Seedream, Seedance, Kling, and more
-**AI Generated Voice** - Support Edge-TTS, Index-TTS and many other mainstream TTS solutions
-**Background Music** - Support adding BGM to make videos more atmospheric
-**Visual Styles** - Multiple templates to choose from, create unique video styles
-**Flexible Dimensions** - Support portrait, landscape and other video dimensions
-**Multiple AI Models** - Support GPT, Qwen, DeepSeek, Ollama and more
-**Flexible Atomic Capability Combination** - Supports ComfyUI / RunningHub workflows and direct API models, allowing image, video, TTS, VLM and other capabilities to be swapped as needed
## 📊 Video Generation Pipeline
Pixelle-Video adopts a modular design, the entire video generation process is clear and concise:
![Video Generation Flow](resources/flow_en.png)
From input text to final video output, the entire process is clear and simple: **Script Generation → Image Planning → Frame-by-Frame Processing → Video Composition**
Each step supports flexible customization, allowing you to choose different AI models, audio engines, visual styles, etc., to meet personalized creation needs.
## 🎬 Video Examples
Here are actual cases generated using Pixelle-Video, showcasing video effects with different themes and styles:
### 📱 Extension Module Video Showcase
<table>
<tr>
<td width="33%">
<h3>👤 AI Digital Avatar</h3>
<video src="https://github.com/user-attachments/assets/7c122563-c2e0-4dcd-a73c-25ba1d4fa2dd" controls width="100%"></video>
<p align="center"><b>Korean-speaking AI Avatar</b></p>
</td>
<td width="33%">
<h3>🖼️ Image-to-Video</h3>
<video src="https://github.com/user-attachments/assets/5b4eef17-07d0-4bde-9748-2ed68cc9888e" controls width="100%"></video>
<p align="center"><b>Animated Cartoon Video</b></p>
</td>
<td width="33%">
<h3>💃 Motion Transfer</h3>
<video src="https://github.com/user-attachments/assets/7b1240bc-e965-434c-b343-118ec4793d4f" controls width="100%"></video>
<p align="center"><b>Dancing Kitten</b></p>
</td>
</tr>
</table>
### 📱 Portrait Video Showcase
<table>
<tr>
<td width="33%">
<h3>🌄 Documentary & Lifestyle Default Template</h3>
<video src="https://github.com/user-attachments/assets/e6716c1d-78de-453d-84c2-10873c8c595f" controls width="100%"></video>
<p align="center"><b>The Scenery Along the Journey</b></p>
</td>
<td width="33%">
<h3>🔍 Cultural Deconstruction Default Template</h3>
<video src="https://github.com/user-attachments/assets/f5de75f6-135a-4ab4-9f5f-079f649764d5" controls width="100%"></video>
<p align="center"><b>Santa ID</b></p>
</td>
<td width="33%">
<h3>🔭 Scientific Inquiry Default Template</h3>
<video src="https://github.com/user-attachments/assets/ceb8b0df-8331-4e1f-88e7-db5b295a1c1d" controls width="100%"></video>
<p align="center"><b>Why Havent We Found Alien Civilizations Yet?</b></p>
</td>
</tr>
<tr>
<td width="33%">
<h3>🌱 Personal Growth Cloned Voice</h3>
<video src="https://github.com/user-attachments/assets/1bad9a49-df83-4905-9cc8-9a7640e9c7d8" controls width="100%"></video>
<p align="center"><b>How to Level Up Yourself</b></p>
</td>
<td width="33%">
<h3>🧠 Deep Thinking Default Template</h3>
<video src="https://github.com/user-attachments/assets/663b705a-2aea-44bc-b266-4bb27aa255a8" controls width="100%"></video>
<p align="center"><b>Understanding Antifragility</b></p>
</td>
<td width="33%">
<h3>🏯 History & Culture Static Frame</h3>
<video src="https://github.com/user-attachments/assets/56e0a018-fa99-47eb-a97f-fc2fa8915724" controls width="100%"></video>
<p align="center"><b>Zizhi Tongjian (Comprehensive Mirror for Aid in Governance)</b></p>
</td>
</tr>
<tr>
<td width="33%">
<h3>☀️ Emotional Storytelling Cloned Voice</h3>
<video src="https://github.com/user-attachments/assets/4687df95-dd21-4a7b-b01e-f33a7b646644" controls width="100%"></video>
<p align="center"><b>Winter Sunlight</b></p>
</td>
<td width="33%">
<h3>📜 Novel Adaptation Custom Script</h3>
<video src="https://github.com/user-attachments/assets/d354465e-3fa8-40b4-93e9-61ad75ef0697" controls width="100%"></video>
<p align="center"><b>Doupo Cangqiong (Battle Through the Heavens)</b></p>
</td>
<td width="33%">
<h3>🧬 Knowledge Explainer Qwen Image Generation</h3>
<video src="https://github.com/user-attachments/assets/8ac21768-41ce-4d41-acdd-e3dd3eb9725a" controls width="100%"></video>
<p align="center"><b>Essential Wellness Tips</b></p>
</td>
</tr>
</table>
### 🖥️ Landscape Video Showcase
<table>
<tr>
<td width="50%">
<h3>💰 Side Hustle Money Making - Movie Template</h3>
<video src="https://github.com/user-attachments/assets/c9209d4e-73a6-4b82-aaad-cf102248c9e2" controls width="100%"></video>
<p align="center"><b>Side Hustle Money Making</b></p>
</td>
<td width="50%">
<h3>🏛️ Historical Commentary - Custom Template</h3>
<video src="https://github.com/user-attachments/assets/a767c452-d5f1-4cff-bb34-b80fff0d4c3e" controls width="100%"></video>
<p align="center"><b>Insights from Zizhi Tongjian</b></p>
</td>
</tr>
</table>
> 💡 **Tip**: All these videos are fully automatically generated by AI just by inputting a topic keyword, without any video editing experience required!
<div id="tutorial-start" />
## 🚀 Quick Start
### 🪟 Windows All-in-One Package (Recommended for Windows Users)
**No need to install Python, uv, or ffmpeg - ready to use out of the box!**
👉 **[Download Windows All-in-One Package](https://github.com/AIDC-AI/Pixelle-Video/releases/latest)**
1. Download the latest Windows All-in-One Package and extract it
2. Double-click `start.bat` to launch the Web interface
3. Browser will automatically open http://localhost:8501
4. Configure LLM API and image generation service in "⚙️ System Configuration"
5. Start generating videos!
> 💡 **Tip**: The package includes all dependencies, no need to manually install any environment. On first use, you only need to configure API keys.
### Install from Source (For macOS / Linux Users or Users Who Need Customization)
#### Prerequisites
Before starting, you need to install Python package manager `uv` and video processing tool `ffmpeg`:
##### Install uv
Please visit the uv official documentation to see the installation method for your system:
👉 **[uv Installation Guide](https://docs.astral.sh/uv/getting-started/installation/)**
After installation, run `uv --version` in the terminal to verify successful installation.
##### Install ffmpeg
**macOS**
```bash
brew install ffmpeg
```
**Ubuntu / Debian**
```bash
sudo apt update
sudo apt install ffmpeg
```
**Windows**
- Download URL: https://ffmpeg.org/download.html
- After downloading, extract and add the `bin` directory to the system environment variable PATH
After installation, run `ffmpeg -version` in the terminal to verify successful installation.
#### Step 1: Clone Project
```bash
git clone https://github.com/AIDC-AI/Pixelle-Video.git
cd Pixelle-Video
```
#### Step 2: Launch Web Interface
```bash
# Run with uv (recommended, will automatically install dependencies)
uv run streamlit run web/app.py
```
Browser will automatically open http://localhost:8501
#### Step 3: Configure in Web Interface
On first use, expand the "⚙️ System Configuration" panel and fill in:
- **LLM Configuration**: Select AI model (such as Qwen, GPT, etc.) and enter API Key
- **ComfyUI / RunningHub Configuration**: Configure local ComfyUI or RunningHub API Key if you want to use workflow-based image, video, or voice generation
- **API Media Model Configuration**: Configure API Key, Base URL, and proxy options for direct image/video model providers such as DashScope, OpenAI, ARK, and Kling
After configuration, click "Save Configuration", and you can start generating videos!
<div id="tutorial-end" />
## 💻 Usage
After opening the Web interface, you will see a three-column layout. Here's a detailed explanation of each part:
### ⚙️ System Configuration (Required on First Use)
Configuration is required on first use. Click to expand the "⚙️ System Configuration" panel:
#### 1. LLM Configuration (Large Language Model)
Used for generating video scripts.
**Quick Select Preset**
- Select preset model from dropdown menu (Qwen, GPT-4o, DeepSeek, etc.)
- After selection, base_url and model will be automatically filled
- Click "🔑 Get API Key" link to register and obtain key
**Manual Configuration**
- API Key: Enter your key
- Base URL: API address
- Model: Model name
#### 2. ComfyUI / RunningHub Configuration
Used for generating video images, video clips, or voices through ComfyUI workflows.
**Local Deployment (Recommended)**
- ComfyUI URL: Local ComfyUI service address (default http://127.0.0.1:8188)
- Click "Test Connection" to confirm service is available
**Cloud Deployment**
- RunningHub API Key: Cloud image generation service key
#### 3. API Media Model Configuration
Used to directly call image, video, or asset-analysis model providers without relying on ComfyUI/RunningHub.
**Supported Providers**
- OpenAI / GPT Image: for GPT image generation models
- DashScope / Wan / HappyHorse: for Alibaba Tongyi Wan image and video generation
- Volcengine ARK / Seedream / Seedance: for Seedream image generation and Seedance video generation
- Kling AI: for Kling video generation
**Configurable Items**
- API Key / Access Key / Secret Key: provider credentials
- Base URL: model service endpoint, with official defaults prefilled in WebUI
- Local proxy: for example `http://127.0.0.1:9090`
- Use proxy: each provider can independently choose whether to route requests through the local proxy
- Print model request parameters: debug option that prints prompts, model names, and input file paths to the terminal
> 💡 If you only use ComfyUI or RunningHub, you can leave API Media Model Configuration empty. If you choose an `api/...` workflow, configure the corresponding provider credentials first.
After configuration, click "Save Configuration".
### 📝 Content Input (Left Column)
#### Generation Mode
- **AI Generated Content**: Input topic, AI automatically creates script
- Suitable for: Want to quickly generate video, let AI write script
- Example: "Why develop a reading habit"
- **Fixed Script Content**: Directly input complete script, skip AI creation
- Suitable for: Already have ready-made script, directly generate video
#### Background Music (BGM)
- **No BGM**: Pure voice narration
- **Built-in Music**: Select preset background music (such as default.mp3)
- **Custom Music**: Put your music files (MP3/WAV, etc.) in the `bgm/` folder
- Click "Preview BGM" to preview music
### 🎤 Voice Settings (Middle Column)
#### TTS Workflow
- Select TTS workflow from dropdown menu (supports Edge-TTS, Index-TTS, etc.)
- System will automatically scan TTS workflows in the `workflows/` folder
- If you know ComfyUI, you can customize TTS workflows
#### Reference Audio (Optional)
- Upload reference audio file for voice cloning (supports MP3/WAV/FLAC and other formats)
- Suitable for TTS workflows that support voice cloning (such as Index-TTS)
- Can listen directly after upload
#### Preview Function
- Enter test text, click "Preview Voice" to listen to the effect
- Supports using reference audio for preview
### 🎨 Visual Settings (Middle Column)
#### Image Generation
Determine what style of images AI generates.
**ComfyUI Workflow**
- Select image generation workflow from dropdown menu
- Supports local deployment (selfhost) and cloud (RunningHub) workflows
- Also supports `api/...` direct image model workflows after configuring the corresponding provider credentials
- Default uses `image_flux.json`
- If you know ComfyUI, you can put your own workflows in the `workflows/` folder
**Image Dimensions**
- Set width and height of generated images (unit: pixels)
- Default 1024x1024, can be adjusted as needed
- Note: Different models have different dimension limitations
**Prompt Prefix**
- Controls overall image style (language needs to be English)
- Example: Minimalist black-and-white matchstick figure style illustration, clean lines, simple sketch style
- Click "Preview Style" to test effect
#### Video Template
Determines video layout and design.
**Template Naming Convention**
- `static_*.html`: Static templates (no AI-generated media, text-only styles)
- `image_*.html`: Image templates (uses AI-generated images as background)
- `video_*.html`: Video templates (uses AI-generated videos as background)
**Usage**
- Select template from dropdown menu, displayed grouped by dimension (portrait/landscape/square)
- Click "Preview Template" to test effect with custom parameters
- If you know HTML, you can create your own templates in the `templates/` folder
- 🔗 [View All Template Previews](https://aidc-ai.github.io/Pixelle-Video/user-guide/templates/#built-in-template-preview)
#### API Video Generation
When using dynamic video templates or extension workflows, you can generate clips through direct API video models.
- Supports DashScope Wan / HappyHorse, Kling, Seedance and other video models
- Displays model-aware options such as resolution, aspect ratio, duration, watermark, and native audio
- Supports network/download retries and LLM-based prompt neutralization retry for content-inspection failures
- In the Custom Media workflow, API video segments try to follow narration audio duration and use neighboring segment information to improve continuity
### 🎬 Generate Video (Right Column)
#### Generate Button
- After configuring all parameters, click "🎬 Generate Video"
- Shows real-time progress (generating script → generating images → synthesizing voice → composing video)
- Automatically shows video preview after completion
#### Progress Display
- Shows current step in real-time
- Example: "Frame 3/5 - Generating Image"
#### Video Preview
- Automatically plays after generation
- Shows video duration, file size, number of frames, etc.
- Video files are saved in the `output/` folder
### ❓ FAQ
**Q: How long does it take to use for the first time?**
A: Generation time depends on the number of video frames, network conditions, and AI inference speed, typically completed within a few minutes.
**Q: What if I'm not satisfied with the video?**
A: You can try:
1. Change LLM model (different models have different script styles)
2. Adjust image dimensions and prompt prefix (change image style)
3. Change TTS workflow or upload reference audio (change voice effect)
4. Try different video templates and dimensions
**Q: What about the cost?**
A: **This project fully supports free operation!**
- **Completely Free Solution**: LLM using Ollama (local) + ComfyUI local deployment = 0 cost
- **Recommended Solution**: LLM using Qwen (extremely low cost, highly cost-effective) + ComfyUI local deployment
- **Cloud Solution**: LLM using OpenAI + Image using RunningHub (higher cost but no need for local environment)
**Selection Suggestion**: If you have a local GPU, recommend completely free solution, otherwise recommend using Qwen (cost-effective)
## 🤝 Referenced Projects
Pixelle-Video design is inspired by the following excellent open-source projects:
- [Pixelle-MCP](https://github.com/AIDC-AI/Pixelle-MCP) - ComfyUI MCP server, allows AI assistants to directly call ComfyUI
- [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo) - Excellent video generation tool
- [NarratoAI](https://github.com/linyqh/NarratoAI) - Film commentary automation tool
- [MoneyPrinterPlus](https://github.com/ddean2009/MoneyPrinterPlus) - Video creation platform
- [ComfyKit](https://github.com/puke3615/ComfyKit) - ComfyUI workflow wrapper library
Thanks for the open-source spirit of these projects! 🙏
## 💬 Community
Scan the QR codes below to join our communities for latest updates and technical support:
| Discord Community | WeChat Group |
| ---- | ---- |
| <img src="resources/discord.png" alt="Discord Community" width="250" /> | <img src="resources/wechat.png" alt="WeChat Group" width="250" /> |
## 📢 Feedback and Support
- 🐛 **Encountered Issues**: Submit [Issue](https://github.com/AIDC-AI/Pixelle-Video/issues)
- 💡 **Feature Suggestions**: Submit [Feature Request](https://github.com/AIDC-AI/Pixelle-Video/issues)
-**Give a Star**: If this project helps you, feel free to give a Star for support!
## 📝 License
This project is released under the Apache License 2.0. For details, please see the [LICENSE](LICENSE) file.
## 📚 Research Series
| Framework | Paper |
|:---:|---|
| <img src="https://github.com/HITsz-TMG/VideoClaw/blob/main/FilmAgent-pics/framework.png" width="420" alt="FilmAgent framework"/> | **[SIGGRAPH Asia 2024] FilmAgent: Automating Virtual Film Production Through a Multi-Agent Collaborative Framework**<br>*Zhenran Xu, Longyue Wang, Jifang Wang, Zhouyi Li, Senbao Shi, Xue Yang, Yiyu Wang, Baotian Hu, Jun Yu, Min Zhang*<br>[[Paper](https://arxiv.org/pdf/2501.12909)] [[GitHub](https://github.com/HITsz-TMG/VideoClaw/blob/main/FilmAgent)] |
| <img src="https://github.com/AIDC-AI/ComfyUI-Copilot/blob/main/assets/Framework-v3.png" width="420" alt="Anim-Director result"/> | **[ACL 2025] ComfyUI-Copilot: An Intelligent Assistant for Automated Workflow Development**<br>*Zhenran Xu, Xue Yang, Yiyu Wang, Qingli Hu, Zijiao Wu, Longyue Wang, Weihua Luo, Kaifu Zhang, Baotian Hu, Min Zhang*<br>[[Paper](https://aclanthology.org/2025.acl-demo.61/)] [[GitHub](https://github.com/AIDC-AI/ComfyUI-Copilot)] |
| <img src="https://raw.githubusercontent.com/HITsz-TMG/Anim-Director/main/AniMaker/assets/pipeline.png" width="420" alt="AniMaker pipeline"/> | **[SIGGRAPH Asia 2025] AniMaker: Multi-Agent Animated Storytelling with MCTS-Driven Clip Generation**<br>*Haoyuan Shi, Yunxin Li, Xinyu Chen, Longyue Wang, Baotian Hu, Min Zhang*<br>[[Paper](https://doi.org/10.1145/3757377.3764009)] [[GitHub](https://github.com/HITsz-TMG/Anim-Director/tree/main/AniMaker)] |
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=AIDC-AI/Pixelle-Video&type=Date)](https://star-history.com/#AIDC-AI/Pixelle-Video&Date)
+17
View File
@@ -0,0 +1,17 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Pixelle-Video API Layer
FastAPI-based REST API for video generation services.
"""
+191
View File
@@ -0,0 +1,191 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Pixelle-Video FastAPI Application
Main FastAPI app with all routers and middleware.
Run this script to start the FastAPI server:
uv run python api/app.py
Or with custom settings:
uv run python api/app.py --host 0.0.0.0 --port 8080 --reload
"""
import sys
from pathlib import Path
# Add project root to sys.path for module imports
# This ensures imports work correctly in both development and packaged environments
_script_dir = Path(__file__).resolve().parent
_project_root = _script_dir.parent
if str(_project_root) not in sys.path:
sys.path.insert(0, str(_project_root))
import argparse
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from loguru import logger
from api.config import api_config
from api.tasks import task_manager
from api.dependencies import shutdown_pixelle_video
# Import routers
from api.routers import (
health_router,
llm_router,
tts_router,
image_router,
content_router,
video_router,
tasks_router,
files_router,
resources_router,
frame_router,
)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
Application lifespan manager
Handles startup and shutdown events.
"""
# Startup
logger.info("🚀 Starting Pixelle-Video API...")
await task_manager.start()
logger.info("✅ Pixelle-Video API started successfully\n")
yield
# Shutdown
logger.info("🛑 Shutting down Pixelle-Video API...")
await task_manager.stop()
await shutdown_pixelle_video()
logger.info("✅ Pixelle-Video API shutdown complete")
# Create FastAPI app
app = FastAPI(
title="Pixelle-Video API",
description="""
## Pixelle-Video - AI Video Generation Platform API
### Features
- 🤖 **LLM**: Large language model integration
- 🔊 **TTS**: Text-to-speech synthesis
- 🎨 **Image**: AI image generation
- 📝 **Content**: Automated content generation
- 🎬 **Video**: End-to-end video generation
### Video Generation Modes
- **Sync**: `/api/video/generate/sync` - For small videos (< 30s)
- **Async**: `/api/video/generate/async` - For large videos with task tracking
### Getting Started
1. Check health: `GET /health`
2. Generate narrations: `POST /api/content/narration`
3. Generate video: `POST /api/video/generate/sync` or `/async`
4. Track task progress: `GET /api/tasks/{task_id}`
""",
version="0.1.0",
docs_url=api_config.docs_url,
redoc_url=api_config.redoc_url,
openapi_url=api_config.openapi_url,
lifespan=lifespan,
)
# Add CORS middleware
if api_config.cors_enabled:
app.add_middleware(
CORSMiddleware,
allow_origins=api_config.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
logger.info(f"CORS enabled for origins: {api_config.cors_origins}")
# Include routers
# Health check (no prefix)
app.include_router(health_router)
# API routers (with /api prefix)
app.include_router(llm_router, prefix=api_config.api_prefix)
app.include_router(tts_router, prefix=api_config.api_prefix)
app.include_router(image_router, prefix=api_config.api_prefix)
app.include_router(content_router, prefix=api_config.api_prefix)
app.include_router(video_router, prefix=api_config.api_prefix)
app.include_router(tasks_router, prefix=api_config.api_prefix)
app.include_router(files_router, prefix=api_config.api_prefix)
app.include_router(resources_router, prefix=api_config.api_prefix)
app.include_router(frame_router, prefix=api_config.api_prefix)
@app.get("/")
async def root():
"""Root endpoint with API information"""
return {
"service": "Pixelle-Video API",
"version": "0.1.0",
"docs": api_config.docs_url,
"health": "/health",
"api": {
"llm": f"{api_config.api_prefix}/llm",
"tts": f"{api_config.api_prefix}/tts",
"image": f"{api_config.api_prefix}/image",
"content": f"{api_config.api_prefix}/content",
"video": f"{api_config.api_prefix}/video",
"tasks": f"{api_config.api_prefix}/tasks",
"files": f"{api_config.api_prefix}/files",
"resources": f"{api_config.api_prefix}/resources",
"frame": f"{api_config.api_prefix}/frame",
}
}
if __name__ == "__main__":
import uvicorn
# Parse command line arguments
parser = argparse.ArgumentParser(description="Start Pixelle-Video API Server")
parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
parser.add_argument("--port", type=int, default=8000, help="Port to bind to")
parser.add_argument("--reload", action="store_true", help="Enable auto-reload")
args = parser.parse_args()
# Print startup banner
print(f"""
╔══════════════════════════════════════════════════════════════╗
║ Pixelle-Video API Server ║
╚══════════════════════════════════════════════════════════════╝
Starting server at http://{args.host}:{args.port}
API Docs: http://{args.host}:{args.port}/docs
ReDoc: http://{args.host}:{args.port}/redoc
Press Ctrl+C to stop the server
""")
# Start server
uvicorn.run(
"api.app:app",
host=args.host,
port=args.port,
reload=args.reload,
)
+50
View File
@@ -0,0 +1,50 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
API Configuration
"""
from typing import Optional
from pydantic import BaseModel
class APIConfig(BaseModel):
"""API configuration"""
# Server settings
host: str = "0.0.0.0"
port: int = 8000
reload: bool = False
# CORS settings
cors_enabled: bool = True
cors_origins: list[str] = ["*"]
# Task settings
max_concurrent_tasks: int = 5
task_cleanup_interval: int = 3600 # Clean completed tasks every hour
task_retention_time: int = 86400 # Keep task results for 24 hours
# File upload settings
max_upload_size: int = 100 * 1024 * 1024 # 100MB
# API settings
api_prefix: str = "/api"
docs_url: Optional[str] = "/docs"
redoc_url: Optional[str] = "/redoc"
openapi_url: Optional[str] = "/openapi.json"
# Global config instance
api_config = APIConfig()
+61
View File
@@ -0,0 +1,61 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
FastAPI Dependencies
Provides dependency injection for PixelleVideoCore and other services.
"""
from typing import Annotated
from fastapi import Depends
from loguru import logger
from pixelle_video.service import PixelleVideoCore
# Global Pixelle-Video instance
_pixelle_video_instance: PixelleVideoCore = None
async def get_pixelle_video() -> PixelleVideoCore:
"""
Get Pixelle-Video core instance (dependency injection)
Returns:
PixelleVideoCore instance
"""
global _pixelle_video_instance
if _pixelle_video_instance is None:
_pixelle_video_instance = PixelleVideoCore()
await _pixelle_video_instance.initialize()
logger.info("✅ Pixelle-Video initialized for API")
return _pixelle_video_instance
async def shutdown_pixelle_video():
"""Shutdown Pixelle-Video instance and cleanup resources"""
global _pixelle_video_instance
if _pixelle_video_instance:
logger.info("Shutting down Pixelle-Video...")
await _pixelle_video_instance.cleanup()
_pixelle_video_instance = None
from pixelle_video.services.frame_html import HTMLFrameGenerator
await HTMLFrameGenerator.close_browser()
# Type alias for dependency injection
PixelleVideoDep = Annotated[PixelleVideoCore, Depends(get_pixelle_video)]
+40
View File
@@ -0,0 +1,40 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
API Routers
"""
from api.routers.health import router as health_router
from api.routers.llm import router as llm_router
from api.routers.tts import router as tts_router
from api.routers.image import router as image_router
from api.routers.content import router as content_router
from api.routers.video import router as video_router
from api.routers.tasks import router as tasks_router
from api.routers.files import router as files_router
from api.routers.resources import router as resources_router
from api.routers.frame import router as frame_router
__all__ = [
"health_router",
"llm_router",
"tts_router",
"image_router",
"content_router",
"video_router",
"tasks_router",
"files_router",
"resources_router",
"frame_router",
]
+146
View File
@@ -0,0 +1,146 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Content generation endpoints
Endpoints for generating narrations, image prompts, and titles.
"""
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.content import (
NarrationGenerateRequest,
NarrationGenerateResponse,
ImagePromptGenerateRequest,
ImagePromptGenerateResponse,
TitleGenerateRequest,
TitleGenerateResponse,
)
from pixelle_video.utils.content_generators import (
generate_narrations_from_topic,
generate_image_prompts,
generate_title,
)
router = APIRouter(prefix="/content", tags=["Content Generation"])
@router.post("/narration", response_model=NarrationGenerateResponse)
async def generate_narration(
request: NarrationGenerateRequest,
pixelle_video: PixelleVideoDep
):
"""
Generate narrations from text
Uses LLM to break down text into multiple narration segments.
- **text**: Source text
- **n_scenes**: Number of narrations to generate
- **min_words**: Minimum words per narration
- **max_words**: Maximum words per narration
Returns list of narration strings.
"""
try:
logger.info(f"Generating {request.n_scenes} narrations from text")
# Call narration generator utility function
narrations = await generate_narrations_from_topic(
llm_service=pixelle_video.llm,
topic=request.text,
n_scenes=request.n_scenes,
min_words=request.min_words,
max_words=request.max_words
)
return NarrationGenerateResponse(
narrations=narrations
)
except Exception as e:
logger.error(f"Narration generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/image-prompt", response_model=ImagePromptGenerateResponse)
async def generate_image_prompt(
request: ImagePromptGenerateRequest,
pixelle_video: PixelleVideoDep
):
"""
Generate image prompts from narrations
Uses LLM to create detailed image generation prompts.
- **narrations**: List of narration texts
- **min_words**: Minimum words per prompt
- **max_words**: Maximum words per prompt
Returns list of image prompts.
"""
try:
logger.info(f"Generating image prompts for {len(request.narrations)} narrations")
# Call image prompt generator utility function
image_prompts = await generate_image_prompts(
llm_service=pixelle_video.llm,
narrations=request.narrations,
min_words=request.min_words,
max_words=request.max_words
)
return ImagePromptGenerateResponse(
image_prompts=image_prompts
)
except Exception as e:
logger.error(f"Image prompt generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/title", response_model=TitleGenerateResponse)
async def generate_title_endpoint(
request: TitleGenerateRequest,
pixelle_video: PixelleVideoDep
):
"""
Generate video title from text
Uses LLM to create an engaging title.
- **text**: Source text
- **style**: Optional title style hint
Returns generated title.
"""
try:
logger.info("Generating title from text")
# Call title generator utility function
title = await generate_title(
llm_service=pixelle_video.llm,
content=request.text,
strategy="llm"
)
return TitleGenerateResponse(
title=title
)
except Exception as e:
logger.error(f"Title generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+128
View File
@@ -0,0 +1,128 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
File service endpoints
Provides access to generated files (videos, images, audio) and resource files.
"""
from pathlib import Path
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse
from loguru import logger
router = APIRouter(prefix="/files", tags=["Files"])
@router.get("/{file_path:path}")
async def get_file(file_path: str):
"""
Get file by path
Serves files from allowed directories:
- output/ - Generated files (videos, images, audio)
- workflows/ - ComfyUI workflow files
- templates/ - HTML templates
- bgm/ - Background music
- data/bgm/ - Custom background music
- data/templates/ - Custom templates
- resources/ - Other resources (images, fonts, etc.)
- **file_path**: File path relative to allowed directories
Examples:
- "abc123.mp4" → output/abc123.mp4
- "workflows/runninghub/image_flux.json" → workflows/runninghub/image_flux.json
- "templates/1080x1920/default.html" → templates/1080x1920/default.html
- "bgm/default.mp3" → bgm/default.mp3
- "resources/example.png" → resources/example.png
Returns file for download or preview.
"""
try:
# Define allowed directories (in priority order)
allowed_prefixes = [
"output/",
"workflows/",
"templates/",
"bgm/",
"data/bgm/",
"data/templates/",
"resources/",
]
# Check if path starts with allowed prefix, otherwise try output/
full_path = None
for prefix in allowed_prefixes:
if file_path.startswith(prefix):
full_path = file_path
break
# If no prefix matched, assume it's in output/ (backward compatibility)
if full_path is None:
full_path = f"output/{file_path}"
abs_path = Path.cwd() / full_path
if not abs_path.exists():
raise HTTPException(status_code=404, detail=f"File not found: {file_path}")
if not abs_path.is_file():
raise HTTPException(status_code=400, detail=f"Path is not a file: {file_path}")
# Security: only allow access to specified directories
try:
rel_path = abs_path.relative_to(Path.cwd())
rel_path_str = str(rel_path)
# Check if path starts with any allowed prefix
is_allowed = any(rel_path_str.startswith(prefix.rstrip('/')) for prefix in allowed_prefixes)
if not is_allowed:
raise HTTPException(
status_code=403,
detail=f"Access denied: only {', '.join(p.rstrip('/') for p in allowed_prefixes)} directories are accessible"
)
except ValueError:
raise HTTPException(status_code=403, detail="Access denied")
# Determine media type
suffix = abs_path.suffix.lower()
media_types = {
'.mp4': 'video/mp4',
'.mp3': 'audio/mpeg',
'.wav': 'audio/wav',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.html': 'text/html',
'.json': 'application/json',
}
media_type = media_types.get(suffix, 'application/octet-stream')
# Use inline disposition for browser preview
return FileResponse(
path=str(abs_path),
media_type=media_type,
headers={
"Content-Disposition": f'inline; filename="{abs_path.name}"'
}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"File access error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+161
View File
@@ -0,0 +1,161 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Frame/Template rendering endpoints
"""
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.frame import FrameRenderRequest, FrameRenderResponse, TemplateParamsResponse
from pixelle_video.services.frame_html import HTMLFrameGenerator
from pixelle_video.utils.template_util import parse_template_size, resolve_template_path
router = APIRouter(prefix="/frame", tags=["Frame Rendering"])
@router.post("/render", response_model=FrameRenderResponse)
async def render_frame(
request: FrameRenderRequest,
pixelle_video: PixelleVideoDep
):
"""
Render a single frame using HTML template
Generates a frame image by combining template, title, text, and image.
This is useful for previewing templates or generating custom frames.
- **template**: Template key (e.g., '1080x1920/default.html')
- **title**: Optional title text
- **text**: Frame text content
- **image**: Image path (can be local path or URL)
Returns path to generated frame image.
Example:
```json
{
"template": "1080x1920/modern.html",
"title": "Welcome",
"text": "This is a beautiful frame with custom styling",
"image": "resources/example.png"
}
```
"""
try:
logger.info(f"Frame render request: template={request.template}")
# Resolve template path (returns absolute path with "templates/" or "data/templates/" prefix)
template_path = resolve_template_path(request.template)
# Parse template size
width, height = parse_template_size(template_path)
# Create HTML frame generator
generator = HTMLFrameGenerator(template_path)
# Generate frame
frame_path = await generator.generate_frame(
title=request.title,
text=request.text,
image=request.image
)
return FrameRenderResponse(
frame_path=frame_path,
width=width,
height=height
)
except Exception as e:
logger.error(f"Frame render error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/template/params", response_model=TemplateParamsResponse)
async def get_template_params(
template: str
):
"""
Get custom parameters for a template
Returns the custom parameters defined in the template HTML file.
These parameters can be passed via `template_params` in video generation requests.
Template parameters are defined using syntax: `{{param_name:type=default}}`
Supported types:
- `text`: String input
- `number`: Numeric input
- `color`: Color picker (hex format)
- `bool`: Boolean checkbox
Example template syntax:
```html
<div style="color: {{accent_color:color=#ff0000}}">
{{custom_text:text=Hello World}}
</div>
```
Args:
template: Template path (e.g., '1080x1920/image_default.html')
Returns:
Template parameters with their types, defaults, and labels
Example response:
```json
{
"template": "1080x1920/image_default.html",
"media_width": 1080,
"media_height": 1440,
"params": {
"accent_color": {
"type": "color",
"default": "#ff0000",
"label": "accent_color"
},
"background": {
"type": "text",
"default": "https://example.com/bg.jpg",
"label": "background"
}
}
}
```
"""
try:
logger.info(f"Get template params: {template}")
# Resolve template path
template_path = resolve_template_path(template)
# Create generator and parse parameters
generator = HTMLFrameGenerator(template_path)
params = generator.parse_template_parameters()
media_width, media_height = generator.get_media_size()
return TemplateParamsResponse(
template=template,
media_width=media_width,
media_height=media_height,
params=params
)
except FileNotFoundError:
raise HTTPException(status_code=404, detail=f"Template not found: {template}")
except Exception as e:
logger.error(f"Get template params error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+54
View File
@@ -0,0 +1,54 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Health check and system info endpoints
"""
from fastapi import APIRouter
from pydantic import BaseModel
router = APIRouter(tags=["Health"])
class HealthResponse(BaseModel):
"""Health check response"""
status: str = "healthy"
version: str = "0.1.0"
service: str = "Pixelle-Video API"
class CapabilitiesResponse(BaseModel):
"""Capabilities response"""
success: bool = True
capabilities: dict
@router.get("/health", response_model=HealthResponse)
async def health_check():
"""
Health check endpoint
Returns service status and version information.
"""
return HealthResponse()
@router.get("/version", response_model=HealthResponse)
async def get_version():
"""
Get API version
Returns version information.
"""
return HealthResponse()
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Image generation endpoints
"""
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.image import ImageGenerateRequest, ImageGenerateResponse
router = APIRouter(prefix="/image", tags=["Basic Services"])
@router.post("/generate", response_model=ImageGenerateResponse)
async def image_generate(
request: ImageGenerateRequest,
pixelle_video: PixelleVideoDep
):
"""
Image generation endpoint
Generate image from text prompt using ComfyKit.
- **prompt**: Image description/prompt
- **width**: Image width (512-2048)
- **height**: Image height (512-2048)
- **workflow**: Optional custom workflow filename
Returns path to generated image.
"""
try:
logger.info(f"Image generation request: {request.prompt[:50]}...")
# Call media service (backward compatible with image API)
media_result = await pixelle_video.media(
prompt=request.prompt,
width=request.width,
height=request.height,
workflow=request.workflow
)
# For backward compatibility, only support image results in /image endpoint
if media_result.is_video:
raise HTTPException(
status_code=400,
detail="Video workflow used. Please use /media/generate endpoint for video generation."
)
return ImageGenerateResponse(
image_path=media_result.url
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Image generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+60
View File
@@ -0,0 +1,60 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
LLM (Large Language Model) endpoints
"""
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.llm import LLMChatRequest, LLMChatResponse
router = APIRouter(prefix="/llm", tags=["Basic Services"])
@router.post("/chat", response_model=LLMChatResponse)
async def llm_chat(
request: LLMChatRequest,
pixelle_video: PixelleVideoDep
):
"""
LLM chat endpoint
Generate text response using configured LLM.
- **prompt**: User prompt/question
- **temperature**: Creativity level (0.0-2.0, lower = more deterministic)
- **max_tokens**: Maximum response length
Returns generated text response.
"""
try:
logger.info(f"LLM chat request: {request.prompt[:50]}...")
# Call LLM service
response = await pixelle_video.llm(
prompt=request.prompt,
temperature=request.temperature,
max_tokens=request.max_tokens
)
return LLMChatResponse(
content=response,
tokens_used=None # Can add token counting if needed
)
except Exception as e:
logger.error(f"LLM chat error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+269
View File
@@ -0,0 +1,269 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Resource discovery endpoints
Provides endpoints to discover available workflows, templates, and BGM.
"""
from pathlib import Path
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.resources import (
WorkflowInfo,
WorkflowListResponse,
TemplateInfo,
TemplateListResponse,
BGMInfo,
BGMListResponse,
)
from pixelle_video.utils.os_util import list_resource_files, get_root_path, get_data_path
from pixelle_video.utils.template_util import get_all_templates_with_info
router = APIRouter(prefix="/resources", tags=["Resources"])
@router.get("/workflows/tts", response_model=WorkflowListResponse)
async def list_tts_workflows(pixelle_video: PixelleVideoDep):
"""
List available TTS workflows
Returns list of TTS workflows from both RunningHub and self-hosted sources.
Example response:
```json
{
"workflows": [
{
"name": "tts_edge.json",
"display_name": "tts_edge.json - Runninghub",
"source": "runninghub",
"path": "workflows/runninghub/tts_edge.json",
"key": "runninghub/tts_edge.json",
"workflow_id": "123456"
}
]
}
```
"""
try:
# Get all workflows from TTS service
all_workflows = pixelle_video.tts.list_workflows()
# Filter to TTS workflows only (filename starts with "tts_")
tts_workflows = [
WorkflowInfo(**wf)
for wf in all_workflows
if wf["name"].startswith("tts_")
]
return WorkflowListResponse(workflows=tts_workflows)
except Exception as e:
logger.error(f"List TTS workflows error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/workflows/media", response_model=WorkflowListResponse)
async def list_media_workflows(pixelle_video: PixelleVideoDep):
"""
List available media workflows (both image and video)
Returns list of all media workflows from both RunningHub and self-hosted sources.
Example response:
```json
{
"workflows": [
{
"name": "image_flux.json",
"display_name": "image_flux.json - Runninghub",
"source": "runninghub",
"path": "workflows/runninghub/image_flux.json",
"key": "runninghub/image_flux.json",
"workflow_id": "123456"
},
{
"name": "video_wan2.1.json",
"display_name": "video_wan2.1.json - Runninghub",
"source": "runninghub",
"path": "workflows/runninghub/video_wan2.1.json",
"key": "runninghub/video_wan2.1.json",
"workflow_id": "123457"
}
]
}
```
"""
try:
# Get all workflows from media service (includes both image and video)
all_workflows = pixelle_video.media.list_workflows()
media_workflows = [WorkflowInfo(**wf) for wf in all_workflows]
return WorkflowListResponse(workflows=media_workflows)
except Exception as e:
logger.error(f"List media workflows error: {e}")
raise HTTPException(status_code=500, detail=str(e))
# Keep old endpoint for backward compatibility
@router.get("/workflows/image", response_model=WorkflowListResponse)
async def list_image_workflows(pixelle_video: PixelleVideoDep):
"""
List available image workflows (deprecated, use /workflows/media instead)
This endpoint is kept for backward compatibility but will filter to image_ workflows only.
"""
try:
all_workflows = pixelle_video.media.list_workflows()
# Filter to image workflows only (filename starts with "image_")
image_workflows = [
WorkflowInfo(**wf)
for wf in all_workflows
if wf["name"].startswith("image_")
]
return WorkflowListResponse(workflows=image_workflows)
except Exception as e:
logger.error(f"List image workflows error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/templates", response_model=TemplateListResponse)
async def list_templates():
"""
List available video templates
Returns list of HTML templates grouped by size (portrait, landscape, square).
Templates are merged from both default (templates/) and custom (data/templates/) directories.
Example response:
```json
{
"templates": [
{
"name": "default.html",
"display_name": "default.html",
"size": "1080x1920",
"width": 1080,
"height": 1920,
"orientation": "portrait",
"path": "templates/1080x1920/default.html",
"key": "1080x1920/default.html"
}
]
}
```
"""
try:
# Get all templates with info
all_templates = get_all_templates_with_info()
# Convert to API response format
templates = []
for t in all_templates:
templates.append(TemplateInfo(
name=t.display_info.name,
display_name=t.display_info.name,
size=t.display_info.size,
width=t.display_info.width,
height=t.display_info.height,
orientation=t.display_info.orientation,
path=t.template_path,
key=t.template_path
))
return TemplateListResponse(templates=templates)
except Exception as e:
logger.error(f"List templates error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/bgm", response_model=BGMListResponse)
async def list_bgm():
"""
List available background music files
Returns list of BGM files merged from both default (bgm/) and custom (data/bgm/) directories.
Custom files take precedence over default files with the same name.
Supported formats: mp3, wav, flac, m4a, aac, ogg
Example response:
```json
{
"bgm_files": [
{
"name": "default.mp3",
"path": "bgm/default.mp3",
"source": "default"
},
{
"name": "happy.mp3",
"path": "data/bgm/happy.mp3",
"source": "custom"
}
]
}
```
"""
try:
# Supported audio extensions
audio_extensions = ('.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg')
# Collect BGM files from both locations
bgm_files_dict = {} # {filename: {"path": str, "source": str}}
# Scan default bgm/ directory
default_bgm_dir = Path(get_root_path("bgm"))
if default_bgm_dir.exists() and default_bgm_dir.is_dir():
for item in default_bgm_dir.iterdir():
if item.is_file() and item.suffix.lower() in audio_extensions:
bgm_files_dict[item.name] = {
"path": f"bgm/{item.name}",
"source": "default"
}
# Scan custom data/bgm/ directory (overrides default)
custom_bgm_dir = Path(get_data_path("bgm"))
if custom_bgm_dir.exists() and custom_bgm_dir.is_dir():
for item in custom_bgm_dir.iterdir():
if item.is_file() and item.suffix.lower() in audio_extensions:
bgm_files_dict[item.name] = {
"path": f"data/bgm/{item.name}",
"source": "custom"
}
# Convert to response format
bgm_files = [
BGMInfo(
name=name,
path=info["path"],
source=info["source"]
)
for name, info in sorted(bgm_files_dict.items())
]
return BGMListResponse(bgm_files=bgm_files)
except Exception as e:
logger.error(f"List BGM error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+105
View File
@@ -0,0 +1,105 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Task management endpoints
Endpoints for managing async tasks (checking status, canceling, etc.)
"""
from typing import List, Optional
from fastapi import APIRouter, HTTPException, Query
from loguru import logger
from api.tasks import task_manager, Task, TaskStatus
router = APIRouter(prefix="/tasks", tags=["Tasks"])
@router.get("", response_model=List[Task])
async def list_tasks(
status: Optional[TaskStatus] = Query(None, description="Filter by status"),
limit: int = Query(100, ge=1, le=1000, description="Maximum number of tasks")
):
"""
List tasks
Retrieve list of tasks with optional filtering.
- **status**: Optional filter by status (pending/running/completed/failed/cancelled)
- **limit**: Maximum number of tasks to return (default 100)
Returns list of tasks sorted by creation time (newest first).
"""
try:
tasks = task_manager.list_tasks(status=status, limit=limit)
return tasks
except Exception as e:
logger.error(f"List tasks error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/{task_id}", response_model=Task)
async def get_task(task_id: str):
"""
Get task details
Retrieve detailed information about a specific task.
- **task_id**: Task ID
Returns task details including status, progress, and result (if completed).
"""
try:
task = task_manager.get_task(task_id)
if not task:
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
return task
except HTTPException:
raise
except Exception as e:
logger.error(f"Get task error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/{task_id}")
async def cancel_task(task_id: str):
"""
Cancel task
Cancel a running or pending task.
- **task_id**: Task ID
Returns success status.
"""
try:
success = task_manager.cancel_task(task_id)
if not success:
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
return {
"success": True,
"message": f"Task {task_id} cancelled successfully"
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Cancel task error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+94
View File
@@ -0,0 +1,94 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
TTS (Text-to-Speech) endpoints
"""
from fastapi import APIRouter, HTTPException
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.tts import TTSSynthesizeRequest, TTSSynthesizeResponse
from pixelle_video.utils.tts_util import get_audio_duration
router = APIRouter(prefix="/tts", tags=["Basic Services"])
@router.post("/synthesize", response_model=TTSSynthesizeResponse)
async def tts_synthesize(
request: TTSSynthesizeRequest,
pixelle_video: PixelleVideoDep
):
"""
Text-to-Speech synthesis endpoint
Convert text to speech audio using ComfyUI workflows.
- **text**: Text to synthesize
- **workflow**: TTS workflow key (optional, uses default if not specified)
- **ref_audio**: Reference audio for voice cloning (optional)
- **voice_id**: (Deprecated) Voice ID for legacy compatibility
Returns path to generated audio file and duration.
Examples:
```json
{
"text": "Hello, welcome to Pixelle-Video!",
"workflow": "runninghub/tts_edge.json"
}
```
With voice cloning:
```json
{
"text": "Hello, this is a cloned voice",
"workflow": "runninghub/tts_index2.json",
"ref_audio": "path/to/reference.wav"
}
```
"""
try:
logger.info(f"TTS synthesis request: {request.text[:50]}...")
# Build TTS parameters
tts_params = {"text": request.text}
# Add workflow if specified
if request.workflow:
tts_params["workflow"] = request.workflow
# Add ref_audio if specified
if request.ref_audio:
tts_params["ref_audio"] = request.ref_audio
# Legacy voice_id support (deprecated)
if request.voice_id and not request.workflow:
logger.warning("voice_id parameter is deprecated, please use workflow instead")
tts_params["voice"] = request.voice_id
# Call TTS service
audio_path = await pixelle_video.tts(**tts_params)
# Get audio duration
duration = get_audio_duration(audio_path)
return TTSSynthesizeResponse(
audio_path=audio_path,
duration=duration
)
except Exception as e:
logger.error(f"TTS synthesis error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+290
View File
@@ -0,0 +1,290 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Video generation endpoints
Supports both synchronous and asynchronous video generation.
"""
import os
from fastapi import APIRouter, HTTPException, Request
from loguru import logger
from api.dependencies import PixelleVideoDep
from api.schemas.video import (
VideoGenerateRequest,
VideoGenerateResponse,
VideoGenerateAsyncResponse,
)
from api.tasks import task_manager, TaskType
router = APIRouter(prefix="/video", tags=["Video Generation"])
def path_to_url(request: Request, file_path: str) -> str:
"""
Convert file path to accessible URL
Handles both absolute and relative paths, extracting the path relative
to the output directory for URL construction.
Args:
request: FastAPI Request object (provides base_url from actual request)
file_path: Absolute or relative file path
Returns:
Full URL to access the file
Examples:
Windows: G:\\...\\output\\20251205_233630_c939\\final.mp4
-> http://localhost:8000/api/files/20251205_233630_c939/final.mp4
Linux: /home/user/.../output/20251205_233630_c939/final.mp4
-> http://localhost:8000/api/files/20251205_233630_c939/final.mp4
Domain: With domain request -> https://your-domain.com/api/files/...
"""
from pathlib import Path
import os
# Normalize path separators to forward slashes first (for cross-platform compatibility)
file_path = file_path.replace("\\", "/")
# Check if it's an absolute path (works for both Windows and Linux)
is_absolute = os.path.isabs(file_path) or Path(file_path).is_absolute()
if is_absolute:
# Find "output" in the path and get everything after it
# Split by / to work with normalized paths
parts = file_path.split("/")
try:
output_idx = parts.index("output")
# Get all parts after "output" and join them
relative_parts = parts[output_idx + 1:]
file_path = "/".join(relative_parts)
except ValueError:
# If "output" not in path, use the filename only
file_path = Path(file_path).name
else:
# If relative path starting with "output/", remove it
if file_path.startswith("output/"):
file_path = file_path[7:] # Remove "output/"
# Build URL using request's base_url (automatically matches the request host)
base_url = str(request.base_url).rstrip('/')
return f"{base_url}/api/files/{file_path}"
@router.post("/generate/sync", response_model=VideoGenerateResponse)
async def generate_video_sync(
request_body: VideoGenerateRequest,
pixelle_video: PixelleVideoDep,
request: Request
):
"""
Generate video synchronously
This endpoint blocks until video generation is complete.
Suitable for small videos (< 30 seconds).
**Note**: May timeout for large videos. Use `/generate/async` instead.
Request body includes all video generation parameters.
See VideoGenerateRequest schema for details.
Returns path to generated video, duration, and file size.
"""
try:
logger.info(f"Sync video generation: {request_body.text[:50]}...")
# Auto-determine media_width and media_height from template meta tags (required)
if not request_body.frame_template:
raise ValueError("frame_template is required to determine media size")
from pixelle_video.services.frame_html import HTMLFrameGenerator
from pixelle_video.utils.template_util import resolve_template_path
template_path = resolve_template_path(request_body.frame_template)
generator = HTMLFrameGenerator(template_path)
media_width, media_height = generator.get_media_size()
logger.debug(f"Auto-determined media size from template: {media_width}x{media_height}")
# Build video generation parameters
video_params = {
"text": request_body.text,
"mode": request_body.mode,
"title": request_body.title,
"n_scenes": request_body.n_scenes,
"min_narration_words": request_body.min_narration_words,
"max_narration_words": request_body.max_narration_words,
"min_image_prompt_words": request_body.min_image_prompt_words,
"max_image_prompt_words": request_body.max_image_prompt_words,
"media_width": media_width,
"media_height": media_height,
"media_workflow": request_body.media_workflow,
"video_fps": request_body.video_fps,
"frame_template": request_body.frame_template,
"prompt_prefix": request_body.prompt_prefix,
"bgm_path": request_body.bgm_path,
"bgm_volume": request_body.bgm_volume,
}
# Add TTS workflow if specified
if request_body.tts_workflow:
video_params["tts_workflow"] = request_body.tts_workflow
# Add ref_audio if specified
if request_body.ref_audio:
video_params["ref_audio"] = request_body.ref_audio
# Legacy voice_id support (deprecated)
if request_body.voice_id:
logger.warning("voice_id parameter is deprecated, please use tts_workflow instead")
video_params["voice_id"] = request_body.voice_id
# Add custom template parameters if specified
if request_body.template_params:
video_params["template_params"] = request_body.template_params
# Call video generator service
result = await pixelle_video.generate_video(**video_params)
# Get file size
file_size = os.path.getsize(result.video_path) if os.path.exists(result.video_path) else 0
# Convert path to URL
video_url = path_to_url(request, result.video_path)
return VideoGenerateResponse(
video_url=video_url,
duration=result.duration,
file_size=file_size
)
except Exception as e:
logger.error(f"Sync video generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/generate/async", response_model=VideoGenerateAsyncResponse)
async def generate_video_async(
request_body: VideoGenerateRequest,
pixelle_video: PixelleVideoDep,
request: Request
):
"""
Generate video asynchronously
Creates a background task for video generation.
Returns immediately with a task_id for tracking progress.
**Workflow:**
1. Submit video generation request
2. Receive task_id in response
3. Poll `/api/tasks/{task_id}` to check status
4. When status is "completed", retrieve video from result
Request body includes all video generation parameters.
See VideoGenerateRequest schema for details.
Returns task_id for tracking progress.
"""
try:
logger.info(f"Async video generation: {request_body.text[:50]}...")
# Create task
task = task_manager.create_task(
task_type=TaskType.VIDEO_GENERATION,
request_params=request_body.model_dump()
)
# Define async execution function
async def execute_video_generation():
"""Execute video generation in background"""
# Auto-determine media_width and media_height from template meta tags (required)
if not request_body.frame_template:
raise ValueError("frame_template is required to determine media size")
from pixelle_video.services.frame_html import HTMLFrameGenerator
from pixelle_video.utils.template_util import resolve_template_path
template_path = resolve_template_path(request_body.frame_template)
generator = HTMLFrameGenerator(template_path)
media_width, media_height = generator.get_media_size()
logger.debug(f"Auto-determined media size from template: {media_width}x{media_height}")
# Build video generation parameters
video_params = {
"text": request_body.text,
"mode": request_body.mode,
"title": request_body.title,
"n_scenes": request_body.n_scenes,
"min_narration_words": request_body.min_narration_words,
"max_narration_words": request_body.max_narration_words,
"min_image_prompt_words": request_body.min_image_prompt_words,
"max_image_prompt_words": request_body.max_image_prompt_words,
"media_width": media_width,
"media_height": media_height,
"media_workflow": request_body.media_workflow,
"video_fps": request_body.video_fps,
"frame_template": request_body.frame_template,
"prompt_prefix": request_body.prompt_prefix,
"bgm_path": request_body.bgm_path,
"bgm_volume": request_body.bgm_volume,
# Progress callback can be added here if needed
# "progress_callback": lambda event: task_manager.update_progress(...)
}
# Add TTS workflow if specified
if request_body.tts_workflow:
video_params["tts_workflow"] = request_body.tts_workflow
# Add ref_audio if specified
if request_body.ref_audio:
video_params["ref_audio"] = request_body.ref_audio
# Legacy voice_id support (deprecated)
if request_body.voice_id:
logger.warning("voice_id parameter is deprecated, please use tts_workflow instead")
video_params["voice_id"] = request_body.voice_id
# Add custom template parameters if specified
if request_body.template_params:
video_params["template_params"] = request_body.template_params
result = await pixelle_video.generate_video(**video_params)
# Get file size
file_size = os.path.getsize(result.video_path) if os.path.exists(result.video_path) else 0
# Convert path to URL
video_url = path_to_url(request, result.video_path)
return {
"video_url": video_url,
"duration": result.duration,
"file_size": file_size
}
# Start execution
await task_manager.execute_task(
task_id=task.task_id,
coro_func=execute_video_generation
)
return VideoGenerateAsyncResponse(
task_id=task.task_id
)
except Exception as e:
logger.error(f"Async video generation error: {e}")
raise HTTPException(status_code=500, detail=str(e))
+60
View File
@@ -0,0 +1,60 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
API Schemas (Pydantic models)
"""
from api.schemas.base import BaseResponse, ErrorResponse
from api.schemas.llm import LLMChatRequest, LLMChatResponse
from api.schemas.tts import TTSSynthesizeRequest, TTSSynthesizeResponse
from api.schemas.image import ImageGenerateRequest, ImageGenerateResponse
from api.schemas.content import (
NarrationGenerateRequest,
NarrationGenerateResponse,
ImagePromptGenerateRequest,
ImagePromptGenerateResponse,
TitleGenerateRequest,
TitleGenerateResponse,
)
from api.schemas.video import (
VideoGenerateRequest,
VideoGenerateResponse,
VideoGenerateAsyncResponse,
)
__all__ = [
# Base
"BaseResponse",
"ErrorResponse",
# LLM
"LLMChatRequest",
"LLMChatResponse",
# TTS
"TTSSynthesizeRequest",
"TTSSynthesizeResponse",
# Image
"ImageGenerateRequest",
"ImageGenerateResponse",
# Content
"NarrationGenerateRequest",
"NarrationGenerateResponse",
"ImagePromptGenerateRequest",
"ImagePromptGenerateResponse",
"TitleGenerateRequest",
"TitleGenerateResponse",
# Video
"VideoGenerateRequest",
"VideoGenerateResponse",
"VideoGenerateAsyncResponse",
]
+33
View File
@@ -0,0 +1,33 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Base schemas
"""
from typing import Any, Optional
from pydantic import BaseModel
class BaseResponse(BaseModel):
"""Base API response"""
success: bool = True
message: str = "Success"
data: Optional[Any] = None
class ErrorResponse(BaseModel):
"""Error response"""
success: bool = False
message: str
error: Optional[str] = None
+103
View File
@@ -0,0 +1,103 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Content generation API schemas
"""
from typing import List, Optional
from pydantic import BaseModel, Field
# ============================================================================
# Narration Generation
# ============================================================================
class NarrationGenerateRequest(BaseModel):
"""Narration generation request"""
text: str = Field(..., description="Source text to generate narrations from")
n_scenes: int = Field(5, ge=1, le=20, description="Number of scenes")
min_words: int = Field(5, ge=1, le=100, description="Minimum words per narration")
max_words: int = Field(20, ge=1, le=200, description="Maximum words per narration")
class Config:
json_schema_extra = {
"example": {
"text": "Atomic Habits is about making small changes that lead to remarkable results.",
"n_scenes": 5,
"min_words": 5,
"max_words": 20
}
}
class NarrationGenerateResponse(BaseModel):
"""Narration generation response"""
success: bool = True
message: str = "Success"
narrations: List[str] = Field(..., description="Generated narrations")
# ============================================================================
# Image Prompt Generation
# ============================================================================
class ImagePromptGenerateRequest(BaseModel):
"""Image prompt generation request"""
narrations: List[str] = Field(..., description="List of narrations")
min_words: int = Field(30, ge=10, le=100, description="Minimum words per prompt")
max_words: int = Field(60, ge=10, le=200, description="Maximum words per prompt")
class Config:
json_schema_extra = {
"example": {
"narrations": [
"Small habits compound over time",
"Focus on systems, not goals"
],
"min_words": 30,
"max_words": 60
}
}
class ImagePromptGenerateResponse(BaseModel):
"""Image prompt generation response"""
success: bool = True
message: str = "Success"
image_prompts: List[str] = Field(..., description="Generated image prompts")
# ============================================================================
# Title Generation
# ============================================================================
class TitleGenerateRequest(BaseModel):
"""Title generation request"""
text: str = Field(..., description="Source text")
style: Optional[str] = Field(None, description="Title style (e.g., 'engaging', 'formal')")
class Config:
json_schema_extra = {
"example": {
"text": "Atomic Habits is about making small changes that lead to remarkable results.",
"style": "engaging"
}
}
class TitleGenerateResponse(BaseModel):
"""Title generation response"""
success: bool = True
message: str = "Success"
title: str = Field(..., description="Generated title")
+69
View File
@@ -0,0 +1,69 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Frame/Template rendering API schemas
"""
from typing import Optional, Dict, Any, List
from pydantic import BaseModel, Field
class FrameRenderRequest(BaseModel):
"""Frame rendering request"""
template: str = Field(
...,
description="Template key (e.g., '1080x1920/default.html'). Can also be just filename (e.g., 'default.html') to use default size."
)
title: Optional[str] = Field(None, description="Frame title (optional)")
text: str = Field(..., description="Frame text content")
image: Optional[str] = Field(None, description="Image path or URL (optional)")
class Config:
json_schema_extra = {
"example": {
"template": "1080x1920/default.html",
"title": "Sample Title",
"text": "This is a sample text for the frame.",
"image": "resources/example.png"
}
}
class FrameRenderResponse(BaseModel):
"""Frame rendering response"""
success: bool = True
message: str = "Success"
frame_path: str = Field(..., description="Path to generated frame image")
width: int = Field(..., description="Frame width in pixels")
height: int = Field(..., description="Frame height in pixels")
class TemplateParamConfig(BaseModel):
"""Single template parameter configuration"""
type: str = Field(..., description="Parameter type: 'text', 'number', 'color', 'bool'")
default: Any = Field(..., description="Default value")
label: str = Field(..., description="Display label for the parameter")
class TemplateParamsResponse(BaseModel):
"""Template parameters response"""
success: bool = True
message: str = "Success"
template: str = Field(..., description="Template path")
media_width: int = Field(..., description="Media width from template meta tags")
media_height: int = Field(..., description="Media height from template meta tags")
params: Dict[str, TemplateParamConfig] = Field(
default_factory=dict,
description="Custom parameters defined in template. Key is parameter name, value is config."
)
+43
View File
@@ -0,0 +1,43 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Image generation API schemas
"""
from typing import Optional
from pydantic import BaseModel, Field
class ImageGenerateRequest(BaseModel):
"""Image generation request"""
prompt: str = Field(..., description="Image generation prompt")
width: int = Field(1024, ge=512, le=2048, description="Image width")
height: int = Field(1024, ge=512, le=2048, description="Image height")
workflow: Optional[str] = Field(None, description="Custom workflow filename")
class Config:
json_schema_extra = {
"example": {
"prompt": "A serene mountain landscape at sunset, photorealistic style",
"width": 1024,
"height": 1024
}
}
class ImageGenerateResponse(BaseModel):
"""Image generation response"""
success: bool = True
message: str = "Success"
image_path: str = Field(..., description="Path to generated image")
+43
View File
@@ -0,0 +1,43 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
LLM API schemas
"""
from typing import Optional
from pydantic import BaseModel, Field
class LLMChatRequest(BaseModel):
"""LLM chat request"""
prompt: str = Field(..., description="User prompt")
temperature: float = Field(0.7, ge=0.0, le=2.0, description="Temperature (0.0-2.0)")
max_tokens: int = Field(2000, ge=1, le=32000, description="Maximum tokens")
class Config:
json_schema_extra = {
"example": {
"prompt": "Explain the concept of atomic habits in 3 sentences",
"temperature": 0.7,
"max_tokens": 2000
}
}
class LLMChatResponse(BaseModel):
"""LLM chat response"""
success: bool = True
message: str = "Success"
content: str = Field(..., description="Generated response")
tokens_used: Optional[int] = Field(None, description="Tokens used (if available)")
+69
View File
@@ -0,0 +1,69 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Resource discovery API schemas
"""
from typing import List, Optional
from pydantic import BaseModel, Field
class WorkflowInfo(BaseModel):
"""Workflow information"""
name: str = Field(..., description="Workflow filename")
display_name: str = Field(..., description="Display name with source info")
source: str = Field(..., description="Source (runninghub or selfhost)")
path: str = Field(..., description="Full path to workflow file")
key: str = Field(..., description="Workflow key (source/name)")
workflow_id: Optional[str] = Field(None, description="RunningHub workflow ID (if applicable)")
class WorkflowListResponse(BaseModel):
"""Workflow list response"""
success: bool = True
message: str = "Success"
workflows: List[WorkflowInfo] = Field(..., description="List of available workflows")
class TemplateInfo(BaseModel):
"""Template information"""
name: str = Field(..., description="Template filename")
display_name: str = Field(..., description="Display name")
size: str = Field(..., description="Size (e.g., 1080x1920)")
width: int = Field(..., description="Width in pixels")
height: int = Field(..., description="Height in pixels")
orientation: str = Field(..., description="Orientation (portrait/landscape/square)")
path: str = Field(..., description="Full path to template file")
key: str = Field(..., description="Template key (size/name)")
class TemplateListResponse(BaseModel):
"""Template list response"""
success: bool = True
message: str = "Success"
templates: List[TemplateInfo] = Field(..., description="List of available templates")
class BGMInfo(BaseModel):
"""BGM information"""
name: str = Field(..., description="BGM filename")
path: str = Field(..., description="Full path to BGM file")
source: str = Field(..., description="Source (default or custom)")
class BGMListResponse(BaseModel):
"""BGM list response"""
success: bool = True
message: str = "Success"
bgm_files: List[BGMInfo] = Field(..., description="List of available BGM files")
+53
View File
@@ -0,0 +1,53 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
TTS API schemas
"""
from typing import Optional
from pydantic import BaseModel, Field
class TTSSynthesizeRequest(BaseModel):
"""TTS synthesis request"""
text: str = Field(..., description="Text to synthesize")
workflow: Optional[str] = Field(
None,
description="TTS workflow key (e.g., 'runninghub/tts_edge.json' or 'selfhost/tts_edge.json'). If not specified, uses default workflow from config."
)
ref_audio: Optional[str] = Field(
None,
description="Reference audio path for voice cloning (optional). Can be a local file path or URL."
)
voice_id: Optional[str] = Field(
None,
description="Voice ID (deprecated, use workflow instead)"
)
class Config:
json_schema_extra = {
"example": {
"text": "Hello, welcome to Pixelle-Video!",
"workflow": "runninghub/tts_edge.json",
"ref_audio": None
}
}
class TTSSynthesizeResponse(BaseModel):
"""TTS synthesis response"""
success: bool = True
message: str = "Success"
audio_path: str = Field(..., description="Path to generated audio file")
duration: float = Field(..., description="Audio duration in seconds")
+116
View File
@@ -0,0 +1,116 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Video generation API schemas
"""
from typing import Optional, Literal, Dict, Any
from pydantic import BaseModel, Field
class VideoGenerateRequest(BaseModel):
"""Video generation request"""
# === Input ===
text: str = Field(..., description="Source text for video generation")
# === Processing Mode ===
mode: Literal["generate", "fixed"] = Field(
"generate",
description="Processing mode: 'generate' (AI generates narrations) or 'fixed' (use text as-is)"
)
# === Optional Title ===
title: Optional[str] = Field(None, description="Video title (auto-generated if not provided)")
# === Basic Config ===
n_scenes: Optional[int] = Field(5, ge=1, le=20, description="Number of scenes (only used in 'generate' mode, ignored in 'fixed' mode)")
# === TTS Parameters ===
tts_workflow: Optional[str] = Field(
None,
description="TTS workflow key (e.g., 'runninghub/tts_edge.json'). If not specified, uses default workflow from config."
)
ref_audio: Optional[str] = Field(
None,
description="Reference audio path for voice cloning (optional)"
)
voice_id: Optional[str] = Field(
None,
description="(Deprecated) TTS voice ID for legacy compatibility"
)
# === LLM Parameters ===
min_narration_words: int = Field(5, ge=1, le=100, description="Min narration words")
max_narration_words: int = Field(20, ge=1, le=200, description="Max narration words")
min_image_prompt_words: int = Field(30, ge=10, le=100, description="Min image prompt words")
max_image_prompt_words: int = Field(60, ge=10, le=200, description="Max image prompt words")
# === Media Parameters ===
# Note: media_width and media_height are auto-determined from template meta tags
media_workflow: Optional[str] = Field(None, description="Custom media workflow (image or video)")
# === Video Parameters ===
video_fps: int = Field(30, ge=15, le=60, description="Video FPS")
# === Frame Template (determines video size) ===
frame_template: Optional[str] = Field(
None,
description="HTML template path with size (e.g., '1080x1920/default.html'). Video size is auto-determined from template."
)
# === Template Custom Parameters ===
template_params: Optional[Dict[str, Any]] = Field(
None,
description="Custom template parameters (e.g., {'accent_color': '#ff0000', 'background': 'url'}). "
"Available parameters depend on the template. Use GET /api/templates/{template_path}/params to discover them."
)
# === Image Style ===
prompt_prefix: Optional[str] = Field(None, description="Image style prefix")
# === BGM ===
bgm_path: Optional[str] = Field(None, description="Background music path")
bgm_volume: float = Field(0.3, ge=0.0, le=1.0, description="BGM volume (0.0-1.0)")
class Config:
json_schema_extra = {
"example": {
"text": "Atomic Habits teaches us that small changes compound over time to produce remarkable results.",
"mode": "generate",
"n_scenes": 5,
"frame_template": "1080x1920/image_default.html",
"template_params": {
"accent_color": "#3498db",
"background": "https://example.com/custom-bg.jpg"
},
"title": "The Power of Atomic Habits"
}
}
class VideoGenerateResponse(BaseModel):
"""Video generation response (synchronous)"""
success: bool = True
message: str = "Success"
video_url: str = Field(..., description="URL to access generated video")
duration: float = Field(..., description="Video duration in seconds")
file_size: int = Field(..., description="File size in bytes")
class VideoGenerateAsyncResponse(BaseModel):
"""Video generation async response"""
success: bool = True
message: str = "Task created successfully"
task_id: str = Field(..., description="Task ID for tracking progress")
+21
View File
@@ -0,0 +1,21 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Task management for async operations
"""
from api.tasks.models import Task, TaskStatus, TaskType
from api.tasks.manager import task_manager
__all__ = ["Task", "TaskStatus", "TaskType", "task_manager"]
+270
View File
@@ -0,0 +1,270 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Task Manager
In-memory task management for video generation jobs.
"""
import asyncio
import uuid
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Callable
from loguru import logger
from api.tasks.models import Task, TaskStatus, TaskType, TaskProgress
from api.config import api_config
class TaskManager:
"""
Task manager for handling async video generation tasks
Features:
- In-memory storage (can be replaced with Redis later)
- Task lifecycle management
- Progress tracking
- Auto cleanup of old tasks
"""
def __init__(self):
self._tasks: Dict[str, Task] = {}
self._task_futures: Dict[str, asyncio.Task] = {}
self._cleanup_task: Optional[asyncio.Task] = None
self._running = False
async def start(self):
"""Start task manager and cleanup scheduler"""
if self._running:
logger.warning("Task manager already running")
return
self._running = True
self._cleanup_task = asyncio.create_task(self._cleanup_loop())
logger.info("✅ Task manager started")
async def stop(self):
"""Stop task manager and cancel all tasks"""
self._running = False
# Cancel cleanup task
if self._cleanup_task:
self._cleanup_task.cancel()
try:
await self._cleanup_task
except asyncio.CancelledError:
pass
# Cancel all running tasks
for task_id, future in self._task_futures.items():
if not future.done():
future.cancel()
logger.info(f"Cancelled task: {task_id}")
self._tasks.clear()
self._task_futures.clear()
logger.info("✅ Task manager stopped")
def create_task(
self,
task_type: TaskType,
request_params: Optional[dict] = None
) -> Task:
"""
Create a new task
Args:
task_type: Type of task
request_params: Original request parameters
Returns:
Created task
"""
task_id = str(uuid.uuid4())
task = Task(
task_id=task_id,
task_type=task_type,
status=TaskStatus.PENDING,
request_params=request_params,
)
self._tasks[task_id] = task
logger.info(f"Created task {task_id} ({task_type})")
return task
async def execute_task(
self,
task_id: str,
coro_func: Callable,
*args,
**kwargs
):
"""
Execute task asynchronously
Args:
task_id: Task ID
coro_func: Async function to execute
*args: Positional arguments
**kwargs: Keyword arguments
"""
task = self._tasks.get(task_id)
if not task:
logger.error(f"Task {task_id} not found")
return
# Create async task
async def _execute():
try:
task.status = TaskStatus.RUNNING
task.started_at = datetime.now()
logger.info(f"Task {task_id} started")
# Execute the actual work
result = await coro_func(*args, **kwargs)
# Update task with result
task.status = TaskStatus.COMPLETED
task.result = result
task.completed_at = datetime.now()
logger.info(f"Task {task_id} completed")
except Exception as e:
task.status = TaskStatus.FAILED
task.error = str(e)
task.completed_at = datetime.now()
logger.error(f"Task {task_id} failed: {e}")
# Start execution
future = asyncio.create_task(_execute())
self._task_futures[task_id] = future
def get_task(self, task_id: str) -> Optional[Task]:
"""Get task by ID"""
return self._tasks.get(task_id)
def list_tasks(
self,
status: Optional[TaskStatus] = None,
limit: int = 100
) -> List[Task]:
"""
List tasks with optional filtering
Args:
status: Filter by status
limit: Maximum number of tasks to return
Returns:
List of tasks
"""
tasks = list(self._tasks.values())
if status:
tasks = [t for t in tasks if t.status == status]
# Sort by created_at descending
tasks.sort(key=lambda t: t.created_at, reverse=True)
return tasks[:limit]
def update_progress(
self,
task_id: str,
current: int,
total: int,
message: str = ""
):
"""
Update task progress
Args:
task_id: Task ID
current: Current progress
total: Total steps
message: Progress message
"""
task = self._tasks.get(task_id)
if not task:
return
percentage = (current / total * 100) if total > 0 else 0
task.progress = TaskProgress(
current=current,
total=total,
percentage=percentage,
message=message
)
def cancel_task(self, task_id: str) -> bool:
"""
Cancel a running task
Args:
task_id: Task ID
Returns:
True if cancelled, False otherwise
"""
task = self._tasks.get(task_id)
if not task:
return False
# Do not cancel already-terminal tasks
if task.status in [TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED]:
return False
# Cancel future if running
future = self._task_futures.get(task_id)
if future and not future.done():
future.cancel()
# Update task status
task.status = TaskStatus.CANCELLED
task.completed_at = datetime.now()
logger.info(f"Cancelled task {task_id}")
return True
async def _cleanup_loop(self):
"""Periodically clean up old completed tasks"""
while self._running:
try:
await asyncio.sleep(api_config.task_cleanup_interval)
self._cleanup_old_tasks()
except asyncio.CancelledError:
break
except Exception as e:
logger.error(f"Error in cleanup loop: {e}")
def _cleanup_old_tasks(self):
"""Remove old completed/failed tasks"""
cutoff_time = datetime.now() - timedelta(seconds=api_config.task_retention_time)
tasks_to_remove = []
for task_id, task in self._tasks.items():
if task.status in [TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED]:
if task.completed_at and task.completed_at < cutoff_time:
tasks_to_remove.append(task_id)
for task_id in tasks_to_remove:
del self._tasks[task_id]
if task_id in self._task_futures:
del self._task_futures[task_id]
if tasks_to_remove:
logger.info(f"Cleaned up {len(tasks_to_remove)} old tasks")
# Global task manager instance
task_manager = TaskManager()
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2025 AIDC-AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Task data models
"""
from datetime import datetime
from enum import Enum
from typing import Any, Optional
from pydantic import BaseModel, Field
class TaskStatus(str, Enum):
"""Task status"""
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class TaskType(str, Enum):
"""Task type"""
VIDEO_GENERATION = "video_generation"
class TaskProgress(BaseModel):
"""Task progress information"""
current: int = 0
total: int = 0
percentage: float = 0.0
message: str = ""
class Task(BaseModel):
"""Task model"""
task_id: str
task_type: TaskType
status: TaskStatus = TaskStatus.PENDING
# Progress tracking
progress: Optional[TaskProgress] = None
# Result
result: Optional[Any] = None
error: Optional[str] = None
# Metadata
created_at: datetime = Field(default_factory=datetime.now)
started_at: Optional[datetime] = None
completed_at: Optional[datetime] = None
# Request parameters (for reference)
request_params: Optional[dict] = None
class Config:
json_encoders = {
datetime: lambda v: v.isoformat()
}
BIN
View File
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
# Pixelle-Video Configuration
# Copy this file to config.yaml and fill in your settings
# ⚠️ Never commit config.yaml to Git!
project_name: Pixelle-Video
# ==================== LLM Configuration ====================
# Supports any OpenAI SDK compatible API
llm:
api_key: ""
base_url: ""
model: ""
# Popular presets:
# Qwen Max: base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1" model: "qwen-max"
# OpenAI GPT-4o: base_url: "https://api.openai.com/v1" model: "gpt-4o"
# DeepSeek: base_url: "https://api.deepseek.com" model: "deepseek-chat"
# Ollama (Local): base_url: "http://localhost:11434/v1" model: "llama3.2"
# ==================== Direct API Provider Configuration ====================
# Optional: use providers directly for image/video/VLM generation without ComfyUI workflows.
api_providers:
common:
print_model_input: false
local_proxy: ""
openai:
api_key: ""
base_url: "https://api.openai.com/v1"
use_proxy: false
dashscope:
api_key: ""
base_url: "https://dashscope.aliyuncs.com/api/v1"
use_proxy: false
ark:
api_key: ""
base_url: "https://ark.cn-beijing.volces.com/api/v3"
use_proxy: false
kling:
base_url: "https://api-beijing.klingai.com"
access_key: ""
secret_key: ""
use_proxy: false
# ==================== ComfyUI Configuration ====================
comfyui:
# Global ComfyUI settings
comfyui_url: http://127.0.0.1:8188 # ComfyUI server URL (required for selfhost workflows)
comfyui_api_key: "" # ComfyUI API key (optional, get from https://platform.comfy.org/profile/api-keys)
# Note for Docker users: Use host.docker.internal:8188 (Mac/Windows) or host IP address (Linux)
runninghub_api_key: "" # RunningHub API key (required for runninghub workflows)
runninghub_concurrent_limit: 1 # Concurrent execution limit for RunningHub (1-10, default 1 for regular members)
# TTS-specific configuration
tts:
default_workflow: selfhost/tts_edge.json # TTS workflow to use
# Image-specific configuration
image:
# Required: Default workflow to use (no fallback)
# Options: runninghub/image_flux.json (recommended, no local setup)
# selfhost/image_flux.json (requires local ComfyUI)
default_workflow: runninghub/image_flux.json
# Image prompt prefix (optional)
prompt_prefix: "Minimalist black-and-white matchstick figure style illustration, clean lines, simple sketch style"
# Video-specific configuration
video:
# Required: Default workflow to use (no fallback)
# Options: runninghub/video_wan2.1_fusionx.json (recommended, no local setup)
# selfhost/video_wan2.1_fusionx.json (requires local ComfyUI)
default_workflow: runninghub/video_wan2.1_fusionx.json
# Video prompt prefix (optional)
prompt_prefix: "Minimalist black-and-white matchstick figure style illustration, clean lines, simple sketch style"
# ==================== Template Configuration ====================
# Configure default template for video generation
template:
# Default frame template to use when not explicitly specified
# Determines video aspect ratio and layout style
# Template naming convention:
# - static_*.html: Static style templates (no AI-generated media)
# - image_*.html: Templates requiring AI-generated images
# - video_*.html: Templates requiring AI-generated videos
# Options:
# - 1080x1920 (vertical/portrait): image_default.html, image_modern.html, image_elegant.html, static_simple.html, etc.
# - 1080x1080 (square): image_minimal_framed.html, etc.
# - 1920x1080 (horizontal/landscape): image_film.html, image_full.html, etc.
# See templates/ directory for all available templates
default_template: "1080x1920/image_default.html"
+123
View File
@@ -0,0 +1,123 @@
version: '3.8'
# Build Arguments Configuration
# You can override these by setting environment variables before running docker-compose
#
# Example for China environment (auto uses Tsinghua mirror):
# USE_CN_MIRROR=true docker-compose up -d
#
# Example for international environment (default):
# docker-compose up -d
services:
# Init Service - Ensures config.yaml exists before other services start
# This fixes the Docker issue where mounting a non-existent file creates a directory
init:
image: alpine:latest
volumes:
- ./:/workspace
command: >
sh -c '
if [ -d /workspace/config.yaml ]; then
echo "⚠️ config.yaml is a directory, removing it...";
rm -rf /workspace/config.yaml;
fi;
if [ ! -f /workspace/config.yaml ] && [ -f /workspace/config.example.yaml ]; then
echo "📋 Creating config.yaml from config.example.yaml...";
cp /workspace/config.example.yaml /workspace/config.yaml;
echo "✅ config.yaml created successfully!";
else
echo "✅ config.yaml already exists.";
fi
'
restart: "no"
# API Service - FastAPI backend
api:
build:
context: .
dockerfile: Dockerfile
args:
USE_CN_MIRROR: ${USE_CN_MIRROR:-false}
container_name: pixelle-video-api
command: .venv/bin/python api/app.py --host 0.0.0.0 --port 8000
depends_on:
init:
condition: service_completed_successfully
ports:
- "8000:8000"
volumes:
# Mount config file (read-write to allow saving from Web UI)
# Note: init service auto-creates config.yaml from config.example.yaml if not exists
- ./config.yaml:/app/config.yaml
# Mount data directories for persistence
# data/ contains: users/, bgm/, templates/, workflows/ (custom resources)
- ./data:/app/data
- ./output:/app/output
# Note: Default resources (bgm/, templates/, workflows/) are baked into the image
# Custom resources in data/* will override defaults
environment:
- TZ=Asia/Shanghai
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- pixelle-network
# Web UI Service - Streamlit frontend
web:
build:
context: .
dockerfile: Dockerfile
args:
USE_CN_MIRROR: ${USE_CN_MIRROR:-false}
container_name: pixelle-video-web
command: .venv/bin/streamlit run web/app.py --server.port 8501 --server.address 0.0.0.0
depends_on:
init:
condition: service_completed_successfully
ports:
- "8501:8501"
volumes:
# Mount config file (read-write to allow saving from Web UI)
# Note: init service auto-creates config.yaml from config.example.yaml if not exists
- ./config.yaml:/app/config.yaml
# Mount data directories for persistence
# data/ contains: users/, bgm/, templates/, workflows/ (custom resources)
- ./data:/app/data
- ./output:/app/output
# Note: Default resources (bgm/, templates/, workflows/) are baked into the image
# Custom resources in data/* will override defaults
environment:
- TZ=Asia/Shanghai
- STREAMLIT_SERVER_PORT=8501
- STREAMLIT_SERVER_ADDRESS=0.0.0.0
- STREAMLIT_BROWSER_GATHER_USAGE_STATS=false
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8501/_stcore/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- pixelle-network
networks:
pixelle-network:
driver: bridge
+84
View File
@@ -0,0 +1,84 @@
#!/bin/bash
# Pixelle-Video Docker Quick Start Script
set -e
echo "🐳 Pixelle-Video Docker Deployment"
echo "=================================="
echo ""
# Check if config.yaml exists as a directory (Docker mount issue)
if [ -d config.yaml ]; then
echo "⚠️ config.yaml is a directory (Docker mount issue), removing it..."
rm -rf config.yaml
fi
# Check if config.yaml exists, if not, create from example
if [ ! -f config.yaml ]; then
echo "⚠️ config.yaml not found, creating from config.example.yaml..."
if [ -f config.example.yaml ]; then
cp config.example.yaml config.yaml
echo "✅ config.yaml created successfully!"
echo ""
echo "⚠️ IMPORTANT: Please edit config.yaml and fill in:"
echo " - LLM API key and settings"
echo " - ComfyUI URL (use host.docker.internal:8188 for local Mac/Windows)"
echo " - RunningHub API key (optional, for cloud workflows)"
echo ""
echo "You can also configure these settings in the Web UI after starting."
echo ""
else
echo "❌ Error: config.example.yaml not found!"
echo ""
exit 1
fi
fi
# Check if docker-compose is available
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
echo "❌ Error: docker-compose not found!"
echo ""
echo "Please install Docker Compose first:"
echo " https://docs.docker.com/compose/install/"
echo ""
exit 1
fi
# Use docker-compose or docker compose based on availability
if command -v docker-compose &> /dev/null; then
DOCKER_COMPOSE="docker-compose"
else
DOCKER_COMPOSE="docker compose"
fi
echo "📦 Building Docker images..."
$DOCKER_COMPOSE build
echo ""
echo "🚀 Starting services..."
$DOCKER_COMPOSE up -d
echo ""
echo "⏳ Waiting for services to be ready..."
sleep 5
echo ""
echo "✅ Pixelle-Video is now running!"
echo ""
echo "Services:"
echo " 🌐 Web UI: http://localhost:8501"
echo " 🔌 API: http://localhost:8000"
echo " 📚 API Docs: http://localhost:8000/docs"
echo ""
echo "Custom Resources (optional):"
echo " 📁 data/bgm/ - Custom background music (overrides default)"
echo " 📁 data/templates/ - Custom HTML templates (overrides default)"
echo " 📁 data/workflows/ - Custom ComfyUI workflows (overrides default)"
echo ""
echo "Useful commands:"
echo " View logs: $DOCKER_COMPOSE logs -f"
echo " Stop: $DOCKER_COMPOSE down"
echo " Restart: $DOCKER_COMPOSE restart"
echo " Rebuild: $DOCKER_COMPOSE up -d --build"
echo ""
+62
View File
@@ -0,0 +1,62 @@
# 🙋‍♀️ Pixelle-Video FAQ
### How to integrate custom local workflows?
If you want to integrate your own ComfyUI workflows, please follow these specifications:
1. **Run Locally First**: Ensure the workflow runs correctly in your local ComfyUI.
2. **Parameter Binding**: Find the Text node (CLIP Text Encode or similar text input node) where prompt words need to be dynamically passed by the program.
- Edit the **Title** of that node.
- Change the title to `$prompt.text!` or `$prompt.value!` (depending on the input type accepted by the node).
<img src="https://github.com/user-attachments/assets/ddb1962c-9272-486f-84ab-8019c3fb5bf4" width="600" alt="参数绑定示例" />
- *Reference Example: Check the editing method of existing JSON files in the `workflows/selfhost/` directory.*
3. **Export Format**: Export the modified workflow as **API Format** (Save (API Format)).
4. **File Naming**: Place the exported JSON file into the `workflows/` directory and adhere to the following naming prefixes:
- **Image Workflows**: Prefix must be `image_` (e.g., `image_my_style.json`)
- **Video Workflows**: Prefix must be `video_`
- **TTS Workflows**: Prefix must be `tts_`
### How to debug RunningHub workflows locally?
If you want to test workflows locally that were originally intended for RunningHub cloud usage:
1. **Get ID**: Open the RunningHub workflow file and find the ID.
2. **Load Workflow**: Paste the ID onto the end of the RunningHub URL (e.g., https://www.runninghub.cn/workflow/1983513964837543938) to enter the workflow page.
<img src="https://github.com/user-attachments/assets/e5330b3a-5475-44f2-81e4-057d33fdf71b" width="600" alt="参数绑定示例" />
3. **Download to Local**: Download the workflow as a JSON file from the workbench.
4. **Local Testing**: Drag the downloaded file into your local ComfyUI canvas for testing and debugging.
### Common Errors and Solutions
#### 1. TTS (Text-to-Speech) Errors
- **Reason**: The default Edge-TTS calls Microsoft's free interface, which may fail frequently due to network instability.
- **Solution**:
- Check your network connection.
- It is recommended to switch to **ComfyUI TTS** workflows (select workflows with the `tts_` prefix) for higher stability.
#### 2. LLM (Large Language Model) Errors
- **Troubleshooting Steps**:
1. Check if the **Base URL** is correct (ensure no extra spaces or incorrect suffixes).
2. Check if the **API Key** is valid and has sufficient balance.
3. Check if the **Model Name** is spelled correctly.
- *Tip: Please consult the official API documentation of your model provider (e.g., OpenAI, DeepSeek, Alibaba Cloud, etc.) for accurate configuration.*
#### 3. Error Message "Could not find a Chrome executable..."
- **Reason**: Your computer system lacks the Chrome browser core, causing features dependent on the browser to fail.
- **Solution**: Please download and install the Google Chrome browser.
### Where are generated videos saved?
All generated videos are automatically saved in the `output/` folder within the project directory. Upon completion, the interface will display the video duration, file size, number of shots, and a download link.
### Community Resources
- **GitHub Repository**: https://github.com/AIDC-AI/Pixelle-Video
- **Issue Reporting**: Submit bugs or feature requests via GitHub Issues.
- **Community Support**: Join discussion groups for help and experience sharing.
- **Contribution**: The project is under the MIT license and welcomes contributions.
💡 **Tip**: If you cannot find the answer you need in this FAQ, please submit an issue on GitHub or join the community discussion. We will continue to update this FAQ based on user feedback!
+65
View File
@@ -0,0 +1,65 @@
# 🙋‍♀️ Pixelle-Video 常见问题解答 (FAQ)
### 本地自己开发的工作流如何集成使用?
如果您想集成自己开发的 ComfyUI 工作流,请遵循以下规范:
1. **本地跑通**:首先确保工作流在您的本地 ComfyUI 中能正常运行。
2. **参数绑定**:找到需要由程序动态传入提示词的 Text 节点(CLIP Text Encode 或类似文本输入节点)。
- 编辑该节点的**标题 (Title)**。
- 修改标题为 `$prompt.text!``$prompt.value!`(根据节点接受的输入类型决定)。
<img src="https://github.com/user-attachments/assets/ddb1962c-9272-486f-84ab-8019c3fb5bf4" width="600" alt="参数绑定示例" />
- *参考示例:可以查看 `workflows/selfhost/` 目录下现有 JSON 文件的编辑方式。*
3. **导出格式**:将修改好的工作流导出为 **API 格式** (Save (API Format))。
4. **文件命名**:将导出的 JSON 文件放入 `workflows/` 目录,并遵守以下命名前缀:
- **图片类工作流**:前缀必须是 `image_` (例如 `image_my_style.json`)
- **视频类工作流**:前缀必须是 `video_`
- **语音合成类**:前缀必须是 `tts_`
### 如何在本地调试项目中的 RunningHub 工作流?
如果您想在本地测试项目中原本用于 RunningHub 云端的工作流:
1. **获取 ID**:打开runninghub工作流文件,找到id
2. **加载工作流**:将 ID 粘贴到 RunningHub 网站 URL 后缀上,如:https://www.runninghub.cn/workflow/1983513964837543938 进入该工作流页面。
<img src="https://github.com/user-attachments/assets/e5330b3a-5475-44f2-81e4-057d33fdf71b" width="600" alt="参数绑定示例" />
4. **下载到本地**:在工作台中将工作流下载为 JSON 文件。
5. **本地测试**:将下载的文件拖入您本地的 ComfyUI 画布进行测试和调试。
### 常见的报错及解决方案
#### 1. TTS (语音合成) 报错
- **原因**:默认的 Edge-TTS 是调用微软的免费接口,可能会受网络波动影响,导致失败频率较高。
- **解决方案**
- 检查网络连接。
- 建议切换使用 **ComfyUI 合成 TTS** 的工作流(选择前缀为 `tts_` 的工作流),稳定性更高。
#### 2. LLM (大模型) 报错
- **排查步骤**
1. 检查 **Base URL** 是否正确(不要多出空格或错误的后缀)。
2. 检查 **API Key** 是否有效且有余额。
3. 检查 **Model Name** 是否拼写正确。
- *提示:请查阅您所使用的模型服务商(如 OpenAI、DeepSeek、阿里云等)的官方 API 文档获取准确配置。*
#### 3. 错误提示 "Could not find a Chrome executable..."
- **原因**:您的电脑系统中缺少 Chrome 浏览器内核,导致部分依赖浏览器的功能无法运行。
- **解决方案**:请下载并安装 Google Chrome 浏览器。
### 生成的视频保存在哪里?
所有生成的视频自动保存到项目目录的 `output/` 文件夹中。生成完成后,界面会显示视频时长、文件大小、分镜数量及下载链接。
### 有哪些社区资源?
- **GitHub 仓库**https://github.com/AIDC-AI/Pixelle-Video
- **问题反馈**:通过 GitHub Issues 提交 bug 或功能请求
- **社区支持**:加入讨论群组获取帮助和分享经验
- **贡献代码**:项目在 MIT 许可证下欢迎贡献
💡 **提示**:如果在此 FAQ 中找不到您需要的答案,请在 GitHub 提交 issue 或加入社区讨论。我们会根据用户反馈持续更新此 FAQ!
+54
View File
@@ -0,0 +1,54 @@
# Architecture
Technical architecture overview of Pixelle-Video.
---
## Core Architecture
Pixelle-Video uses a layered architecture design:
- **Web Layer**: Streamlit Web interface
- **Service Layer**: Core business logic
- **ComfyUI Layer**: Image and TTS generation
---
## Main Components
### PixelleVideoCore
Core service class coordinating all sub-services.
### LLM Service
Responsible for calling large language models to generate scripts.
### Image Service
Responsible for calling ComfyUI to generate images.
### TTS Service
Responsible for calling ComfyUI to generate speech.
### Video Generator
Responsible for composing the final video.
---
## Tech Stack
- **Backend**: Python 3.10+, AsyncIO
- **Web**: Streamlit
- **AI**: OpenAI API, ComfyUI
- **Configuration**: YAML
- **Tools**: uv (package management)
---
## More Information
Detailed architecture documentation coming soon.
+50
View File
@@ -0,0 +1,50 @@
# Contributing
Thank you for your interest in contributing to Pixelle-Video!
---
## How to Contribute
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
---
## Development Setup
```bash
# Clone your fork
git clone https://github.com/your-username/Pixelle-Video.git
cd Pixelle-Video
# Install development dependencies
uv sync
# Run tests
pytest
```
---
## Code Standards
- All code and comments in English
- Follow PEP 8 standards
- Add appropriate tests
---
## Submit Issues
Having problems or feature suggestions? Please submit at [GitHub Issues](https://github.com/AIDC-AI/Pixelle-Video/issues).
---
## Code of Conduct
Please be friendly and respectful. We are committed to fostering an inclusive community environment.
+87
View File
@@ -0,0 +1,87 @@
# FAQ
Frequently Asked Questions.
---
## Installation
### Q: How to install uv?
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### Q: Can I use something other than uv?
Yes, you can use traditional pip + venv approach.
---
## Configuration
### Q: Do I need to configure ComfyUI?
**Not necessarily** - it depends on your template choice:
| Template Type | ComfyUI | Best For | Speed |
|--------------|---------|----------|-------|
| Text-only<br/>(e.g., `simple.html`) | ❌ Not needed | Quotes, announcements, reading prompts | ⚡⚡⚡ Very fast |
| AI Images<br/>(e.g., `default.html`) | ✅ Required | Rich visual content | ⚡ Standard |
**Tip**: Beginners can start with text-only templates for instant zero-barrier experience!
**Alternative**: If you need AI images but don't want local ComfyUI, use RunningHub cloud service.
### Q: Which LLMs are supported?
All OpenAI-compatible LLMs, including:
- Qianwen
- GPT-4o
- DeepSeek
- Ollama (local)
---
## Usage
### Q: How long does first-time usage take?
Generating a 3-5 scene video takes approximately 2-5 minutes.
### Q: What if I'm not satisfied with the video?
Try:
1. Change LLM model
2. Adjust image dimensions and prompt prefix
3. Change TTS workflow
4. Try different video templates
### Q: What are the costs?
- **Completely Free**: Ollama + Local ComfyUI = $0
- **Recommended**: Qianwen + Local ComfyUI ≈ $0.01-0.05/video
- **Cloud Solution**: OpenAI + RunningHub (higher cost)
---
## Troubleshooting
### Q: ComfyUI connection failed
1. Confirm ComfyUI is running
2. Check if URL is correct
3. Click "Test Connection" in Web interface
### Q: LLM API call failed
1. Check if API Key is correct
2. Check network connection
3. Review error messages
---
## Other Questions
Have other questions? Check [Troubleshooting](troubleshooting.md) or submit an [Issue](https://github.com/AIDC-AI/Pixelle-Video/issues).
+45
View File
@@ -0,0 +1,45 @@
# 🎬 Video Gallery
Showcase of videos created with Pixelle-Video. Click on cards to view complete workflows and configuration files.
---
<div class="grid cards" markdown>
- **Reading Habit**
---
<video controls width="100%" style="border-radius: 8px;">
<source src="https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com/pixelle-video/reading-habit/video.mp4" type="video/mp4">
</video>
[:octicons-mark-github-16: View Workflows & Config](https://github.com/AIDC-AI/Pixelle-Video/tree/main/docs/gallery/reading-habit)
- **Work Efficiency**
---
<video controls width="100%" style="border-radius: 8px;">
<source src="https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com/pixelle-video/work-efficiency/video.mp4" type="video/mp4">
</video>
[:octicons-mark-github-16: View Workflows & Config](https://github.com/AIDC-AI/Pixelle-Video/tree/main/docs/gallery/work-efficiency)
- **Healthy Diet**
---
<video controls width="100%" style="border-radius: 8px;">
<source src="https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com/pixelle-video/healthy-diet/video.mp4" type="video/mp4">
</video>
[:octicons-mark-github-16: View Workflows & Config](https://github.com/AIDC-AI/Pixelle-Video/tree/main/docs/gallery/healthy-diet)
</div>
---
!!! tip "How to Use"
Click on a case card to jump to GitHub, download workflow files and configuration, and reproduce the video effect with one click.
+64
View File
@@ -0,0 +1,64 @@
# Configuration
After installation, you need to configure services to use Pixelle-Video.
---
## LLM Configuration
LLM (Large Language Model) is used to generate video scripts.
### Quick Preset Selection
1. Select a preset model from the dropdown:
- Qianwen (recommended, great value)
- GPT-4o
- DeepSeek
- Ollama (local, completely free)
2. The system will auto-fill `base_url` and `model`
3. Click「🔑 Get API Key」to register and obtain credentials
4. Enter your API Key
---
## Image/Video Generation Configuration
Two options available:
### Local Deployment
Using local ComfyUI service:
1. Install and start ComfyUI
2. Enter ComfyUI URL (default `http://127.0.0.1:8188`)
3. Click "Test Connection" to verify
4. (Optional) Enter ComfyUI API Key (get from [Comfy Platform](https://platform.comfy.org/profile/api-keys))
### Cloud Deployment (Recommended)
Using RunningHub cloud service, no local GPU required:
1. Register for a RunningHub account
2. Obtain API Key
3. Enter API Key in configuration
4. Configure advanced options (optional):
- **Concurrent Limit**: Set number of simultaneous tasks (1-10, default 1 for regular members)
- **Instance Type**: Choose 24GB or 48GB VRAM machine (48GB for large video generation)
---
## Save Configuration
After filling in all required configuration, click the "Save Configuration" button.
Configuration will be saved to `config.yaml` file.
---
## Next Steps
- [Quick Start](quick-start.md) - Create your first video
+134
View File
@@ -0,0 +1,134 @@
# Installation
This page will guide you through installing Pixelle-Video.
---
## System Requirements
### Required
- **Python**: 3.10 or higher
- **Operating System**: Windows, macOS, or Linux
- **Package Manager**: uv (recommended) or pip
### Optional
- **GPU**: NVIDIA GPU with 6GB+ VRAM recommended for local ComfyUI
- **Network**: Stable internet connection for LLM API and image generation services
---
## 🪟 Windows All-in-One Package (Recommended for Windows Users)
**No need to install Python, uv, or ffmpeg - ready to use out of the box!**
### Download and Install
1. Visit [GitHub Releases](https://github.com/AIDC-AI/Pixelle-Video/releases/latest) to download the latest version
2. Download the latest Windows All-in-One Package and extract it to any directory
3. Double-click `start.bat` to launch the Web interface
4. Your browser will automatically open `http://localhost:8501`
!!! success "Installation Complete!"
The package includes all dependencies, no need to manually install any environment. On first use, you only need to configure API keys in "⚙️ System Configuration" to get started.
!!! tip "Next Steps"
After installation, check out the [Configuration Guide](configuration.md) to set up LLM and image generation services, then see [Quick Start](quick-start.md) to create your first video.
---
## Install from Source (For macOS / Linux Users or Users Who Need Customization)
### Step 1: Clone the Repository
```bash
git clone https://github.com/AIDC-AI/Pixelle-Video.git
cd Pixelle-Video
```
### Step 2: Install Dependencies
!!! tip "Recommended: Use uv"
This project uses `uv` as the package manager, which is faster and more reliable than traditional pip.
#### Using uv (Recommended)
```bash
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install project dependencies (uv will create a virtual environment automatically)
uv sync
```
#### Using pip
```bash
# Create virtual environment
python -m venv venv
# Activate virtual environment
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate
# Install dependencies
pip install -e .
```
---
## Verify Installation
Run the following command to verify the installation:
```bash
# Using uv
uv run streamlit run web/app.py
# Or using pip (activate virtual environment first)
streamlit run web/app.py
```
Your browser should automatically open `http://localhost:8501` and display the Pixelle-Video web interface.
!!! success "Installation Successful!"
If you can see the web interface, the installation was successful! Next, check out the [Configuration Guide](configuration.md) to set up your services.
---
## Optional: Install ComfyUI (Local Deployment)
If you want to run image generation locally, you'll need to install ComfyUI:
### Quick Install
```bash
# Clone ComfyUI
git clone https://github.com/comfyanonymous/ComfyUI.git
cd ComfyUI
# Install dependencies
pip install -r requirements.txt
```
### Start ComfyUI
```bash
python main.py
```
ComfyUI runs on `http://127.0.0.1:8188` by default.
!!! info "ComfyUI Models"
ComfyUI requires downloading model files to work. Please refer to the [ComfyUI documentation](https://github.com/comfyanonymous/ComfyUI) for information on downloading and configuring models.
---
## Next Steps
- [Configuration](configuration.md) - Configure LLM and image generation services
- [Quick Start](quick-start.md) - Create your first video
+115
View File
@@ -0,0 +1,115 @@
# Quick Start
Already installed and configured? Let's create your first video!
---
## Start the Web Interface
### Windows All-in-One Package Users
If you're using the Windows All-in-One Package, simply:
1. Double-click `start.bat`
2. Your browser will automatically open `http://localhost:8501`
### Install from Source Users
```bash
# Using uv
uv run streamlit run web/app.py
```
Your browser will automatically open `http://localhost:8501`
---
## Create Your First Video
### Step 1: Check Configuration
On first use, expand the「⚙️ System Configuration」panel and confirm:
- **LLM Configuration**: Select an AI model (e.g., Qianwen, GPT) and enter API Key
- **Image Configuration**: Configure ComfyUI address or RunningHub API Key
If not yet configured, see the [Configuration Guide](configuration.md).
Click "Save Configuration" when done.
---
### Step 2: Enter a Topic
In the left panel's「📝 Content Input」section:
1. Select「**AI Generate Content**」mode
2. Enter a topic in the text box, for example:
```
Why develop a reading habit
```
3. (Optional) Set number of scenes, default is 5 frames
!!! tip "Topic Examples"
- Why develop a reading habit
- How to improve work efficiency
- The importance of healthy eating
- The meaning of travel
---
### Step 3: Configure Voice and Visuals
In the middle panel:
**Voice Settings**
- Select TTS workflow (default Edge-TTS works well)
- For voice cloning, upload a reference audio file
**Visual Settings**
- Select image generation workflow (default works well)
- Set image dimensions (default 1024x1024)
- Choose video template (recommend portrait 1080x1920)
---
### Step 4: Generate Video
Click the「🎬 Generate Video」button in the right panel!
The system will show real-time progress:
- Generate script
- Generate images (for each scene)
- Synthesize voice
- Compose video
!!! info "Generation Time"
Generating a 5-scene video takes about 2-5 minutes, depending on: LLM API response speed, image generation speed, TTS workflow type, and network conditions
---
### Step 5: Preview Video
Once complete, the video will automatically play in the right panel!
You'll see:
- 📹 Video preview player
- ⏱️ Video duration
- 📦 File size
- 🎬 Number of scenes
- 📐 Video dimensions
The video file is saved in the `output/` folder.
---
## Next Steps
Congratulations! You've successfully created your first video 🎉
Next, you can:
- **Adjust Styles** - See the [Custom Visual Style](../tutorials/custom-style.md) tutorial
- **Clone Voices** - See the [Voice Cloning with Reference Audio](../tutorials/voice-cloning.md) tutorial
- **Use API** - See the [API Usage Guide](../user-guide/api.md)
- **Develop Templates** - See the [Template Development Guide](../user-guide/templates.md)
+99
View File
@@ -0,0 +1,99 @@
# Pixelle-Video 🎬
<div align="center" markdown="1">
**AI Video Creator - Generate a short video in 3 minutes**
[![Stars](https://img.shields.io/github/stars/AIDC-AI/Pixelle-Video.svg?style=flat-square)](https://github.com/AIDC-AI/Pixelle-Video/stargazers)
[![Issues](https://img.shields.io/github/issues/AIDC-AI/Pixelle-Video.svg?style=flat-square)](https://github.com/AIDC-AI/Pixelle-Video/issues)
[![License](https://img.shields.io/github/license/AIDC-AI/Pixelle-Video.svg?style=flat-square)](https://github.com/AIDC-AI/Pixelle-Video/blob/main/LICENSE)
</div>
---
## 🎯 Overview
Simply input a **topic**, and Pixelle-Video will automatically:
- ✍️ Write video scripts
- 🎨 Generate AI images
- 🗣️ Synthesize voice narration
- 🎵 Add background music
- 🎬 Create the final video
**No barriers, no video editing experience required** - turn video creation into a one-line task!
---
## ✨ Features
-**Fully Automated** - Input a topic, get a complete video in 3 minutes
-**AI-Powered Scripts** - Intelligently create narration based on your topic
-**AI-Generated Images** - Each sentence comes with beautiful AI illustrations
-**AI Voice Synthesis** - Support for Edge-TTS, Index-TTS and more mainstream TTS solutions
-**Background Music** - Add BGM for enhanced atmosphere
-**Visual Styles** - Multiple templates to create unique video styles
-**Flexible Dimensions** - Support for portrait, landscape and more video sizes
-**Multiple AI Models** - Support for GPT, Qianwen, DeepSeek, Ollama, etc.
-**Flexible Composition** - Based on ComfyUI architecture, use preset workflows or customize any capability
---
## 🎬 Video Examples
!!! info "Sample Videos"
Coming soon: Video examples will be added here
---
## 🚀 Quick Start
Ready to get started? Just three steps:
1. **[Install Pixelle-Video](getting-started/installation.md)** - Download and install the project
- 🪟 **Windows Users (Recommended)**: Use the [All-in-One Package](https://github.com/AIDC-AI/Pixelle-Video/releases/latest), no Python installation required
- 💻 **macOS/Linux Users**: Install from source, see [Installation Guide](getting-started/installation.md)
2. **[Configure Services](getting-started/configuration.md)** - Set up LLM and image generation services
3. **[Create Your First Video](getting-started/quick-start.md)** - Start creating your first video
---
## 💰 Pricing
!!! success "Completely free to run!"
- **Completely Free**: Use Ollama (local) + Local ComfyUI = $0
- **Recommended**: Use Qianwen LLM (≈$0.01-0.05 per 3-scene video) + Local ComfyUI
- **Cloud Solution**: Use OpenAI + RunningHub (higher cost but no local setup required)
**Recommendation**: If you have a local GPU, go with the completely free solution. Otherwise, we recommend Qianwen for best value.
---
## 🤝 Acknowledgments
Pixelle-Video was inspired by the following excellent open source projects:
- [Pixelle-MCP](https://github.com/AIDC-AI/Pixelle-MCP) - ComfyUI MCP server
- [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo) - Excellent video generation tool
- [NarratoAI](https://github.com/linyqh/NarratoAI) - Video narration automation tool
- [MoneyPrinterPlus](https://github.com/ddean2009/MoneyPrinterPlus) - Video creation platform
- [ComfyKit](https://github.com/puke3615/ComfyKit) - ComfyUI workflow wrapper library
Thanks to these projects for their open source spirit! 🙏
---
## 📢 Feedback & Support
- 🐛 **Found a bug**: Submit an [Issue](https://github.com/AIDC-AI/Pixelle-Video/issues)
- 💡 **Feature request**: Submit a [Feature Request](https://github.com/AIDC-AI/Pixelle-Video/issues)
-**Give us a Star**: If this project helps you, please give us a star!
---
## 📝 License
This project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/AIDC-AI/Pixelle-Video/blob/main/LICENSE) file for details.
+141
View File
@@ -0,0 +1,141 @@
# API Overview
Pixelle-Video provides both Python SDK and HTTP REST API.
---
## Python SDK
### PixelleVideoCore
Main service class providing video generation functionality.
```python
from pixelle_video.service import PixelleVideoCore
pixelle = PixelleVideoCore()
await pixelle.initialize()
```
### generate_video()
Primary method for generating videos.
**Parameters**:
- `text` (str): Topic or complete script
- `mode` (str): Generation mode ("generate" or "fixed")
- `n_scenes` (int): Number of scenes
- `title` (str, optional): Video title
- `tts_workflow` (str): TTS workflow
- `media_workflow` (str): Media generation workflow (image or video)
- `frame_template` (str): Video template
- `template_params` (dict, optional): Custom template parameters
- `bgm_path` (str, optional): BGM file path
- `bgm_volume` (float): BGM volume (0.0-1.0)
**Returns**: `VideoResult` object
---
## HTTP REST API
Start the API server:
```bash
uv run uvicorn api.app:app --host 0.0.0.0 --port 8000
```
### Video Generation - Synchronous
`POST /api/video/generate/sync`
Generate video synchronously, waits until completion. Suitable for small videos (< 30 seconds).
**Request Body**:
```json
{
"text": "Why you should develop a reading habit",
"mode": "generate",
"n_scenes": 5,
"frame_template": "1080x1920/image_default.html",
"template_params": {
"accent_color": "#3498db",
"background": "https://example.com/custom-bg.jpg"
},
"title": "The Power of Reading"
}
```
**Response**:
```json
{
"success": true,
"message": "Success",
"video_url": "http://localhost:8000/api/files/xxx/final.mp4",
"duration": 45.5,
"file_size": 12345678
}
```
### Video Generation - Asynchronous
`POST /api/video/generate/async`
Generate video asynchronously, returns task ID immediately. Suitable for large videos.
**Response**:
```json
{
"success": true,
"message": "Task created successfully",
"task_id": "abc123"
}
```
### Query Task Status
`GET /api/tasks/{task_id}`
**Response**:
```json
{
"task_id": "abc123",
"status": "completed",
"result": {
"video_url": "http://localhost:8000/api/files/xxx/final.mp4",
"duration": 45.5,
"file_size": 12345678
}
}
```
---
## Request Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `text` | string | Yes | Topic or complete script |
| `mode` | string | No | `"generate"` (AI generates) or `"fixed"` (use text as-is) |
| `n_scenes` | int | No | Number of scenes (1-20), only used in generate mode |
| `title` | string | No | Video title (auto-generated if not provided) |
| `frame_template` | string | No | Template path, e.g., `1080x1920/image_default.html` |
| `template_params` | object | No | Custom template parameters (colors, backgrounds, etc.) |
| `media_workflow` | string | No | Media workflow (image or video generation) |
| `tts_workflow` | string | No | TTS workflow |
| `ref_audio` | string | No | Reference audio path for voice cloning |
| `prompt_prefix` | string | No | Image style prefix |
| `bgm_path` | string | No | BGM file path |
| `bgm_volume` | float | No | BGM volume (0.0-1.0, default 0.3) |
---
## More Information
API documentation is also available via Swagger UI: `http://localhost:8000/docs`
+89
View File
@@ -0,0 +1,89 @@
# Config Schema
Detailed explanation of the `config.yaml` configuration file.
---
## Configuration Structure
```yaml
llm:
api_key: "your-api-key"
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
model: "qwen-plus"
comfyui:
comfyui_url: "http://127.0.0.1:8188"
comfyui_api_key: "" # ComfyUI API key (optional)
runninghub_api_key: ""
runninghub_concurrent_limit: 1 # Concurrent limit (1-10)
runninghub_instance_type: "" # Instance type (optional, set to "plus" for 48GB VRAM)
image:
default_workflow: "runninghub/image_flux.json"
prompt_prefix: "Minimalist illustration style"
video:
default_workflow: "runninghub/video_wan2.1_fusionx.json"
prompt_prefix: "Minimalist illustration style"
tts:
default_workflow: "selfhost/tts_edge.json"
template:
default_template: "1080x1920/image_default.html"
```
---
## LLM Configuration
- `api_key`: API key
- `base_url`: API service address (supports any OpenAI-compatible interface)
- `model`: Model name
---
## ComfyUI Configuration
### Basic Configuration
- `comfyui_url`: Local ComfyUI address (default `http://127.0.0.1:8188`)
- `comfyui_api_key`: ComfyUI API key (optional, for [Comfy Platform](https://platform.comfy.org/profile/api-keys))
### RunningHub Cloud Configuration
- `runninghub_api_key`: RunningHub API key (required for cloud workflows)
- `runninghub_concurrent_limit`: Concurrent execution limit (1-10, default 1 for regular members)
- `runninghub_instance_type`: Instance type (optional)
- Empty or unset: Use 24GB VRAM machine
- `"plus"`: Use 48GB VRAM machine (suitable for large video generation)
### Image Configuration
- `default_workflow`: Default image generation workflow
- `prompt_prefix`: Prompt prefix
### Video Configuration
- `default_workflow`: Default video generation workflow
- `runninghub/video_wan2.1_fusionx.json`: Cloud workflow (recommended, no local setup required)
- `selfhost/video_wan2.1_fusionx.json`: Local workflow (requires local ComfyUI support)
- `prompt_prefix`: Video prompt prefix (controls video generation style)
### TTS Configuration
- `default_workflow`: Default TTS workflow
---
## Template Configuration
- `default_template`: Default frame template path (e.g., `1080x1920/image_default.html`)
---
## More Information
The configuration file is automatically created on first run.
+108
View File
@@ -0,0 +1,108 @@
# Troubleshooting
Having issues? Here are solutions to common problems.
---
## Installation Issues
### Dependency installation failed
```bash
# Clean cache
uv cache clean
# Reinstall
uv sync
```
---
## Configuration Issues
### ComfyUI connection failed
**Possible Causes**:
- ComfyUI not running
- Incorrect URL configuration
- Firewall blocking
**Solutions**:
1. Confirm ComfyUI is running
2. Check URL configuration (default `http://127.0.0.1:8188`)
3. Test by accessing ComfyUI address in browser
4. Check firewall settings
### LLM API call failed
**Possible Causes**:
- Incorrect API Key
- Network issues
- Insufficient balance
**Solutions**:
1. Verify API Key is correct
2. Check network connection
3. Review error message details
4. Check account balance
---
## Generation Issues
### Video generation failed
**Possible Causes**:
- Corrupted workflow file
- Models not downloaded
- Insufficient resources
**Solutions**:
1. Check if workflow file exists
2. Confirm ComfyUI has downloaded required models
3. Check disk space and memory
### Image generation failed
**Solutions**:
1. Check if ComfyUI is running properly
2. Try manually testing workflow in ComfyUI
3. Check workflow configuration
### TTS generation failed
**Solutions**:
1. Check if TTS workflow is correct
2. If using voice cloning, check reference audio format
3. Review error logs
---
## Performance Issues
### Slow generation speed
**Optimization Tips**:
1. Use local ComfyUI (faster than cloud)
2. Reduce number of scenes
3. Use faster LLM (e.g., Qianwen)
4. Check network connection
---
## Other Issues
Still having problems?
1. Check project [GitHub Issues](https://github.com/AIDC-AI/Pixelle-Video/issues)
2. Submit a new Issue describing your problem
3. Include error logs and configuration details for quick diagnosis
---
## View Logs
Log files are located in project root:
- `api_server.log` - API service logs
- `test_output.log` - Test logs
+36
View File
@@ -0,0 +1,36 @@
# Custom Visual Style
Learn how to adjust image generation parameters to create unique visual styles.
---
## Adjust Prompt Prefix
The prompt prefix controls overall visual style:
```
Minimalist black-and-white illustration, clean lines, simple style
```
---
## Adjust Image Dimensions
Different dimensions for different scenarios:
- **1024x1024**: Square, suitable for Xiaohongshu
- **1080x1920**: Portrait, suitable for TikTok, Kuaishou
- **1920x1080**: Landscape, suitable for Bilibili, YouTube
---
## Preview Effects
Use the "Preview Style" feature to test different configurations.
---
## More Information
More style customization tips coming soon.
+35
View File
@@ -0,0 +1,35 @@
# Voice Cloning
Use reference audio to implement voice cloning functionality.
---
## Prepare Reference Audio
1. Prepare a clear audio file (MP3/WAV/FLAC)
2. Recommended duration: 10-30 seconds
3. Avoid background noise
---
## Usage Steps
1. Select a TTS workflow that supports voice cloning (e.g., Index-TTS) in voice settings
2. Upload reference audio file
3. Test effects with "Preview Voice"
4. Generate video
---
## Notes
- Not all TTS workflows support voice cloning
- Reference audio quality affects cloning results
- Edge-TTS does not support voice cloning
---
## More Information
Detailed voice cloning tutorial coming soon.
+33
View File
@@ -0,0 +1,33 @@
# Your First Video
Step-by-step guide to creating your first video with Pixelle-Video.
---
## Prerequisites
Make sure you've completed:
- ✅ [Installation](../getting-started/installation.md)
- ✅ [Configuration](../getting-started/configuration.md)
---
## Tutorial Steps
For detailed steps, see [Quick Start](../getting-started/quick-start.md).
---
## Tips
- Choose an appropriate topic for better results
- Start with 3-5 scenes for first generation
- Preview voice and image effects before generating
---
## Troubleshooting
Having issues? Check out [FAQ](../faq.md) or [Troubleshooting](../troubleshooting.md).
+42
View File
@@ -0,0 +1,42 @@
# API Usage
Pixelle-Video provides a complete Python API for easy integration into your projects.
---
## Quick Start
```python
from pixelle_video.service import PixelleVideoCore
import asyncio
async def main():
# Initialize
pixelle = PixelleVideoCore()
await pixelle.initialize()
# Generate video
result = await pixelle.generate_video(
text="Why develop a reading habit",
mode="generate",
n_scenes=5
)
print(f"Video generated: {result.video_path}")
# Run
asyncio.run(main())
```
---
## API Reference
For detailed API documentation, see [API Overview](../reference/api-overview.md).
---
## Examples
For more usage examples, check the `examples/` directory in the project.
+410
View File
@@ -0,0 +1,410 @@
# Template Development
How to create custom video templates.
---
## Template Introduction
Video templates use HTML to define the layout and style of video frames. Pixelle-Video provides multiple preset templates covering different video dimensions and style requirements.
---
## Built-in Template Preview
### Portrait Templates (1080x1920)
Suitable for TikTok, Kuaishou, Xiaohongshu, and other short video platforms.
<div class="grid cards" markdown>
- **static_default**
---
![static_default](../../images/1080x1920/static_default_en.jpg)
Default static template
- **static_excerpt**
---
![static_excerpt](../../images/1080x1920/static_excerpt_en.jpg)
Text excerpt static template
- **Blur Card**
---
![blur_card](../../images/1080x1920/image_blur_card_en.jpg)
Blurred background card style, suitable for graphic content display
- **Cartoon**
---
![cartoon](../../images/1080x1920/image_cartoon_en.jpg)
Cartoon style, suitable for light and lively content
- **Default**
---
![default](../../images/1080x1920/image_default_en.jpg)
Default template, simple and versatile
- **Elegant**
---
![elegant](../../images/1080x1920/image_elegant_en.jpg)
Elegant style, suitable for artistic and intellectual content
- **Fashion Vintage**
---
![fashion_vintage](../../images/1080x1920/image_fashion_vintage_en.jpg)
Retro fashion style, suitable for nostalgic themes
- **Life Insights**
---
![life_insights](../../images/1080x1920/image_life_insights_en.jpg)
Life insight style, suitable for inspirational content
- **Modern**
---
![modern](../../images/1080x1920/image_modern_en.jpg)
Modern minimalist style, suitable for business and tech content
- **Neon**
---
![neon](../../images/1080x1920/image_neon_en.jpg)
Neon style, suitable for fashion and trendy content
- **Psychology Card**
---
![psychology_card](../../images/1080x1920/image_psychology_card_en.jpg)
Psychology card style, suitable for knowledge popularization
- **Purple**
---
![purple](../../images/1080x1920/image_purple_en.jpg)
Purple theme, suitable for dreamy and mysterious styles
- **Satirical Cartoon**
---
![satirical_cartoon](../../images/1080x1920/image_satirical_cartoon_en.jpg)
80s satirical cartoon style for spiritual tales
- **Simple Black Background**
---
![simple_black](../../images/1080x1920/image_simple_black_en.jpg)
Simple black background, suitable for inspirational content
- **Simple Line Drawing**
---
![simple_line_drawing](../../images/1080x1920/image_simple_line_drawing_en.jpg)
Simple line drawing style for cognitive growth content
- **Book**
---
![book](../../images/1080x1920/image_book_en.jpg)
Book style, suitable for book lists
- **Long Text**
---
![long_text](../../images/1080x1920/image_long_text_en.jpg)
Long text style, suitable for inspirational content
- **Excerpt**
---
![excerpt](../../images/1080x1920/image_excerpt_en.jpg)
Excerpt style, suitable for quotes and book excerpts
- **Health Preservation**
---
![health_preservation](../../images/1080x1920/image_health_preservation_en.jpg)
Health preserving tips, suitable for wellness explainers.
- **Life Insights**
---
![life_insights_light](../../images/1080x1920/image_life_insights_light_en.jpg)
Life insights, conveying warmth and strength
- **Full**
---
![full](../../images/1080x1920/image_full_en.jpg)
Full screen display, suitable for book lists
- **Healing**
---
![healing](../../images/1080x1920/image_healing_en.jpg)
Healing style, suitable for therapeutic content
- **Video_Default**
---
![video_default](../../images/1080x1920/video_default.jpg)
Default dynamic template
- **Video_Healing**
---
![video_healing](../../images/1080x1920/video_healing.jpg)
Healing dynamic template
</div>
---
### Landscape Templates (1920x1080)
Suitable for YouTube, Bilibili, and other video platforms.
<div class="grid cards" markdown>
- **Ultrawide Minimal**
---
![ultrawide_minimal](../../images/1920x1080/image_ultrawide_minimal_en.jpg)
Ultrawide minimalist style, suitable for desktop viewing
- **Wide Darktech**
---
![wide_darktech](../../images/1920x1080/image_wide_darktech_en.jpg)
Dark tech style, suitable for technology and gaming content
- **Film**
---
![film](../../images/1920x1080/image_film_en.jpg)
Film style, immersive experience
- **Full**
---
![full](../../images/1920x1080/image_full_en.jpg)
Full screen display, suitable for book lists
- **Book**
---
![book](../../images/1920x1080/image_book_en.jpg)
Book style, suitable for book lists
</div>
---
### Square Templates (1080x1080)
Suitable for Instagram, WeChat Moments, and other platforms.
<div class="grid cards" markdown>
- **Minimal Framed**
---
![minimal_framed](../../images/1080x1080/image_minimal_framed_en.jpg)
Minimalist framed style, suitable for social media sharing
</div>
---
## Template Naming Convention
Templates follow a unified naming convention to distinguish different types:
- **`static_*.html`**: Static templates
- No AI-generated media content required
- Pure text style rendering
- Suitable for quick generation and low-cost scenarios
- **`image_*.html`**: Image templates
- Uses AI-generated images as background
- Invokes ComfyUI image generation workflows
- Suitable for content requiring visual illustrations
- **`video_*.html`**: Video templates
- Uses AI-generated videos as background
- Invokes ComfyUI video generation workflows
- Creates dynamic video content with enhanced expressiveness
## Template Structure
Templates are located in the `templates/` directory, grouped by size:
```
templates/
├── 1080x1920/ # Portrait
│ ├── static_*.html # Static templates
│ ├── image_*.html # Image templates
│ └── video_*.html # Video templates
├── 1920x1080/ # Landscape
│ └── image_*.html # Image templates
└── 1080x1080/ # Square
└── image_*.html # Image templates
```
---
## Creating Custom Templates
### Steps
1. Copy an existing template file from the `templates/` directory
2. Modify HTML and CSS styles
3. Save to the corresponding size directory with `.html` extension
4. Use the new template name in configuration or Web interface
### Template Variables
Templates support the following Jinja2 variables:
- `{{ title }}` - Video title (optional)
- `{{ text }}` - Current scene text content
- `{{ image }}` - Current scene image (if any)
### Example Template
```html
<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 1080px;
height: 1920px;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
font-family: 'Arial', sans-serif;
}
.content {
text-align: center;
color: white;
padding: 40px;
}
.text {
font-size: 48px;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="content">
<div class="text">{{ text }}</div>
</div>
</body>
</html>
```
---
## Template Development Tips
### 1. Responsive Sizing
Ensure the template's `body` size matches the target video dimensions:
- Portrait: `width: 1080px; height: 1920px;`
- Landscape: `width: 1920px; height: 1080px;`
- Square: `width: 1080px; height: 1080px;`
### 2. Text Typography
- Use appropriate font sizes and line heights for readability
- Add shadows or backgrounds to text for better contrast
- Control text length to avoid overflow
### 3. Image Handling
- Use `object-fit: cover` to ensure image filling
- Add gradients or overlay layers to improve text readability
- Consider fallback solutions for image loading failures
### 4. Performance Optimization
- Avoid overly complex CSS animations
- Optimize background image sizes
- Use system fonts or web-safe fonts
---
## More Information
For template development questions, feel free to ask in [GitHub Issues](https://github.com/AIDC-AI/Pixelle-Video/issues).
+98
View File
@@ -0,0 +1,98 @@
# Web UI Guide
Detailed introduction to the Pixelle-Video Web interface features.
---
## Interface Layout
The Web interface uses a three-column layout:
- **Left Panel**: Content input and audio settings
- **Middle Panel**: Voice and visual settings
- **Right Panel**: Video generation and preview
- **Sidebar**: System configuration and FAQ
---
## System Configuration
First-time use requires configuring LLM and image generation services. See [Configuration Guide](../getting-started/configuration.md).
---
## Content Input
### Generation Mode
- **AI Generate Content**: Enter a topic, AI creates script automatically
- **Fixed Script Content**: Enter complete script directly
### Fixed Script Split Mode
When using fixed script mode, you can choose how to split the content:
- **By Paragraph**: Split by empty lines, each paragraph becomes a scene
- **By Line**: Split by line breaks, each line becomes a scene
- **By Sentence**: Smart sentence boundary detection, each sentence becomes a scene
### Background Music
- Built-in music supported
- Custom music files supported
---
## Voice Settings
### TTS Workflow
- Select TTS workflow
- Supports Edge-TTS, Index-TTS, etc.
### Reference Audio
- Upload reference audio for voice cloning
- Supports MP3/WAV/FLAC formats
---
## Visual Settings
### Image/Video Generation
- Select media generation workflow (image or video)
- Adjust prompt prefix to control style
### Video Template
- **Template Preview Gallery**: Visually preview all available templates
- Supports portrait (1080x1920) / landscape (1920x1080) / square (1080x1080)
- Template types:
- `static_*.html`: Static templates (no AI-generated media)
- `image_*.html`: Image templates (requires AI-generated images)
- `video_*.html`: Video templates (requires AI-generated videos)
---
## Generate Video
After clicking "Generate Video", the system will:
1. Generate video script
2. Generate images/videos for each scene
3. Synthesize voice narration
4. Compose final video
Automatically previews when complete.
---
## FAQ
The sidebar includes built-in FAQ for quick reference:
- Common configuration issues
- Generation failure solutions
- Performance optimization tips
+69
View File
@@ -0,0 +1,69 @@
# Workflow Customization
How to customize ComfyUI workflows to achieve specific functionality.
---
## Workflow Introduction
Pixelle-Video is built on the ComfyUI architecture and supports custom workflows.
---
## Workflow Types
### TTS Workflows
Located in `workflows/selfhost/` or `workflows/runninghub/`
Used for Text-to-Speech, supporting various TTS engines:
- Edge-TTS
- Index-TTS (supports voice cloning)
- Other ComfyUI-compatible TTS nodes
### Image Generation Workflows
Located in `workflows/selfhost/` or `workflows/runninghub/`
Used for generating static images as video backgrounds:
- FLUX series models
- Stable Diffusion series models
- Other image generation models
### Video Generation Workflows
Located in `workflows/selfhost/` or `workflows/runninghub/`
**New Feature**: Supports AI video generation to create dynamic video content.
**Preset Workflows**:
- `runninghub/video_wan2.1_fusionx.json`: Cloud workflow (recommended)
- Based on WAN 2.1 model
- No local setup required, accessed via RunningHub API
- Supports Text-to-Video generation
- `selfhost/video_wan2.1_fusionx.json`: Local workflow
- Requires local ComfyUI environment
- Requires installation of corresponding video generation nodes
- Suitable for users with local GPU
**Use Cases**:
- Works with `video_*.html` templates
- Automatically generates dynamic video backgrounds based on scripts
- Enhances visual expressiveness and viewing experience
---
## Custom Workflows
1. Design your workflow in ComfyUI
2. Export as JSON file
3. Place in `workflows/` directory
4. Select and use in Web interface
---
## More Information
Detailed workflow customization guide coming soon.
+78
View File
@@ -0,0 +1,78 @@
# 🎬 视频示例库 / Video Gallery
展示使用 Pixelle-Video 制作的各类视频案例,包含完整的制作参数和资源下载。
Showcase of videos created with Pixelle-Video, including complete production parameters and downloadable resources.
---
## 📚 案例列表 / Cases
<div class="grid cards" markdown>
- :material-book-open-variant:{ .lg .middle } **阅读习惯养成**
---
![视频缩略图](https://via.placeholder.com/400x225?text=Reading+Habit)
**时长 Duration**: 45s | **分镜 Scenes**: 5 | **尺寸 Size**: 1080x1920
一个关于为什么要养成阅读习惯的教育科普视频。
An educational video about why we should develop reading habits.
[:octicons-arrow-right-24: 查看详情 View Details](reading-habit/)
- :material-chart-line:{ .lg .middle } **提高工作效率**
---
![视频缩略图](https://via.placeholder.com/400x225?text=Work+Efficiency)
**时长 Duration**: 30s | **分镜 Scenes**: 3 | **尺寸 Size**: 1920x1080
关于如何提高工作效率的实用技巧分享。
Practical tips on improving work efficiency.
[:octicons-arrow-right-24: 查看详情 View Details](#) *(即将推出 Coming soon)*
- :material-food-apple:{ .lg .middle } **健康饮食**
---
![视频缩略图](https://via.placeholder.com/400x225?text=Healthy+Diet)
**时长 Duration**: 60s | **分镜 Scenes**: 6 | **尺寸 Size**: 1080x1080
健康饮食的重要性和实用建议。
The importance of healthy eating and practical advice.
[:octicons-arrow-right-24: 查看详情 View Details](#) *(即将推出 Coming soon)*
</div>
---
## 🎯 如何使用这些案例 / How to Use
每个案例都包含:/ Each case includes:
- **📹 成品视频 Video**: OSS 托管的完整视频 / Complete video hosted on OSS
- **⚙️ 工作流文件 Workflows**: ComfyUI 工作流 JSON / ComfyUI workflow JSON files
- **📝 配置文件 Config**: 完整的生成配置 / Complete generation configuration
- **🎨 提示词 Prompts**: 所有使用的提示词 / All prompts used
- **📥 一键复现 Reproduce**: 可直接导入使用 / Can be imported directly
---
## 💡 贡献你的案例 / Contribute Your Case
制作了优秀的视频?欢迎分享!/ Created an awesome video? Share it with us!
查看 [贡献指南](../en/development/contributing.md) 了解如何提交你的案例。
See [Contributing Guide](../en/development/contributing.md) to learn how to submit your case.
+1
View File
@@ -0,0 +1 @@
为什么要养成阅读习惯
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Some files were not shown because too many files have changed in this diff Show More