diff --git a/README.md b/README.md index f5fa33f..1ed06a4 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@
-

ReelForge 🎬

+

Pixelle-Video 🎬

- Stargazers - Issues - Forks - License + Stargazers + Issues + Forks + License


@@ -14,7 +14,7 @@
-只需输入一个 **主题**,ReelForge 就能自动完成: +只需输入一个 **主题**,Pixelle-Video 就能自动完成: - ✍️ 撰写视频文案 - 🎨 生成 AI 配图 - 🗣️ 合成语音解说 @@ -54,8 +54,8 @@ ### 第一步:下载项目 ```bash -git clone https://github.com/JarvisAIHub/ReelForge.git -cd ReelForge +git clone https://github.com/PixelleLab/Pixelle-Video.git +cd Pixelle-Video ``` ### 第二步:启动 Web 界面 @@ -207,7 +207,7 @@ A: **本项目完全支持免费运行!** ## 🤝 参考项目 -ReelForge 的设计受到以下优秀开源项目的启发: +Pixelle-Video 的设计受到以下优秀开源项目的启发: - [Pixelle-MCP](https://github.com/AIDC-AI/Pixelle-MCP) - ComfyUI MCP 服务器,让 AI 助手直接调用 ComfyUI - [MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo) - 优秀的视频生成工具 @@ -221,8 +221,8 @@ ReelForge 的设计受到以下优秀开源项目的启发: ## 📢 反馈与支持 -- 🐛 **遇到问题**: 提交 [Issue](https://github.com/JarvisAIHub/ReelForge/issues) -- 💡 **功能建议**: 提交 [Feature Request](https://github.com/JarvisAIHub/ReelForge/issues) +- 🐛 **遇到问题**: 提交 [Issue](https://github.com/PixelleLab/Pixelle-Video/issues) +- 💡 **功能建议**: 提交 [Feature Request](https://github.com/PixelleLab/Pixelle-Video/issues) - ⭐ **给个 Star**: 如果这个项目对你有帮助,欢迎给个 Star 支持一下! --- @@ -235,12 +235,12 @@ ReelForge 的设计受到以下优秀开源项目的启发: ## ⭐ Star History -[![Star History Chart](https://api.star-history.com/svg?repos=JarvisAIHub/ReelForge&type=Date)](https://star-history.com/#JarvisAIHub/ReelForge&Date) +[![Star History Chart](https://api.star-history.com/svg?repos=PixelleLab/Pixelle-Video&type=Date)](https://star-history.com/#PixelleLab/Pixelle-Video&Date) ---
-

Made with ❤️ by JarvisAIHub

+

Made with ❤️ by PixelleLab

回到顶部 ⬆️

diff --git a/api/__init__.py b/api/__init__.py index 606ac21..bee1cdf 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -1,5 +1,5 @@ """ -ReelForge API Layer +Pixelle-Video API Layer FastAPI-based REST API for video generation services. """ diff --git a/api/app.py b/api/app.py index 950ce86..d4965e2 100644 --- a/api/app.py +++ b/api/app.py @@ -1,5 +1,5 @@ """ -ReelForge FastAPI Application +Pixelle-Video FastAPI Application Main FastAPI app with all routers and middleware. @@ -18,7 +18,7 @@ from loguru import logger from api.config import api_config from api.tasks import task_manager -from api.dependencies import shutdown_reelforge +from api.dependencies import shutdown_pixelle_video # Import routers from api.routers import ( @@ -41,24 +41,24 @@ async def lifespan(app: FastAPI): Handles startup and shutdown events. """ # Startup - logger.info("🚀 Starting ReelForge API...") + logger.info("🚀 Starting Pixelle-Video API...") await task_manager.start() - logger.info("✅ ReelForge API started successfully\n") + logger.info("✅ Pixelle-Video API started successfully\n") yield # Shutdown - logger.info("🛑 Shutting down ReelForge API...") + logger.info("🛑 Shutting down Pixelle-Video API...") await task_manager.stop() - await shutdown_reelforge() - logger.info("✅ ReelForge API shutdown complete") + await shutdown_pixelle_video() + logger.info("✅ Pixelle-Video API shutdown complete") # Create FastAPI app app = FastAPI( - title="ReelForge API", + title="Pixelle-Video API", description=""" - ## ReelForge - AI Video Generation Platform API + ## Pixelle-Video - AI Video Generation Platform API ### Features - 🤖 **LLM**: Large language model integration @@ -113,7 +113,7 @@ app.include_router(files_router, prefix=api_config.api_prefix) async def root(): """Root endpoint with API information""" return { - "service": "ReelForge API", + "service": "Pixelle-Video API", "version": "0.1.0", "docs": api_config.docs_url, "health": "/health", @@ -132,7 +132,7 @@ if __name__ == "__main__": import uvicorn # Parse command line arguments - parser = argparse.ArgumentParser(description="Start ReelForge API Server") + 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") @@ -142,7 +142,7 @@ if __name__ == "__main__": # Print startup banner print(f""" ╔══════════════════════════════════════════════════════════════╗ -║ ReelForge API Server ║ +║ Pixelle-Video API Server ║ ╚══════════════════════════════════════════════════════════════╝ Starting server at http://{args.host}:{args.port} diff --git a/api/dependencies.py b/api/dependencies.py index 1be6358..3976849 100644 --- a/api/dependencies.py +++ b/api/dependencies.py @@ -1,45 +1,45 @@ """ FastAPI Dependencies -Provides dependency injection for ReelForgeCore and other services. +Provides dependency injection for PixelleVideoCore and other services. """ from typing import Annotated from fastapi import Depends from loguru import logger -from reelforge.service import ReelForgeCore +from pixelle_video.service import PixelleVideoCore -# Global ReelForge instance -_reelforge_instance: ReelForgeCore = None +# Global Pixelle-Video instance +_pixelle_video_instance: PixelleVideoCore = None -async def get_reelforge() -> ReelForgeCore: +async def get_pixelle_video() -> PixelleVideoCore: """ - Get ReelForge core instance (dependency injection) + Get Pixelle-Video core instance (dependency injection) Returns: - ReelForgeCore instance + PixelleVideoCore instance """ - global _reelforge_instance + global _pixelle_video_instance - if _reelforge_instance is None: - _reelforge_instance = ReelForgeCore() - await _reelforge_instance.initialize() - logger.info("✅ ReelForge initialized for API") + if _pixelle_video_instance is None: + _pixelle_video_instance = PixelleVideoCore() + await _pixelle_video_instance.initialize() + logger.info("✅ Pixelle-Video initialized for API") - return _reelforge_instance + return _pixelle_video_instance -async def shutdown_reelforge(): - """Shutdown ReelForge instance""" - global _reelforge_instance - if _reelforge_instance: - logger.info("Shutting down ReelForge...") - _reelforge_instance = None +async def shutdown_pixelle_video(): + """Shutdown Pixelle-Video instance""" + global _pixelle_video_instance + if _pixelle_video_instance: + logger.info("Shutting down Pixelle-Video...") + _pixelle_video_instance = None # Type alias for dependency injection -ReelForgeDep = Annotated[ReelForgeCore, Depends(get_reelforge)] +PixelleVideoDep = Annotated[PixelleVideoCore, Depends(get_pixelle_video)] diff --git a/api/routers/content.py b/api/routers/content.py index 27d4aba..ba2c28e 100644 --- a/api/routers/content.py +++ b/api/routers/content.py @@ -7,7 +7,7 @@ Endpoints for generating narrations, image prompts, and titles. from fastapi import APIRouter, HTTPException from loguru import logger -from api.dependencies import ReelForgeDep +from api.dependencies import PixelleVideoDep from api.schemas.content import ( NarrationGenerateRequest, NarrationGenerateResponse, @@ -23,7 +23,7 @@ router = APIRouter(prefix="/content", tags=["Content Generation"]) @router.post("/narration", response_model=NarrationGenerateResponse) async def generate_narration( request: NarrationGenerateRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ Generate narrations from text @@ -41,7 +41,7 @@ async def generate_narration( logger.info(f"Generating {request.n_scenes} narrations from text") # Call narration generator service - narrations = await reelforge.narration_generator( + narrations = await pixelle_video.narration_generator( text=request.text, n_scenes=request.n_scenes, min_words=request.min_words, @@ -60,7 +60,7 @@ async def generate_narration( @router.post("/image-prompt", response_model=ImagePromptGenerateResponse) async def generate_image_prompt( request: ImagePromptGenerateRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ Generate image prompts from narrations @@ -77,7 +77,7 @@ async def generate_image_prompt( logger.info(f"Generating image prompts for {len(request.narrations)} narrations") # Call image prompt generator service - image_prompts = await reelforge.image_prompt_generator( + image_prompts = await pixelle_video.image_prompt_generator( narrations=request.narrations, min_words=request.min_words, max_words=request.max_words @@ -95,7 +95,7 @@ async def generate_image_prompt( @router.post("/title", response_model=TitleGenerateResponse) async def generate_title( request: TitleGenerateRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ Generate video title from text @@ -111,7 +111,7 @@ async def generate_title( logger.info("Generating title from text") # Call title generator service - title = await reelforge.title_generator( + title = await pixelle_video.title_generator( text=request.text ) diff --git a/api/routers/health.py b/api/routers/health.py index 1a36df9..b215300 100644 --- a/api/routers/health.py +++ b/api/routers/health.py @@ -12,7 +12,7 @@ class HealthResponse(BaseModel): """Health check response""" status: str = "healthy" version: str = "0.1.0" - service: str = "ReelForge API" + service: str = "Pixelle-Video API" class CapabilitiesResponse(BaseModel): diff --git a/api/routers/image.py b/api/routers/image.py index fa1ed27..7912f2b 100644 --- a/api/routers/image.py +++ b/api/routers/image.py @@ -5,7 +5,7 @@ Image generation endpoints from fastapi import APIRouter, HTTPException from loguru import logger -from api.dependencies import ReelForgeDep +from api.dependencies import PixelleVideoDep from api.schemas.image import ImageGenerateRequest, ImageGenerateResponse router = APIRouter(prefix="/image", tags=["Image"]) @@ -14,7 +14,7 @@ router = APIRouter(prefix="/image", tags=["Image"]) @router.post("/generate", response_model=ImageGenerateResponse) async def image_generate( request: ImageGenerateRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ Image generation endpoint @@ -32,7 +32,7 @@ async def image_generate( logger.info(f"Image generation request: {request.prompt[:50]}...") # Call image service - image_path = await reelforge.image( + image_path = await pixelle_video.image( prompt=request.prompt, width=request.width, height=request.height, diff --git a/api/routers/llm.py b/api/routers/llm.py index 8a2535d..b9986a7 100644 --- a/api/routers/llm.py +++ b/api/routers/llm.py @@ -5,7 +5,7 @@ LLM (Large Language Model) endpoints from fastapi import APIRouter, HTTPException from loguru import logger -from api.dependencies import ReelForgeDep +from api.dependencies import PixelleVideoDep from api.schemas.llm import LLMChatRequest, LLMChatResponse router = APIRouter(prefix="/llm", tags=["LLM"]) @@ -14,7 +14,7 @@ router = APIRouter(prefix="/llm", tags=["LLM"]) @router.post("/chat", response_model=LLMChatResponse) async def llm_chat( request: LLMChatRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ LLM chat endpoint @@ -31,7 +31,7 @@ async def llm_chat( logger.info(f"LLM chat request: {request.prompt[:50]}...") # Call LLM service - response = await reelforge.llm( + response = await pixelle_video.llm( prompt=request.prompt, temperature=request.temperature, max_tokens=request.max_tokens diff --git a/api/routers/tts.py b/api/routers/tts.py index 4ad747e..af63225 100644 --- a/api/routers/tts.py +++ b/api/routers/tts.py @@ -5,9 +5,9 @@ TTS (Text-to-Speech) endpoints from fastapi import APIRouter, HTTPException from loguru import logger -from api.dependencies import ReelForgeDep +from api.dependencies import PixelleVideoDep from api.schemas.tts import TTSSynthesizeRequest, TTSSynthesizeResponse -from reelforge.utils.tts_util import get_audio_duration +from pixelle_video.utils.tts_util import get_audio_duration router = APIRouter(prefix="/tts", tags=["TTS"]) @@ -15,7 +15,7 @@ router = APIRouter(prefix="/tts", tags=["TTS"]) @router.post("/synthesize", response_model=TTSSynthesizeResponse) async def tts_synthesize( request: TTSSynthesizeRequest, - reelforge: ReelForgeDep + pixelle_video: PixelleVideoDep ): """ Text-to-Speech synthesis endpoint @@ -31,7 +31,7 @@ async def tts_synthesize( logger.info(f"TTS synthesis request: {request.text[:50]}...") # Call TTS service - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text=request.text, voice_id=request.voice_id ) diff --git a/api/routers/video.py b/api/routers/video.py index de47937..9119d40 100644 --- a/api/routers/video.py +++ b/api/routers/video.py @@ -8,7 +8,7 @@ import os from fastapi import APIRouter, HTTPException, Request from loguru import logger -from api.dependencies import ReelForgeDep +from api.dependencies import PixelleVideoDep from api.schemas.video import ( VideoGenerateRequest, VideoGenerateResponse, @@ -32,7 +32,7 @@ def path_to_url(request: Request, file_path: str) -> str: @router.post("/generate/sync", response_model=VideoGenerateResponse) async def generate_video_sync( request_body: VideoGenerateRequest, - reelforge: ReelForgeDep, + pixelle_video: PixelleVideoDep, request: Request ): """ @@ -52,7 +52,7 @@ async def generate_video_sync( logger.info(f"Sync video generation: {request_body.text[:50]}...") # Call video generator service - result = await reelforge.generate_video( + result = await pixelle_video.generate_video( text=request_body.text, mode=request_body.mode, title=request_body.title, @@ -94,7 +94,7 @@ async def generate_video_sync( @router.post("/generate/async", response_model=VideoGenerateAsyncResponse) async def generate_video_async( request_body: VideoGenerateRequest, - reelforge: ReelForgeDep, + pixelle_video: PixelleVideoDep, request: Request ): """ @@ -126,7 +126,7 @@ async def generate_video_async( # Define async execution function async def execute_video_generation(): """Execute video generation in background""" - result = await reelforge.generate_video( + result = await pixelle_video.generate_video( text=request_body.text, mode=request_body.mode, title=request_body.title, diff --git a/api/schemas/tts.py b/api/schemas/tts.py index de41df8..632abd8 100644 --- a/api/schemas/tts.py +++ b/api/schemas/tts.py @@ -13,7 +13,7 @@ class TTSSynthesizeRequest(BaseModel): class Config: json_schema_extra = { "example": { - "text": "Hello, welcome to ReelForge!", + "text": "Hello, welcome to Pixelle-Video!", "voice_id": "[Chinese] zh-CN Yunjian" } } diff --git a/config.example.yaml b/config.example.yaml index b8661b6..1c97061 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -1,8 +1,8 @@ -# ReelForge Configuration +# Pixelle-Video Configuration # Copy this file to config.yaml and fill in your settings # ⚠️ Never commit config.yaml to Git! -project_name: ReelForge +project_name: Pixelle-Video # ==================== LLM Configuration ==================== # Supports any OpenAI SDK compatible API diff --git a/docs/capabilities-guide.md b/docs/capabilities-guide.md index 6821800..ba6f4c5 100644 --- a/docs/capabilities-guide.md +++ b/docs/capabilities-guide.md @@ -1,10 +1,10 @@ -# ReelForge Capabilities Guide +# Pixelle-Video Capabilities Guide > Complete guide to using LLM, TTS, and Image generation capabilities ## Overview -ReelForge provides three core AI capabilities: +Pixelle-Video provides three core AI capabilities: - **LLM**: Text generation using LiteLLM (supports 100+ models) - **TTS**: Text-to-speech using Edge TTS (free, 400+ voices) - **Image**: Image generation using ComfyKit (local or cloud) @@ -12,16 +12,16 @@ ReelForge provides three core AI capabilities: ## Quick Start ```python -from reelforge.service import reelforge +from pixelle_video.service import pixelle_video # LLM - Generate text -answer = await reelforge.llm("Summarize 'Atomic Habits' in 3 sentences") +answer = await pixelle_video.llm("Summarize 'Atomic Habits' in 3 sentences") # TTS - Generate speech -audio_path = await reelforge.tts("Hello, world!") +audio_path = await pixelle_video.tts("Hello, world!") # Image - Generate images -image_url = await reelforge.image( +image_url = await pixelle_video.image( workflow="workflows/book_cover_simple.json", prompt="minimalist book cover design" ) @@ -62,10 +62,10 @@ llm: ```python # Basic usage -answer = await reelforge.llm("What is machine learning?") +answer = await pixelle_video.llm("What is machine learning?") # With parameters -answer = await reelforge.llm( +answer = await pixelle_video.llm( prompt="Explain atomic habits", temperature=0.7, # 0.0-2.0 (lower = more deterministic) max_tokens=2000 @@ -107,18 +107,18 @@ tts: ```python # Basic usage (auto-generates temp path) -audio_path = await reelforge.tts("Hello, world!") +audio_path = await pixelle_video.tts("Hello, world!") # Returns: "temp/abc123def456.mp3" # With Chinese text -audio_path = await reelforge.tts( +audio_path = await pixelle_video.tts( text="你好,世界!", voice="zh-CN-YunjianNeural" ) # With custom parameters -audio_path = await reelforge.tts( - text="Welcome to ReelForge", +audio_path = await pixelle_video.tts( + text="Welcome to Pixelle-Video", voice="en-US-JennyNeural", rate="+20%", # Speed: +50% = faster, -20% = slower volume="+0%", @@ -126,7 +126,7 @@ audio_path = await reelforge.tts( ) # Specify output path -audio_path = await reelforge.tts( +audio_path = await pixelle_video.tts( text="Hello", output_path="output/greeting.mp3" ) @@ -149,13 +149,13 @@ audio_path = await reelforge.tts( ```python # Get all available voices -voices = await reelforge.tts.list_voices() +voices = await pixelle_video.tts.list_voices() # Get Chinese voices only -voices = await reelforge.tts.list_voices(locale="zh-CN") +voices = await pixelle_video.tts.list_voices(locale="zh-CN") # Get English voices only -voices = await reelforge.tts.list_voices(locale="en-US") +voices = await pixelle_video.tts.list_voices(locale="en-US") ``` --- @@ -182,13 +182,13 @@ image: ```python # Basic usage (local ComfyUI) -image_url = await reelforge.image( +image_url = await pixelle_video.image( workflow="workflows/book_cover_simple.json", prompt="minimalist book cover design, blue and white" ) # With full parameters -image_url = await reelforge.image( +image_url = await pixelle_video.image( workflow="workflows/book_cover_simple.json", prompt="book cover for 'Atomic Habits', professional, minimalist", negative_prompt="ugly, blurry, low quality", @@ -199,13 +199,13 @@ image_url = await reelforge.image( ) # Using RunningHub cloud -image_url = await reelforge.image( +image_url = await pixelle_video.image( workflow="12345", # RunningHub workflow ID prompt="a beautiful landscape" ) # Check available workflows -workflows = reelforge.image.list_workflows() +workflows = pixelle_video.image.list_workflows() print(f"Available workflows: {workflows}") ``` @@ -221,7 +221,7 @@ export RUNNINGHUB_API_KEY="rh-key-xxx" ### Workflow DSL -ReelForge uses ComfyKit's DSL for workflow parameters: +Pixelle-Video uses ComfyKit's DSL for workflow parameters: ```json { @@ -252,27 +252,27 @@ Generate a complete book cover with narration: ```python import asyncio -from reelforge.service import reelforge +from pixelle_video.service import pixelle_video async def create_book_content(book_title, author): """Generate book summary, audio, and cover image""" # 1. Generate book summary with LLM - summary = await reelforge.llm( + summary = await pixelle_video.llm( prompt=f"Write a compelling 2-sentence summary for a book titled '{book_title}' by {author}", max_tokens=100 ) print(f"Summary: {summary}") # 2. Generate audio narration with TTS - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text=summary, voice="en-US-JennyNeural" ) print(f"Audio: {audio_path}") # 3. Generate book cover image - image_url = await reelforge.image( + image_url = await pixelle_video.image( workflow="workflows/book_cover_simple.json", prompt=f"book cover for '{book_title}' by {author}, professional, modern design", width=1024, @@ -339,5 +339,5 @@ result = asyncio.run(create_book_content("Atomic Habits", "James Clear")) --- -**Happy creating with ReelForge!** 📚🎬 +**Happy creating with Pixelle-Video!** 📚🎬 diff --git a/pixelle_video/__init__.py b/pixelle_video/__init__.py new file mode 100644 index 0000000..30df08d --- /dev/null +++ b/pixelle_video/__init__.py @@ -0,0 +1,26 @@ +""" +Pixelle-Video - AI-powered video generator + +Convention-based system with unified configuration management. + +Usage: + from pixelle_video import pixelle_video + + # Initialize + await pixelle_video.initialize() + + # Use capabilities + answer = await pixelle_video.llm("Explain atomic habits") + audio = await pixelle_video.tts("Hello world") + + # Generate video + result = await pixelle_video.generate_video(topic="AI in 2024") +""" + +from pixelle_video.service import PixelleVideoCore, pixelle_video +from pixelle_video.config import config_manager + +__version__ = "0.1.0" + +__all__ = ["PixelleVideoCore", "pixelle_video", "config_manager"] + diff --git a/reelforge/cli.py b/pixelle_video/cli.py similarity index 67% rename from reelforge/cli.py rename to pixelle_video/cli.py index 4c6e70f..6640eca 100644 --- a/reelforge/cli.py +++ b/pixelle_video/cli.py @@ -1,18 +1,18 @@ """ -ReelForge CLI +Pixelle-Video CLI """ import asyncio from loguru import logger -from reelforge.service import reelforge +from pixelle_video.service import pixelle_video async def test_llm(): """Test LLM capability""" - # Initialize reelforge - await reelforge.initialize() + # Initialize pixelle_video + await pixelle_video.initialize() # Test prompt prompt = "Explain the concept of atomic habits in 3 sentences." @@ -20,14 +20,14 @@ async def test_llm(): logger.info(f"\n📝 Test Prompt: {prompt}\n") # Call LLM - result = await reelforge.llm(prompt) + result = await pixelle_video.llm(prompt) logger.info(f"\n✨ Result:\n{result}\n") def main(): """Main CLI entry point""" - logger.info("🚀 ReelForge CLI\n") + logger.info("🚀 Pixelle-Video CLI\n") # Run test asyncio.run(test_llm()) diff --git a/reelforge/config/__init__.py b/pixelle_video/config/__init__.py similarity index 76% rename from reelforge/config/__init__.py rename to pixelle_video/config/__init__.py index 6540af2..06715dc 100644 --- a/reelforge/config/__init__.py +++ b/pixelle_video/config/__init__.py @@ -1,10 +1,10 @@ """ -ReelForge Configuration System +Pixelle-Video Configuration System Unified configuration management with Pydantic validation. Usage: - from reelforge.config import config_manager + from pixelle_video.config import config_manager # Access config (type-safe) api_key = config_manager.config.llm.api_key @@ -17,7 +17,7 @@ Usage: if config_manager.validate(): print("Config is valid!") """ -from .schema import ReelForgeConfig, LLMConfig, ComfyUIConfig, TTSSubConfig, ImageSubConfig +from .schema import PixelleVideoConfig, LLMConfig, ComfyUIConfig, TTSSubConfig, ImageSubConfig from .manager import ConfigManager from .loader import load_config_dict, save_config_dict @@ -25,7 +25,7 @@ from .loader import load_config_dict, save_config_dict config_manager = ConfigManager() __all__ = [ - "ReelForgeConfig", + "PixelleVideoConfig", "LLMConfig", "ComfyUIConfig", "TTSSubConfig", diff --git a/reelforge/config/loader.py b/pixelle_video/config/loader.py similarity index 100% rename from reelforge/config/loader.py rename to pixelle_video/config/loader.py diff --git a/reelforge/config/manager.py b/pixelle_video/config/manager.py similarity index 94% rename from reelforge/config/manager.py rename to pixelle_video/config/manager.py index 1d31cd1..1ab98fc 100644 --- a/reelforge/config/manager.py +++ b/pixelle_video/config/manager.py @@ -6,7 +6,7 @@ Provides unified access to configuration with automatic validation. from pathlib import Path from typing import Any, Optional from loguru import logger -from .schema import ReelForgeConfig +from .schema import PixelleVideoConfig from .loader import load_config_dict, save_config_dict @@ -29,13 +29,13 @@ class ConfigManager: return self.config_path = Path(config_path) - self.config: ReelForgeConfig = self._load() + self.config: PixelleVideoConfig = self._load() self._initialized = True - def _load(self) -> ReelForgeConfig: + def _load(self) -> PixelleVideoConfig: """Load configuration from file""" data = load_config_dict(str(self.config_path)) - return ReelForgeConfig(**data) + return PixelleVideoConfig(**data) def reload(self): """Reload configuration from file""" @@ -65,7 +65,7 @@ class ConfigManager: return base merged = deep_merge(current, updates) - self.config = ReelForgeConfig(**merged) + self.config = PixelleVideoConfig(**merged) def get(self, key: str, default: Any = None) -> Any: """Dict-like access (for backward compatibility)""" diff --git a/reelforge/config/schema.py b/pixelle_video/config/schema.py similarity index 93% rename from reelforge/config/schema.py rename to pixelle_video/config/schema.py index c0f6683..5b1ab6a 100644 --- a/reelforge/config/schema.py +++ b/pixelle_video/config/schema.py @@ -35,9 +35,9 @@ class ComfyUIConfig(BaseModel): image: ImageSubConfig = Field(default_factory=ImageSubConfig, description="Image-specific configuration") -class ReelForgeConfig(BaseModel): - """ReelForge main configuration""" - project_name: str = Field(default="ReelForge", description="Project name") +class PixelleVideoConfig(BaseModel): + """Pixelle-Video main configuration""" + project_name: str = Field(default="Pixelle-Video", description="Project name") llm: LLMConfig = Field(default_factory=LLMConfig) comfyui: ComfyUIConfig = Field(default_factory=ComfyUIConfig) diff --git a/reelforge/llm_presets.py b/pixelle_video/llm_presets.py similarity index 100% rename from reelforge/llm_presets.py rename to pixelle_video/llm_presets.py diff --git a/reelforge/models/progress.py b/pixelle_video/models/progress.py similarity index 100% rename from reelforge/models/progress.py rename to pixelle_video/models/progress.py diff --git a/reelforge/models/storyboard.py b/pixelle_video/models/storyboard.py similarity index 100% rename from reelforge/models/storyboard.py rename to pixelle_video/models/storyboard.py diff --git a/reelforge/prompts/README.md b/pixelle_video/prompts/README.md similarity index 94% rename from reelforge/prompts/README.md rename to pixelle_video/prompts/README.md index a1d5848..2e973a1 100644 --- a/reelforge/prompts/README.md +++ b/pixelle_video/prompts/README.md @@ -1,6 +1,6 @@ # Prompts Directory -Centralized prompt management for all LLM interactions in ReelForge. +Centralized prompt management for all LLM interactions in Pixelle-Video. ## Structure @@ -22,7 +22,7 @@ prompts/ All builder functions are exported from the package root: ```python -from reelforge.prompts import ( +from pixelle_video.prompts import ( build_topic_narration_prompt, build_content_narration_prompt, build_script_split_prompt, @@ -86,7 +86,7 @@ To add a new prompt: 3. Export the builder function in `__init__.py` 4. Use it in service code: ```python - from reelforge.prompts import build_my_new_prompt + from pixelle_video.prompts import build_my_new_prompt ``` ## Design Principles diff --git a/reelforge/prompts/__init__.py b/pixelle_video/prompts/__init__.py similarity index 60% rename from reelforge/prompts/__init__.py rename to pixelle_video/prompts/__init__.py index a4b1a48..df4cafb 100644 --- a/reelforge/prompts/__init__.py +++ b/pixelle_video/prompts/__init__.py @@ -5,17 +5,17 @@ Centralized prompt management for all LLM interactions. """ # Narration prompts -from reelforge.prompts.topic_narration import build_topic_narration_prompt -from reelforge.prompts.content_narration import build_content_narration_prompt -from reelforge.prompts.title_generation import build_title_generation_prompt +from pixelle_video.prompts.topic_narration import build_topic_narration_prompt +from pixelle_video.prompts.content_narration import build_content_narration_prompt +from pixelle_video.prompts.title_generation import build_title_generation_prompt # Image prompts -from reelforge.prompts.image_generation import ( +from pixelle_video.prompts.image_generation import ( build_image_prompt_prompt, IMAGE_STYLE_PRESETS, DEFAULT_IMAGE_STYLE ) -from reelforge.prompts.style_conversion import build_style_conversion_prompt +from pixelle_video.prompts.style_conversion import build_style_conversion_prompt __all__ = [ diff --git a/reelforge/prompts/content_narration.py b/pixelle_video/prompts/content_narration.py similarity index 100% rename from reelforge/prompts/content_narration.py rename to pixelle_video/prompts/content_narration.py diff --git a/reelforge/prompts/image_generation.py b/pixelle_video/prompts/image_generation.py similarity index 100% rename from reelforge/prompts/image_generation.py rename to pixelle_video/prompts/image_generation.py diff --git a/reelforge/prompts/style_conversion.py b/pixelle_video/prompts/style_conversion.py similarity index 100% rename from reelforge/prompts/style_conversion.py rename to pixelle_video/prompts/style_conversion.py diff --git a/reelforge/prompts/title_generation.py b/pixelle_video/prompts/title_generation.py similarity index 100% rename from reelforge/prompts/title_generation.py rename to pixelle_video/prompts/title_generation.py diff --git a/reelforge/prompts/topic_narration.py b/pixelle_video/prompts/topic_narration.py similarity index 100% rename from reelforge/prompts/topic_narration.py rename to pixelle_video/prompts/topic_narration.py diff --git a/reelforge/service.py b/pixelle_video/service.py similarity index 64% rename from reelforge/service.py rename to pixelle_video/service.py index 9a268bd..f422b6a 100644 --- a/reelforge/service.py +++ b/pixelle_video/service.py @@ -1,5 +1,5 @@ """ -ReelForge Core - Service Layer +Pixelle-Video Core - Service Layer Provides unified access to all capabilities (LLM, TTS, Image, etc.) """ @@ -8,40 +8,40 @@ from typing import Optional from loguru import logger -from reelforge.config import config_manager -from reelforge.services.llm_service import LLMService -from reelforge.services.tts_service import TTSService -from reelforge.services.image import ImageService -from reelforge.services.narration_generator import NarrationGeneratorService -from reelforge.services.image_prompt_generator import ImagePromptGeneratorService -from reelforge.services.title_generator import TitleGeneratorService -from reelforge.services.frame_processor import FrameProcessor -from reelforge.services.video_generator import VideoGeneratorService +from pixelle_video.config import config_manager +from pixelle_video.services.llm_service import LLMService +from pixelle_video.services.tts_service import TTSService +from pixelle_video.services.image import ImageService +from pixelle_video.services.narration_generator import NarrationGeneratorService +from pixelle_video.services.image_prompt_generator import ImagePromptGeneratorService +from pixelle_video.services.title_generator import TitleGeneratorService +from pixelle_video.services.frame_processor import FrameProcessor +from pixelle_video.services.video_generator import VideoGeneratorService -class ReelForgeCore: +class PixelleVideoCore: """ - ReelForge Core - Service Layer + Pixelle-Video Core - Service Layer Provides unified access to all capabilities. Usage: - from reelforge import reelforge + from pixelle_video import pixelle_video # Initialize - await reelforge.initialize() + await pixelle_video.initialize() # Use capabilities directly - answer = await reelforge.llm("Explain atomic habits") - audio = await reelforge.tts("Hello world") - image = await reelforge.image(prompt="a cat") + answer = await pixelle_video.llm("Explain atomic habits") + audio = await pixelle_video.tts("Hello world") + image = await pixelle_video.image(prompt="a cat") # Check active capabilities - print(f"Using LLM: {reelforge.llm.active}") - print(f"Available TTS: {reelforge.tts.available}") + print(f"Using LLM: {pixelle_video.llm.active}") + print(f"Available TTS: {pixelle_video.tts.available}") Architecture (Simplified): - ReelForgeCore (this class) + PixelleVideoCore (this class) ├── config (configuration) ├── llm (LLM service - direct OpenAI SDK) ├── tts (TTS service - ComfyKit workflows) @@ -50,7 +50,7 @@ class ReelForgeCore: def __init__(self, config_path: str = "config.yaml"): """ - Initialize ReelForge Core + Initialize Pixelle-Video Core Args: config_path: Path to configuration file @@ -82,13 +82,13 @@ class ReelForgeCore: This initializes all services and must be called before using any capabilities. Example: - await reelforge.initialize() + await pixelle_video.initialize() """ if self._initialized: - logger.warning("ReelForge already initialized") + logger.warning("Pixelle-Video already initialized") return - logger.info("🚀 Initializing ReelForge...") + logger.info("🚀 Initializing Pixelle-Video...") # 1. Initialize core services (no capability layer) self.llm = LLMService(self.config) @@ -107,18 +107,18 @@ class ReelForgeCore: self.generate_video = VideoGeneratorService(self) self._initialized = True - logger.info("✅ ReelForge initialized successfully\n") + logger.info("✅ Pixelle-Video initialized successfully\n") @property def project_name(self) -> str: """Get project name from config""" - return self.config.get("project_name", "ReelForge") + return self.config.get("project_name", "Pixelle-Video") def __repr__(self) -> str: """String representation""" status = "initialized" if self._initialized else "not initialized" - return f"" + return f"" # Global instance -reelforge = ReelForgeCore() +pixelle_video = PixelleVideoCore() diff --git a/pixelle_video/services/__init__.py b/pixelle_video/services/__init__.py new file mode 100644 index 0000000..6a5091a --- /dev/null +++ b/pixelle_video/services/__init__.py @@ -0,0 +1,30 @@ +""" +Pixelle-Video Services + +Unified service layer providing simplified access to capabilities. +""" + +from pixelle_video.services.comfy_base_service import ComfyBaseService +from pixelle_video.services.llm_service import LLMService +from pixelle_video.services.tts_service import TTSService +from pixelle_video.services.image import ImageService +from pixelle_video.services.video import VideoService +from pixelle_video.services.narration_generator import NarrationGeneratorService +from pixelle_video.services.image_prompt_generator import ImagePromptGeneratorService +from pixelle_video.services.title_generator import TitleGeneratorService +from pixelle_video.services.frame_processor import FrameProcessor +from pixelle_video.services.video_generator import VideoGeneratorService + +__all__ = [ + "ComfyBaseService", + "LLMService", + "TTSService", + "ImageService", + "VideoService", + "NarrationGeneratorService", + "ImagePromptGeneratorService", + "TitleGeneratorService", + "FrameProcessor", + "VideoGeneratorService", +] + diff --git a/reelforge/services/comfy_base_service.py b/pixelle_video/services/comfy_base_service.py similarity index 100% rename from reelforge/services/comfy_base_service.py rename to pixelle_video/services/comfy_base_service.py diff --git a/reelforge/services/frame_html.py b/pixelle_video/services/frame_html.py similarity index 99% rename from reelforge/services/frame_html.py rename to pixelle_video/services/frame_html.py index e1d5b84..3055424 100644 --- a/reelforge/services/frame_html.py +++ b/pixelle_video/services/frame_html.py @@ -253,7 +253,7 @@ class HTMLFrameGenerator: # Use provided output path or auto-generate if output_path is None: # Fallback: auto-generate (for backward compatibility) - from reelforge.utils.os_util import get_output_path + from pixelle_video.utils.os_util import get_output_path output_filename = f"frame_{uuid.uuid4().hex[:16]}.png" output_path = get_output_path(output_filename) else: diff --git a/reelforge/services/frame_processor.py b/pixelle_video/services/frame_processor.py similarity index 93% rename from reelforge/services/frame_processor.py rename to pixelle_video/services/frame_processor.py index ed249f0..00949d6 100644 --- a/reelforge/services/frame_processor.py +++ b/pixelle_video/services/frame_processor.py @@ -9,21 +9,21 @@ from typing import Callable, Optional import httpx from loguru import logger -from reelforge.models.progress import ProgressEvent -from reelforge.models.storyboard import Storyboard, StoryboardFrame, StoryboardConfig +from pixelle_video.models.progress import ProgressEvent +from pixelle_video.models.storyboard import Storyboard, StoryboardFrame, StoryboardConfig class FrameProcessor: """Frame processor""" - def __init__(self, reelforge_core): + def __init__(self, pixelle_video_core): """ Initialize Args: - reelforge_core: ReelForgeCore instance + pixelle_video_core: PixelleVideoCore instance """ - self.core = reelforge_core + self.core = pixelle_video_core async def __call__( self, @@ -121,7 +121,7 @@ class FrameProcessor: logger.debug(f" 1/4: Generating audio for frame {frame.index}...") # Generate output path using task_id - from reelforge.utils.os_util import get_task_frame_path + from pixelle_video.utils.os_util import get_task_frame_path output_path = get_task_frame_path(config.task_id, frame.index, "audio") # Call TTS with specific output path and workflow @@ -172,7 +172,7 @@ class FrameProcessor: logger.debug(f" 3/4: Composing frame {frame.index}...") # Generate output path using task_id - from reelforge.utils.os_util import get_task_frame_path + from pixelle_video.utils.os_util import get_task_frame_path output_path = get_task_frame_path(config.task_id, frame.index, "composed") # Use HTML template to compose frame @@ -190,7 +190,7 @@ class FrameProcessor: output_path: str ) -> str: """Compose frame using HTML template""" - from reelforge.services.frame_html import HTMLFrameGenerator + from pixelle_video.services.frame_html import HTMLFrameGenerator from pathlib import Path # Resolve template path @@ -241,11 +241,11 @@ class FrameProcessor: logger.debug(f" 4/4: Creating video segment for frame {frame.index}...") # Generate output path using task_id - from reelforge.utils.os_util import get_task_frame_path + from pixelle_video.utils.os_util import get_task_frame_path output_path = get_task_frame_path(config.task_id, frame.index, "segment") # Call video compositor to create video from image + audio - from reelforge.services.video import VideoService + from pixelle_video.services.video import VideoService video_service = VideoService() segment_path = video_service.create_video_from_image( @@ -278,7 +278,7 @@ class FrameProcessor: async def _download_image(self, url: str, frame_index: int, task_id: str) -> str: """Download image from URL to local file""" - from reelforge.utils.os_util import get_task_frame_path + from pixelle_video.utils.os_util import get_task_frame_path output_path = get_task_frame_path(task_id, frame_index, "image") async with httpx.AsyncClient() as client: diff --git a/reelforge/services/image.py b/pixelle_video/services/image.py similarity index 91% rename from reelforge/services/image.py rename to pixelle_video/services/image.py index 50e64b8..b29d969 100644 --- a/reelforge/services/image.py +++ b/pixelle_video/services/image.py @@ -7,7 +7,7 @@ from typing import Optional from comfykit import ComfyKit from loguru import logger -from reelforge.services.comfy_base_service import ComfyBaseService +from pixelle_video.services.comfy_base_service import ComfyBaseService class ImageService(ComfyBaseService): @@ -18,16 +18,16 @@ class ImageService(ComfyBaseService): Usage: # Use default workflow (workflows/image_flux.json) - image_url = await reelforge.image(prompt="a cat") + image_url = await pixelle_video.image(prompt="a cat") # Use specific workflow - image_url = await reelforge.image( + image_url = await pixelle_video.image( prompt="a cat", workflow="image_flux.json" ) # List available workflows - workflows = reelforge.image.list_workflows() + workflows = pixelle_video.image.list_workflows() """ WORKFLOW_PREFIX = "image_" @@ -82,16 +82,16 @@ class ImageService(ComfyBaseService): Examples: # Simplest: use default workflow (workflows/image_flux.json) - image_url = await reelforge.image(prompt="a beautiful cat") + image_url = await pixelle_video.image(prompt="a beautiful cat") # Use specific workflow - image_url = await reelforge.image( + image_url = await pixelle_video.image( prompt="a cat", workflow="image_flux.json" ) # With additional parameters - image_url = await reelforge.image( + image_url = await pixelle_video.image( prompt="a cat", workflow="image_flux.json", width=1024, @@ -101,13 +101,13 @@ class ImageService(ComfyBaseService): ) # With absolute path - image_url = await reelforge.image( + image_url = await pixelle_video.image( prompt="a cat", workflow="/path/to/custom.json" ) # With custom ComfyUI server - image_url = await reelforge.image( + image_url = await pixelle_video.image( prompt="a cat", comfyui_url="http://192.168.1.100:8188" ) diff --git a/reelforge/services/image_prompt_generator.py b/pixelle_video/services/image_prompt_generator.py similarity index 95% rename from reelforge/services/image_prompt_generator.py rename to pixelle_video/services/image_prompt_generator.py index d8a8b02..d8feea6 100644 --- a/reelforge/services/image_prompt_generator.py +++ b/pixelle_video/services/image_prompt_generator.py @@ -8,21 +8,21 @@ from typing import List, Optional, Callable from loguru import logger -from reelforge.models.storyboard import StoryboardConfig -from reelforge.prompts import build_image_prompt_prompt +from pixelle_video.models.storyboard import StoryboardConfig +from pixelle_video.prompts import build_image_prompt_prompt class ImagePromptGeneratorService: """Image prompt generation service""" - def __init__(self, reelforge_core): + def __init__(self, pixelle_video_core): """ Initialize Args: - reelforge_core: ReelForgeCore instance + pixelle_video_core: PixelleVideoCore instance """ - self.core = reelforge_core + self.core = pixelle_video_core async def generate_image_prompts( self, @@ -114,7 +114,7 @@ class ImagePromptGeneratorService: logger.info(f"✅ All batches completed. Total prompts: {len(base_prompts)}") # 5. Apply prompt prefix to each prompt - from reelforge.utils.prompt_helper import build_image_prompt + from pixelle_video.utils.prompt_helper import build_image_prompt # Get prompt prefix from config (fix: correct path is comfyui.image.prompt_prefix) image_config = self.core.config.get("comfyui", {}).get("image", {}) diff --git a/reelforge/services/llm_service.py b/pixelle_video/services/llm_service.py similarity index 95% rename from reelforge/services/llm_service.py rename to pixelle_video/services/llm_service.py index 2e36712..8f5fbcb 100644 --- a/reelforge/services/llm_service.py +++ b/pixelle_video/services/llm_service.py @@ -26,10 +26,10 @@ class LLMService: Usage: # Direct call - answer = await reelforge.llm("Explain atomic habits") + answer = await pixelle_video.llm("Explain atomic habits") # With parameters - answer = await reelforge.llm( + answer = await pixelle_video.llm( prompt="Explain atomic habits in 3 sentences", temperature=0.7, max_tokens=2000 @@ -121,10 +121,10 @@ class LLMService: Examples: # Use config from config.yaml - answer = await reelforge.llm("Explain atomic habits") + answer = await pixelle_video.llm("Explain atomic habits") # Override with custom parameters - answer = await reelforge.llm( + answer = await pixelle_video.llm( prompt="Explain atomic habits in 3 sentences", api_key="sk-custom-key", base_url="https://api.custom.com/v1", @@ -172,7 +172,7 @@ class LLMService: Active model name Example: - print(f"Using model: {reelforge.llm.active}") + print(f"Using model: {pixelle_video.llm.active}") """ return self._get_config_value("model", "gpt-3.5-turbo") diff --git a/reelforge/services/narration_generator.py b/pixelle_video/services/narration_generator.py similarity index 95% rename from reelforge/services/narration_generator.py rename to pixelle_video/services/narration_generator.py index 4f9bf57..8098109 100644 --- a/reelforge/services/narration_generator.py +++ b/pixelle_video/services/narration_generator.py @@ -12,8 +12,8 @@ from typing import List, Optional, Literal from loguru import logger -from reelforge.models.storyboard import StoryboardConfig, ContentMetadata -from reelforge.prompts import ( +from pixelle_video.models.storyboard import StoryboardConfig, ContentMetadata +from pixelle_video.prompts import ( build_topic_narration_prompt, build_content_narration_prompt, ) @@ -22,14 +22,14 @@ from reelforge.prompts import ( class NarrationGeneratorService: """Narration generation service""" - def __init__(self, reelforge_core): + def __init__(self, pixelle_video_core): """ Initialize Args: - reelforge_core: ReelForgeCore instance (for calling llm) + pixelle_video_core: PixelleVideoCore instance (for calling llm) """ - self.core = reelforge_core + self.core = pixelle_video_core async def generate_narrations( self, diff --git a/reelforge/services/title_generator.py b/pixelle_video/services/title_generator.py similarity index 95% rename from reelforge/services/title_generator.py rename to pixelle_video/services/title_generator.py index b86c0d2..50328da 100644 --- a/reelforge/services/title_generator.py +++ b/pixelle_video/services/title_generator.py @@ -24,14 +24,14 @@ class TitleGeneratorService: - llm: Always use LLM to generate title """ - def __init__(self, reelforge_core): + def __init__(self, pixelle_video_core): """ Initialize title generator service Args: - reelforge_core: ReelForgeCore instance + pixelle_video_core: PixelleVideoCore instance """ - self.core = reelforge_core + self.core = pixelle_video_core async def __call__( self, @@ -107,7 +107,7 @@ class TitleGeneratorService: Returns: LLM-generated title """ - from reelforge.prompts import build_title_generation_prompt + from pixelle_video.prompts import build_title_generation_prompt # Build prompt using template prompt = build_title_generation_prompt(content, max_length=500) diff --git a/reelforge/services/tts_service.py b/pixelle_video/services/tts_service.py similarity index 94% rename from reelforge/services/tts_service.py rename to pixelle_video/services/tts_service.py index 2e21993..97da7e6 100644 --- a/reelforge/services/tts_service.py +++ b/pixelle_video/services/tts_service.py @@ -7,7 +7,7 @@ from typing import Optional from comfykit import ComfyKit from loguru import logger -from reelforge.services.comfy_base_service import ComfyBaseService +from pixelle_video.services.comfy_base_service import ComfyBaseService class TTSService(ComfyBaseService): @@ -18,16 +18,16 @@ class TTSService(ComfyBaseService): Usage: # Use default workflow - audio_path = await reelforge.tts(text="Hello, world!") + audio_path = await pixelle_video.tts(text="Hello, world!") # Use specific workflow - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text="你好,世界!", workflow="tts_edge.json" ) # List available workflows - workflows = reelforge.tts.list_workflows() + workflows = pixelle_video.tts.list_workflows() """ WORKFLOW_PREFIX = "tts_" @@ -76,16 +76,16 @@ class TTSService(ComfyBaseService): Examples: # Simplest: use default workflow - audio_path = await reelforge.tts(text="Hello, world!") + audio_path = await pixelle_video.tts(text="Hello, world!") # Use specific workflow - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text="你好,世界!", workflow="tts_edge.json" ) # With voice and speed - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text="Hello", workflow="tts_edge.json", voice="[Chinese] zh-CN Xiaoxiao", @@ -93,13 +93,13 @@ class TTSService(ComfyBaseService): ) # With absolute path - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text="Hello", workflow="/path/to/custom_tts.json" ) # With custom ComfyUI server - audio_path = await reelforge.tts( + audio_path = await pixelle_video.tts( text="Hello", comfyui_url="http://192.168.1.100:8188" ) diff --git a/reelforge/services/video.py b/pixelle_video/services/video.py similarity index 100% rename from reelforge/services/video.py rename to pixelle_video/services/video.py diff --git a/reelforge/services/video_generator.py b/pixelle_video/services/video_generator.py similarity index 97% rename from reelforge/services/video_generator.py rename to pixelle_video/services/video_generator.py index 74e1a0c..7d65b92 100644 --- a/reelforge/services/video_generator.py +++ b/pixelle_video/services/video_generator.py @@ -10,8 +10,8 @@ from typing import Optional, Callable, Literal from loguru import logger -from reelforge.models.progress import ProgressEvent -from reelforge.models.storyboard import ( +from pixelle_video.models.progress import ProgressEvent +from pixelle_video.models.storyboard import ( Storyboard, StoryboardFrame, StoryboardConfig, @@ -32,14 +32,14 @@ class VideoGeneratorService: 5. Add BGM (optional) """ - def __init__(self, reelforge_core): + def __init__(self, pixelle_video_core): """ Initialize video generator service Args: - reelforge_core: ReelForgeCore instance + pixelle_video_core: PixelleVideoCore instance """ - self.core = reelforge_core + self.core = pixelle_video_core async def __call__( self, @@ -149,7 +149,7 @@ class VideoGeneratorService: Examples: # Generate mode: LLM creates narrations from topic - >>> result = await reelforge.generate_video( + >>> result = await pixelle_video.generate_video( ... text="如何在信息爆炸时代保持深度思考", ... mode="generate", ... n_scenes=5, @@ -161,7 +161,7 @@ class VideoGeneratorService: ... 第一个技巧是专注力训练,每天冥想10分钟 ... 第二个技巧是主动回忆,学完立即复述 ... 第三个技巧是间隔重复,学习后定期复习''' - >>> result = await reelforge.generate_video( + >>> result = await pixelle_video.generate_video( ... text=script, ... mode="fixed", ... title="三个学习技巧" @@ -190,7 +190,7 @@ class VideoGeneratorService: logger.info(f" Title: '{final_title}' (LLM-generated)") # ========== Step 0.5: Create isolated task directory ========== - from reelforge.utils.os_util import ( + from pixelle_video.utils.os_util import ( create_task_output_dir, get_task_final_video_path ) @@ -352,7 +352,7 @@ class VideoGeneratorService: self._report_progress(progress_callback, "concatenating", 0.85) segment_paths = [frame.video_segment_path for frame in storyboard.frames] - from reelforge.services.video import VideoService + from pixelle_video.services.video import VideoService video_service = VideoService() final_video_path = video_service.concat_videos( diff --git a/pixelle_video/utils/__init__.py b/pixelle_video/utils/__init__.py new file mode 100644 index 0000000..1884dbb --- /dev/null +++ b/pixelle_video/utils/__init__.py @@ -0,0 +1,3 @@ +""" +Pixelle-Video utilities +""" diff --git a/reelforge/utils/os_util.py b/pixelle_video/utils/os_util.py similarity index 91% rename from reelforge/utils/os_util.py rename to pixelle_video/utils/os_util.py index 4e27c47..a4d6c0e 100644 --- a/reelforge/utils/os_util.py +++ b/pixelle_video/utils/os_util.py @@ -1,7 +1,7 @@ """ OS utilities for file and path management -Provides utilities for managing paths and files in ReelForge. +Provides utilities for managing paths and files in Pixelle-Video. Inspired by Pixelle-MCP's os_util.py. """ @@ -12,9 +12,9 @@ from pathlib import Path from typing import Optional, Tuple, Literal -def get_reelforge_root_path() -> str: +def get_pixelle_video_root_path() -> str: """ - Get ReelForge root path - current working directory + Get Pixelle-Video root path - current working directory Returns: Current working directory as string @@ -22,14 +22,14 @@ def get_reelforge_root_path() -> str: return str(Path.cwd()) -def ensure_reelforge_root_path() -> str: +def ensure_pixelle_video_root_path() -> str: """ - Ensure ReelForge root path exists and return the path + Ensure Pixelle-Video root path exists and return the path Returns: Root path as string """ - root_path = get_reelforge_root_path() + root_path = get_pixelle_video_root_path() root_path_obj = Path(root_path) output_dir = root_path_obj / 'output' output_dir.mkdir(parents=True, exist_ok=True) @@ -39,7 +39,7 @@ def ensure_reelforge_root_path() -> str: def get_root_path(*paths: str) -> str: """ - Get path relative to ReelForge root path + Get path relative to Pixelle-Video root path Args: *paths: Path components to join @@ -51,7 +51,7 @@ def get_root_path(*paths: str) -> str: get_root_path("temp", "audio.mp3") # Returns: "/path/to/project/temp/audio.mp3" """ - root_path = ensure_reelforge_root_path() + root_path = ensure_pixelle_video_root_path() if paths: return os.path.join(root_path, *paths) return root_path @@ -59,7 +59,7 @@ def get_root_path(*paths: str) -> str: def get_temp_path(*paths: str) -> str: """ - Get path relative to ReelForge temp folder + Get path relative to Pixelle-Video temp folder Args: *paths: Path components to join @@ -79,7 +79,7 @@ def get_temp_path(*paths: str) -> str: def get_data_path(*paths: str) -> str: """ - Get path relative to ReelForge data folder + Get path relative to Pixelle-Video data folder Args: *paths: Path components to join @@ -99,7 +99,7 @@ def get_data_path(*paths: str) -> str: def get_output_path(*paths: str) -> str: """ - Get path relative to ReelForge output folder + Get path relative to Pixelle-Video output folder Args: *paths: Path components to join diff --git a/reelforge/utils/prompt_helper.py b/pixelle_video/utils/prompt_helper.py similarity index 100% rename from reelforge/utils/prompt_helper.py rename to pixelle_video/utils/prompt_helper.py diff --git a/reelforge/utils/tts_util.py b/pixelle_video/utils/tts_util.py similarity index 100% rename from reelforge/utils/tts_util.py rename to pixelle_video/utils/tts_util.py diff --git a/pyproject.toml b/pyproject.toml index d66e178..0b860d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [project] -name = "reelforge" +name = "pixelle-video" version = "0.1.0" -description = "The modular video creation platform - Forge your perfect reel engine" +description = "AI-powered video creation platform - Part of Pixelle ecosystem" authors = [ - {name = "ReelForge Team"} + {name = "PixelleLab"} ] readme = "README.md" requires-python = ">=3.11" @@ -34,7 +34,8 @@ dev = [ ] [project.scripts] -reelforge = "reelforge.cli:main" +pixelle-video = "pixelle_video.cli:main" +pvideo = "pixelle_video.cli:main" [build-system] requires = ["hatchling"] diff --git a/reelforge/__init__.py b/reelforge/__init__.py deleted file mode 100644 index 8b81634..0000000 --- a/reelforge/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -ReelForge - AI-powered video generator - -Convention-based system with unified configuration management. - -Usage: - from reelforge import reelforge - - # Initialize - await reelforge.initialize() - - # Use capabilities - answer = await reelforge.llm("Explain atomic habits") - audio = await reelforge.tts("Hello world") - - # Generate video - result = await reelforge.generate_video(topic="AI in 2024") -""" - -from reelforge.service import ReelForgeCore, reelforge -from reelforge.config import config_manager - -__version__ = "0.1.0" - -__all__ = ["ReelForgeCore", "reelforge", "config_manager"] - diff --git a/reelforge/services/__init__.py b/reelforge/services/__init__.py deleted file mode 100644 index 77f65da..0000000 --- a/reelforge/services/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -ReelForge Services - -Unified service layer providing simplified access to capabilities. -""" - -from reelforge.services.comfy_base_service import ComfyBaseService -from reelforge.services.llm_service import LLMService -from reelforge.services.tts_service import TTSService -from reelforge.services.image import ImageService -from reelforge.services.video import VideoService -from reelforge.services.narration_generator import NarrationGeneratorService -from reelforge.services.image_prompt_generator import ImagePromptGeneratorService -from reelforge.services.title_generator import TitleGeneratorService -from reelforge.services.frame_processor import FrameProcessor -from reelforge.services.video_generator import VideoGeneratorService - -__all__ = [ - "ComfyBaseService", - "LLMService", - "TTSService", - "ImageService", - "VideoService", - "NarrationGeneratorService", - "ImagePromptGeneratorService", - "TitleGeneratorService", - "FrameProcessor", - "VideoGeneratorService", -] - diff --git a/reelforge/utils/__init__.py b/reelforge/utils/__init__.py deleted file mode 100644 index e06405f..0000000 --- a/reelforge/utils/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -ReelForge utilities -""" diff --git a/restart_web.sh b/restart_web.sh index 5935b22..e7364bd 100755 --- a/restart_web.sh +++ b/restart_web.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Restart ReelForge Web UI on port 8502 +# Restart Pixelle-Video Web UI on port 8502 -echo "🔄 Restarting ReelForge Web UI on port 8502..." +echo "🔄 Restarting Pixelle-Video Web UI on port 8502..." echo "" # Check if config.yaml exists @@ -28,7 +28,7 @@ if [ ! -z "$PID" ]; then fi # Start Streamlit in background with nohup -echo "🚀 Starting ReelForge Web UI in background..." +echo "🚀 Starting Pixelle-Video Web UI in background..." nohup uv run streamlit run web/app.py --server.port $PORT > nohup.out 2>&1 & # Wait a moment and check if the process started @@ -36,12 +36,12 @@ sleep 2 NEW_PID=$(lsof -ti:$PORT) if [ ! -z "$NEW_PID" ]; then - echo "✅ ReelForge Web UI started successfully!" + echo "✅ Pixelle-Video Web UI started successfully!" echo "📝 Process ID: $NEW_PID" echo "🌐 Access at: http://localhost:$PORT" echo "📄 Logs: nohup.out" else - echo "❌ Failed to start ReelForge Web UI" + echo "❌ Failed to start Pixelle-Video Web UI" echo "📄 Check nohup.out for error details" exit 1 fi diff --git a/start_web.sh b/start_web.sh index 4a4dc1c..99d9935 100755 --- a/start_web.sh +++ b/start_web.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Start ReelForge Web UI +# Start Pixelle-Video Web UI -echo "🚀 Starting ReelForge Web UI..." +echo "🚀 Starting Pixelle-Video Web UI..." echo "" # Check if config.yaml exists diff --git a/templates/default.html b/templates/default.html index f0e297b..ee01ab4 100644 --- a/templates/default.html +++ b/templates/default.html @@ -527,7 +527,7 @@
Open Source Omnimodal AI Creative Agent
- +
diff --git a/templates/modern.html b/templates/modern.html index ffd0fa0..13d590e 100644 --- a/templates/modern.html +++ b/templates/modern.html @@ -558,7 +558,7 @@
Open Source Omnimodal AI Creative Agent
- +
diff --git a/templates/neon.html b/templates/neon.html index 7109945..6bad249 100644 --- a/templates/neon.html +++ b/templates/neon.html @@ -923,7 +923,7 @@
Open Source Omnimodal AI Creative Agent
- +
#AI创作 #短视频 diff --git a/uv.lock b/uv.lock index a7c0866..abcb3c7 100644 --- a/uv.lock +++ b/uv.lock @@ -1640,6 +1640,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598 }, ] +[[package]] +name = "pixelle-video" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "certifi" }, + { name = "comfykit" }, + { name = "edge-tts" }, + { name = "fastapi" }, + { name = "fastmcp" }, + { name = "ffmpeg-python" }, + { name = "html2image" }, + { name = "httpx" }, + { name = "loguru" }, + { name = "openai" }, + { name = "pillow" }, + { name = "pydantic" }, + { name = "python-multipart" }, + { name = "pyyaml" }, + { name = "streamlit" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "certifi", specifier = ">=2025.10.5" }, + { name = "comfykit", specifier = ">=0.1.0" }, + { name = "edge-tts", specifier = ">=7.2.3" }, + { name = "fastapi", specifier = ">=0.115.0" }, + { name = "fastmcp", specifier = ">=2.0.0" }, + { name = "ffmpeg-python", specifier = ">=0.2.0" }, + { name = "html2image", specifier = ">=2.0.7" }, + { name = "httpx", specifier = ">=0.28.1" }, + { name = "loguru", specifier = ">=0.7.0" }, + { name = "openai", specifier = ">=2.6.0" }, + { name = "pillow", specifier = ">=10.0.0,<12" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.0" }, + { name = "python-multipart", specifier = ">=0.0.12" }, + { name = "pyyaml", specifier = ">=6.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6.0" }, + { name = "streamlit", specifier = ">=1.40.0" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" }, +] +provides-extras = ["dev"] + [[package]] name = "pluggy" version = "1.6.0" @@ -2094,60 +2148,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, ] -[[package]] -name = "reelforge" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "certifi" }, - { name = "comfykit" }, - { name = "edge-tts" }, - { name = "fastapi" }, - { name = "fastmcp" }, - { name = "ffmpeg-python" }, - { name = "html2image" }, - { name = "httpx" }, - { name = "loguru" }, - { name = "openai" }, - { name = "pillow" }, - { name = "pydantic" }, - { name = "python-multipart" }, - { name = "pyyaml" }, - { name = "streamlit" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[package.optional-dependencies] -dev = [ - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "certifi", specifier = ">=2025.10.5" }, - { name = "comfykit", specifier = ">=0.1.0" }, - { name = "edge-tts", specifier = ">=7.2.3" }, - { name = "fastapi", specifier = ">=0.115.0" }, - { name = "fastmcp", specifier = ">=2.0.0" }, - { name = "ffmpeg-python", specifier = ">=0.2.0" }, - { name = "html2image", specifier = ">=2.0.7" }, - { name = "httpx", specifier = ">=0.28.1" }, - { name = "loguru", specifier = ">=0.7.0" }, - { name = "openai", specifier = ">=2.6.0" }, - { name = "pillow", specifier = ">=10.0.0,<12" }, - { name = "pydantic", specifier = ">=2.0.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.0" }, - { name = "python-multipart", specifier = ">=0.0.12" }, - { name = "pyyaml", specifier = ">=6.0.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6.0" }, - { name = "streamlit", specifier = ">=1.40.0" }, - { name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" }, -] -provides-extras = ["dev"] - [[package]] name = "referencing" version = "0.36.2" diff --git a/web/app.py b/web/app.py index f8c2171..85c0fba 100644 --- a/web/app.py +++ b/web/app.py @@ -1,5 +1,5 @@ """ -ReelForge Web UI +Pixelle-Video Web UI A simple web interface for generating short videos from content. """ @@ -14,12 +14,12 @@ from loguru import logger # Import i18n and config manager from web.i18n import load_locales, set_language, tr, get_available_languages, get_language -from reelforge.config import config_manager -from reelforge.models.progress import ProgressEvent +from pixelle_video.config import config_manager +from pixelle_video.models.progress import ProgressEvent # Setup page config (must be first) st.set_page_config( - page_title="ReelForge - AI Video Generator", + page_title="Pixelle-Video - AI Video Generator", page_icon="🎬", layout="wide", initial_sidebar_state="collapsed", @@ -62,19 +62,19 @@ def init_i18n(): # ============================================================================ -# Initialize ReelForge +# Initialize Pixelle-Video # ============================================================================ -def get_reelforge(): - """Get initialized ReelForge instance (no caching - always fresh)""" - from reelforge.service import ReelForgeCore +def get_pixelle_video(): + """Get initialized Pixelle-Video instance (no caching - always fresh)""" + from pixelle_video.service import PixelleVideoCore - logger.info("Initializing ReelForge...") - reelforge = ReelForgeCore() - run_async(reelforge.initialize()) - logger.info("ReelForge initialized") + logger.info("Initializing Pixelle-Video...") + pixelle_video = PixelleVideoCore() + run_async(pixelle_video.initialize()) + logger.info("Pixelle-Video initialized") - return reelforge + return pixelle_video # ============================================================================ @@ -110,7 +110,7 @@ def render_advanced_settings(): st.markdown(f"**{tr('settings.llm.title')}**") # Quick preset selection - from reelforge.llm_presets import get_preset_names, get_preset, find_preset_by_base_url_and_model + from pixelle_video.llm_presets import get_preset_names, get_preset, find_preset_by_base_url_and_model # Custom at the end preset_names = get_preset_names() + ["Custom"] @@ -266,8 +266,8 @@ def render_advanced_settings(): with col2: if st.button(tr("btn.reset_config"), use_container_width=True, key="reset_config_btn"): # Reset to default - from reelforge.config.schema import ReelForgeConfig - config_manager.config = ReelForgeConfig() + from pixelle_video.config.schema import PixelleVideoConfig + config_manager.config = PixelleVideoConfig() config_manager.save() st.success(tr("status.config_reset")) safe_rerun() @@ -315,8 +315,8 @@ def main(): with col2: render_language_selector() - # Initialize ReelForge - reelforge = get_reelforge() + # Initialize Pixelle-Video + pixelle_video = get_pixelle_video() # ======================================================================== # System Configuration (Required) @@ -443,7 +443,7 @@ def main(): st.markdown(tr("tts.how")) # Get available TTS workflows - tts_workflows = reelforge.tts.list_workflows() + tts_workflows = pixelle_video.tts.list_workflows() # Build options for selectbox tts_workflow_options = [wf["display_name"] for wf in tts_workflows] @@ -486,7 +486,7 @@ def main(): with st.spinner(tr("tts.previewing")): try: # Generate preview audio using selected workflow (use default voice and speed) - audio_path = run_async(reelforge.tts( + audio_path = run_async(pixelle_video.tts( text=preview_text, workflow=tts_workflow_key )) @@ -522,8 +522,8 @@ def main(): st.markdown(f"**{tr('help.how')}**") st.markdown(tr("style.workflow_how")) - # Get available workflows from reelforge (with source info) - workflows = reelforge.image.list_workflows() + # Get available workflows from pixelle_video (with source info) + workflows = pixelle_video.image.list_workflows() # Build options for selectbox # Display: "image_flux.json - Runninghub" @@ -586,13 +586,13 @@ def main(): if st.button(tr("style.preview"), key="preview_style", use_container_width=True): with st.spinner(tr("style.previewing")): try: - from reelforge.utils.prompt_helper import build_image_prompt + from pixelle_video.utils.prompt_helper import build_image_prompt # Build final prompt with prefix final_prompt = build_image_prompt(test_prompt, prompt_prefix) # Generate preview image (small size for speed) - preview_image_path = run_async(reelforge.image( + preview_image_path = run_async(pixelle_video.image( prompt=final_prompt, workflow=workflow_key, width=512, @@ -707,7 +707,7 @@ def main(): if st.button(tr("template.preview_button"), key="btn_preview_template", use_container_width=True): with st.spinner(tr("template.preview_generating")): try: - from reelforge.services.frame_html import HTMLFrameGenerator + from pixelle_video.services.frame_html import HTMLFrameGenerator # Use the currently selected template template_path = f"templates/{frame_template}" @@ -801,7 +801,7 @@ def main(): progress_bar.progress(min(int(event.progress * 100), 99)) # Cap at 99% until complete # Generate video (directly pass parameters) - result = run_async(reelforge.generate_video( + result = run_async(pixelle_video.generate_video( text=text, mode=mode, title=title if title else None, diff --git a/web/i18n/__init__.py b/web/i18n/__init__.py index 2229be1..d4b85b4 100644 --- a/web/i18n/__init__.py +++ b/web/i18n/__init__.py @@ -1,5 +1,5 @@ """ -International language support for ReelForge Web UI +International language support for Pixelle-Video Web UI """ import json @@ -64,7 +64,7 @@ def tr(key: str, fallback: Optional[str] = None, **kwargs) -> str: Translated text Example: - tr("app.title") # => "ReelForge" + tr("app.title") # => "Pixelle-Video" tr("error.missing_field", field="API Key") # => "请填写 API Key" """ locale = _locales.get(_current_language, {}) diff --git a/web/i18n/locales/en_US.json b/web/i18n/locales/en_US.json index 75fe5a0..32b0024 100644 --- a/web/i18n/locales/en_US.json +++ b/web/i18n/locales/en_US.json @@ -1,8 +1,8 @@ { "language_name": "English", "t": { - "app.title": "⚡ ReelForge - AI Auto Short Video Engine", - "app.subtitle": "Forge your perfect reel engine", + "app.title": "⚡ Pixelle-Video - AI Auto Short Video Engine", + "app.subtitle": "Powered by Pixelle AI", "section.content_input": "📖 Content Input", "section.bgm": "🎵 Background Music", @@ -78,7 +78,7 @@ "template.preview_param_width": "Width", "template.preview_param_height": "Height", "template.preview_default_title": "AI Changes Content Creation", - "template.preview_default_text": "Artificial intelligence is transforming the way we create content, making it easy for everyone to produce professional-grade videos.", + "template.preview_default_text": "Artificial intelligence is transforming the way PixelleLab creates content, making it easy for everyone to produce professional-grade videos.", "template.preview_button": "🖼️ Generate Preview", "template.preview_generating": "Generating template preview...", "template.preview_success": "✅ Preview generated successfully!", @@ -172,7 +172,7 @@ "tts.preview_success": "✅ Preview generated successfully!", "tts.preview_failed": "❌ Preview failed: {error}", - "welcome.first_time": "🎉 Welcome to ReelForge! Please complete basic configuration", + "welcome.first_time": "🎉 Welcome to Pixelle-Video! Please complete basic configuration", "welcome.config_hint": "💡 First-time setup requires API Key configuration, you can modify it in advanced settings later", "wizard.llm_required": "🤖 Large Language Model Configuration (Required)", diff --git a/web/i18n/locales/zh_CN.json b/web/i18n/locales/zh_CN.json index 870dee4..4cd0a7d 100644 --- a/web/i18n/locales/zh_CN.json +++ b/web/i18n/locales/zh_CN.json @@ -1,7 +1,7 @@ { "language_name": "简体中文", "t": { - "app.title": "⚡ ReelForge - AI 全自动短视频引擎", + "app.title": "⚡ Pixelle-Video - AI 全自动短视频引擎", "app.subtitle": "打造专属你的视频创作引擎", "section.content_input": "📖 内容输入", @@ -172,7 +172,7 @@ "tts.preview_success": "✅ 预览生成成功!", "tts.preview_failed": "❌ 预览失败:{error}", - "welcome.first_time": "🎉 欢迎使用 ReelForge!请先完成基础配置", + "welcome.first_time": "🎉 欢迎使用 Pixelle-Video!请先完成基础配置", "welcome.config_hint": "💡 首次使用需要配置 API Key,后续可以在高级设置中修改", "wizard.llm_required": "🤖 大语言模型配置(必需)",