From 3f59b324ad0b8c5c35b7fc7db1a16f5a1b842c2b Mon Sep 17 00:00:00 2001 From: empty Date: Sat, 10 Jan 2026 16:13:02 +0800 Subject: [PATCH] fix: Remove hardcoded ports, support custom port configuration - Replace all hardcoded localhost:8000/3000/8501 with environment variables - Frontend: Use API_PORT env var in next.config.ts - Backend: Use API_PORT env var in editor.py and quality.py - Web UI: Use API_PORT and EDITOR_PORT env vars in all Streamlit pages - Update dev.sh to pass environment variables to all services - Add .env.example with port configuration template Now supports custom ports via environment variables: API_PORT=8080 EDITOR_PORT=3001 WEB_PORT=8502 ./dev.sh Co-Authored-By: Claude Sonnet 4.5 --- .env.example | 21 +++++++++++++++++++++ api/routers/editor.py | 22 +++++++++++++++------- api/routers/quality.py | 5 +++-- dev.sh | 6 +++--- frontend/next.config.ts | 3 ++- web/components/output_preview.py | 8 ++++++-- web/pages/2_📚_History.py | 5 ++++- web/pages/3_📋_Tasks.py | 9 +++++++-- 8 files changed, 61 insertions(+), 18 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e7cb624 --- /dev/null +++ b/.env.example @@ -0,0 +1,21 @@ +# Pixelle-Video Environment Configuration +# Copy this file to .env and customize as needed + +# ============================================================================ +# Port Configuration +# ============================================================================ + +# FastAPI Backend Port +API_PORT=8000 + +# Next.js Editor Port +EDITOR_PORT=3000 + +# Streamlit Web UI Port +WEB_PORT=8501 + +# ============================================================================ +# Other Configuration +# ============================================================================ + +# Add other environment variables here as needed diff --git a/api/routers/editor.py b/api/routers/editor.py index d80059f..9022ead 100644 --- a/api/routers/editor.py +++ b/api/routers/editor.py @@ -47,24 +47,31 @@ from api.schemas.editor import ( from fastapi import BackgroundTasks import asyncio import uuid as uuid_module +import os router = APIRouter(prefix="/editor", tags=["Editor"]) # Export task storage _export_tasks: dict = {} +# Get API port from environment +API_PORT = os.getenv("API_PORT", "8000") -def _path_to_url(file_path: str, base_url: str = "http://localhost:8000") -> str: + +def _path_to_url(file_path: str, base_url: str = None) -> str: """Convert local file path to URL accessible through API""" if not file_path: return None - + + if base_url is None: + base_url = f"http://localhost:{API_PORT}" + import os from pathlib import Path - + # Normalize path separators file_path = file_path.replace("\\", "/") - + # Extract relative path from output directory parts = file_path.split("/") try: @@ -73,7 +80,7 @@ def _path_to_url(file_path: str, base_url: str = "http://localhost:8000") -> str relative_path = "/".join(relative_parts) except ValueError: relative_path = Path(file_path).name - + return f"{base_url}/api/files/{relative_path}" @@ -951,8 +958,9 @@ async def export_video( for frame in sorted_frames: path = frame.get("video_segment_path", "") if path.startswith("http"): - # Extract path from URL - path = path.replace("http://localhost:8000/api/files/", "output/") + # Extract path from URL (format: http://localhost:{port}/api/files/{relative_path}) + if "/api/files/" in path: + path = "output/" + path.split("/api/files/")[-1] video_segments.append(path) _export_tasks[task_id]["progress"] = 0.3 diff --git a/api/routers/quality.py b/api/routers/quality.py index b144128..ee83d83 100644 --- a/api/routers/quality.py +++ b/api/routers/quality.py @@ -349,8 +349,9 @@ async def extract_style( # Convert URL to file path if needed actual_path = image_path if image_path.startswith("http"): - # Extract path from URL like http://localhost:8000/api/files/... - actual_path = image_path.replace("http://localhost:8000/api/files/", "output/") + # Extract path from URL (format: http://localhost:{port}/api/files/{relative_path}) + if "/api/files/" in image_path: + actual_path = "output/" + image_path.split("/api/files/")[-1] # Check if file exists import os diff --git a/dev.sh b/dev.sh index 55c83b3..028b32f 100755 --- a/dev.sh +++ b/dev.sh @@ -54,7 +54,7 @@ print_banner() { start_api() { echo -e "${GREEN}🚀 Starting FastAPI Backend...${NC}" - uv run python api/app.py --port $API_PORT --reload & + API_PORT=$API_PORT uv run python api/app.py --port $API_PORT --reload & echo $! > "$PID_DIR/api.pid" echo -e " ${GREEN}✓${NC} API running at: ${YELLOW}http://localhost:$API_PORT${NC}" echo -e " ${GREEN}✓${NC} API Docs at: ${YELLOW}http://localhost:$API_PORT/docs${NC}" @@ -63,7 +63,7 @@ start_api() { start_editor() { echo -e "${GREEN}🎬 Starting Next.js Editor...${NC}" cd "$PROJECT_ROOT/frontend" - PORT=$EDITOR_PORT npm run dev & + API_PORT=$API_PORT PORT=$EDITOR_PORT npm run dev & echo $! > "$PID_DIR/editor.pid" cd "$PROJECT_ROOT" echo -e " ${GREEN}✓${NC} Editor running at: ${YELLOW}http://localhost:$EDITOR_PORT${NC}" @@ -71,7 +71,7 @@ start_editor() { start_web() { echo -e "${GREEN}🌐 Starting Streamlit Web UI...${NC}" - uv run streamlit run web/app.py --server.port $WEB_PORT & + API_PORT=$API_PORT EDITOR_PORT=$EDITOR_PORT uv run streamlit run web/app.py --server.port $WEB_PORT & echo $! > "$PID_DIR/web.pid" echo -e " ${GREEN}✓${NC} Web UI running at: ${YELLOW}http://localhost:$WEB_PORT${NC}" } diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 77b8708..bb744a0 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -2,10 +2,11 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { async rewrites() { + const apiPort = process.env.API_PORT || '8000'; return [ { source: '/api/:path*', - destination: 'http://localhost:8000/api/:path*', + destination: `http://localhost:${apiPort}/api/:path*`, }, ] }, diff --git a/web/components/output_preview.py b/web/components/output_preview.py index d4a0fc5..5221040 100644 --- a/web/components/output_preview.py +++ b/web/components/output_preview.py @@ -26,6 +26,10 @@ from web.utils.async_helpers import run_async from pixelle_video.models.progress import ProgressEvent from pixelle_video.config import config_manager +# Get ports from environment +API_PORT = os.getenv("API_PORT", "8000") +EDITOR_PORT = os.getenv("EDITOR_PORT", "3000") + def render_output_preview(pixelle_video, video_params): """Render output preview section (right column)""" @@ -135,7 +139,7 @@ def render_single_output(pixelle_video, video_params): # Submit to async API response = requests.post( - "http://localhost:8000/api/video/generate/async", + f"http://localhost:{API_PORT}/api/video/generate/async", json=api_payload, timeout=30 ) @@ -309,7 +313,7 @@ def render_single_output(pixelle_video, video_params): pass if task_id: - editor_url = f"http://localhost:3000/editor?storyboard_id={task_id}" + editor_url = f"http://localhost:{EDITOR_PORT}/editor?storyboard_id={task_id}" st.markdown( f''' diff --git a/web/pages/2_📚_History.py b/web/pages/2_📚_History.py index f619b65..30e32f8 100644 --- a/web/pages/2_📚_History.py +++ b/web/pages/2_📚_History.py @@ -33,6 +33,9 @@ from web.components.header import render_header from web.i18n import tr from web.utils.async_helpers import run_async +# Get ports from environment +EDITOR_PORT = os.getenv("EDITOR_PORT", "3000") + # Page config st.set_page_config( page_title="History - Pixelle-Video", @@ -363,7 +366,7 @@ def render_task_detail_modal(task_id: str, pixelle_video): ) # Open in Editor button - editor_url = f"http://localhost:3000/editor?storyboard_id={task_id}" + editor_url = f"http://localhost:{EDITOR_PORT}/editor?storyboard_id={task_id}" st.markdown( f''' diff --git a/web/pages/3_📋_Tasks.py b/web/pages/3_📋_Tasks.py index 956970b..3eaad08 100644 --- a/web/pages/3_📋_Tasks.py +++ b/web/pages/3_📋_Tasks.py @@ -22,6 +22,7 @@ Features: import streamlit as st import requests import time +import os from datetime import datetime from web.i18n import tr, get_language @@ -33,8 +34,12 @@ st.set_page_config( layout="wide", ) +# Get ports from environment +API_PORT = os.getenv("API_PORT", "8000") +EDITOR_PORT = os.getenv("EDITOR_PORT", "3000") + # API endpoint -API_BASE = "http://localhost:8000/api" +API_BASE = f"http://localhost:{API_PORT}/api" def get_all_tasks(): @@ -183,7 +188,7 @@ def render_task_card(task): with col_a: st.success("✨ 视频生成成功") with col_b: - editor_url = f"http://localhost:3000/editor?storyboard_id={task_id}" + editor_url = f"http://localhost:{EDITOR_PORT}/editor?storyboard_id={task_id}" st.markdown( f'''