Spaces:
Running
Running
| import os | |
| import sys | |
| import subprocess | |
| import importlib.util | |
| import uuid | |
| import json | |
| from datetime import datetime | |
| print("=" * 60) | |
| print("π STARTING VIDEO PROJECT MANAGER") | |
| print("=" * 60) | |
| # Function to check and install packages | |
| def ensure_package(package_name, import_name=None): | |
| if import_name is None: | |
| import_name = package_name | |
| if importlib.util.find_spec(import_name) is None: | |
| print(f"π¦ Installing {package_name}...") | |
| try: | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", package_name, "--quiet"]) | |
| print(f"β {package_name} installed successfully!") | |
| return True | |
| except Exception as e: | |
| print(f"β Failed to install {package_name}: {e}") | |
| return False | |
| else: | |
| print(f"β {package_name} already installed") | |
| return True | |
| # Install required packages | |
| ensure_package("gradio") | |
| ensure_package("supabase") | |
| ensure_package("python-dotenv") | |
| ensure_package("fastapi") | |
| ensure_package("uvicorn") | |
| # Now import after ensuring they're installed | |
| import gradio as gr | |
| from supabase import create_client | |
| from fastapi import FastAPI, Request | |
| from fastapi.responses import JSONResponse | |
| import uvicorn | |
| from threading import Thread | |
| import time | |
| print("\n" + "=" * 60) | |
| # ============================================= | |
| # SUPABASE CONNECTION | |
| # ============================================= | |
| SUPABASE_URL = os.environ.get("SUPABASE_URL") | |
| SUPABASE_KEY = os.environ.get("SUPABASE_KEY") | |
| print(f"\nπ§ Supabase Configuration:") | |
| print(f" URL: {'β Set' if SUPABASE_URL else 'β Missing'}") | |
| print(f" Key: {'β Set' if SUPABASE_KEY else 'β Missing'}") | |
| # Initialize Supabase client | |
| supabase = None | |
| if SUPABASE_URL and SUPABASE_KEY: | |
| try: | |
| supabase = create_client(SUPABASE_URL, SUPABASE_KEY) | |
| print("β Supabase client initialized successfully!") | |
| # Test connection | |
| try: | |
| test_result = supabase.table("projects").select("count", count="exact").limit(1).execute() | |
| print(f"β Database connected! Projects found: {test_result.count}") | |
| except Exception as e: | |
| print(f"β οΈ Database connection test failed: {e}") | |
| except Exception as e: | |
| print(f"β Failed to connect to Supabase: {e}") | |
| supabase = None | |
| else: | |
| print("β οΈ Supabase credentials missing - running in memory-only mode") | |
| # ============================================= | |
| # CORE FUNCTIONS | |
| # ============================================= | |
| def create_project(title, content, tags, image_prompt, channel): | |
| """Create a new project and save to Supabase""" | |
| print(f"\nπ Creating project: {title}") | |
| try: | |
| # Generate proper UUID | |
| project_id = str(uuid.uuid4()) | |
| folder_name = title.lower().replace(' ', '_').replace('/', '-')[:20] | |
| project_data = { | |
| "project_id": project_id, | |
| "folder_name": folder_name, | |
| "title": title, | |
| "content": content[:5000], | |
| "tags": tags, | |
| "image_prompt": image_prompt, | |
| "channel_details": channel, | |
| "status": "created", | |
| "created_at": datetime.now().isoformat() | |
| } | |
| print(f"πΎ Saving project with UUID: {project_id}") | |
| if supabase: | |
| result = supabase.table("projects").insert(project_data).execute() | |
| print(f"β Saved to database!") | |
| return { | |
| "status": "success", | |
| "project_id": project_id, | |
| "folder": folder_name, | |
| "title": title, | |
| "message": "Project created successfully in database!" | |
| } | |
| else: | |
| return { | |
| "status": "memory_only", | |
| "project_id": project_id, | |
| "folder": folder_name, | |
| "title": title, | |
| "message": "Project created in memory only (no database)" | |
| } | |
| except Exception as e: | |
| print(f"β Error: {e}") | |
| return {"status": "error", "message": str(e)} | |
| def search_projects(term): | |
| """Search for projects in Supabase""" | |
| print(f"\nπ Searching for: {term}") | |
| if not supabase: | |
| return [ | |
| ["Demo Project 1", "memory", datetime.now().strftime("%Y-%m-%d"), "demo_1"], | |
| ] | |
| try: | |
| if term and term.strip(): | |
| result = supabase.table("projects")\ | |
| .select("title, status, created_at, folder_name")\ | |
| .ilike("title", f"%{term}%")\ | |
| .limit(20)\ | |
| .execute() | |
| else: | |
| result = supabase.table("projects")\ | |
| .select("title, status, created_at, folder_name")\ | |
| .limit(20)\ | |
| .order("created_at", desc=True)\ | |
| .execute() | |
| projects = [] | |
| for p in result.data: | |
| created = p.get("created_at", "") | |
| if created and len(created) > 10: | |
| created = created[:10] | |
| projects.append([ | |
| p.get("title", "Untitled"), | |
| p.get("status", "unknown"), | |
| created, | |
| p.get("folder_name", "") | |
| ]) | |
| return projects if projects else [["No projects found", "", "", ""]] | |
| except Exception as e: | |
| print(f"β Search error: {e}") | |
| return [["Error", str(e)[:50], "", ""]] | |
| def health_check(): | |
| """Check system health""" | |
| return { | |
| "status": "healthy", | |
| "supabase_connected": bool(supabase), | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| # ============================================= | |
| # CREATE FASTAPI APP | |
| # ============================================= | |
| app = FastAPI() | |
| async def api_create(request: Request): | |
| """Direct API endpoint for creating projects""" | |
| try: | |
| data = await request.json() | |
| if "data" in data and len(data["data"]) >= 5: | |
| result = create_project( | |
| data["data"][0], | |
| data["data"][1], | |
| data["data"][2], | |
| data["data"][3], | |
| data["data"][4] | |
| ) | |
| return JSONResponse(content=result) | |
| else: | |
| return JSONResponse( | |
| status_code=400, | |
| content={"error": "Invalid data format. Expected: {\"data\": [title, content, tags, prompt, channel]}"} | |
| ) | |
| except Exception as e: | |
| return JSONResponse( | |
| status_code=500, | |
| content={"error": str(e)} | |
| ) | |
| async def api_health(): | |
| """Health check endpoint""" | |
| return JSONResponse(content=health_check()) | |
| async def api_search(request: Request): | |
| """Search endpoint""" | |
| try: | |
| data = await request.json() | |
| term = data.get("data", [""])[0] if data.get("data") else "" | |
| result = search_projects(term) | |
| return JSONResponse(content={"results": result}) | |
| except Exception as e: | |
| return JSONResponse( | |
| status_code=500, | |
| content={"error": str(e)} | |
| ) | |
| async def root(): | |
| """Root endpoint redirects to Gradio""" | |
| return {"message": "Video Project Manager API. Use /api/ endpoints. Access UI at /gradio"} | |
| # ============================================= | |
| # MOUNT GRADIO APP TO FASTAPI | |
| # ============================================= | |
| print("\nπ Creating Gradio interface...") | |
| with gr.Blocks(title="Video Project Manager") as demo: | |
| gr.Markdown("# π¬ Video Project Manager") | |
| if supabase: | |
| gr.Markdown("### β Connected to Supabase") | |
| else: | |
| gr.Markdown("### β οΈ Running in Memory Mode (No Database)") | |
| with gr.Tabs(): | |
| with gr.TabItem("π Create Project"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| title_input = gr.Textbox(label="Title", placeholder="Enter video title") | |
| content_input = gr.Textbox(label="Content", lines=3, placeholder="Enter TTS content") | |
| tags_input = gr.Textbox(label="Tags", placeholder="tag1, tag2, tag3") | |
| image_input = gr.Textbox(label="Image Prompt", lines=2, placeholder="Describe images") | |
| channel_input = gr.Textbox(label="Channel Details", value='{"platform": "youtube"}') | |
| create_btn = gr.Button("π Create Project", variant="primary") | |
| with gr.Column(): | |
| output = gr.JSON(label="Result") | |
| with gr.TabItem("π Search"): | |
| search_input = gr.Textbox(label="Search Term", placeholder="Enter search term") | |
| search_btn = gr.Button("π Search", variant="secondary") | |
| results = gr.Dataframe( | |
| headers=["Title", "Status", "Date", "Folder"], | |
| label="Search Results" | |
| ) | |
| with gr.TabItem("π API Info"): | |
| gr.Markdown(""" | |
| ## API Endpoints | |
| ### Create Project | |
| ```bash | |
| curl -X POST "https://yukee1992-video-project-manager.hf.space/api/create" \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{"data": ["Title", "Content", "tags", "prompt", "{}"]}' | |
| ``` | |
| ### Health Check | |
| ```bash | |
| curl -X POST "https://yukee1992-video-project-manager.hf.space/api/health" \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{}' | |
| ``` | |
| """) | |
| # Gradio event handlers | |
| create_btn.click( | |
| fn=create_project, | |
| inputs=[title_input, content_input, tags_input, image_input, channel_input], | |
| outputs=[output] | |
| ) | |
| search_btn.click( | |
| fn=search_projects, | |
| inputs=[search_input], | |
| outputs=[results] | |
| ) | |
| print("β Gradio interface created") | |
| # Mount Gradio app to FastAPI | |
| app = gr.mount_gradio_app(app, demo, path="/") | |
| # ============================================= | |
| # RUN | |
| # ============================================= | |
| if __name__ == "__main__": | |
| print("\n" + "=" * 60) | |
| print("π Starting server on port 7860...") | |
| print(" - UI: https://yukee1992-video-project-manager.hf.space") | |
| print(" - API: https://yukee1992-video-project-manager.hf.space/api/") | |
| print(" - Endpoints: /api/create, /api/health, /api/search") | |
| print("=" * 60) | |
| uvicorn.run(app, host="0.0.0.0", port=7860) |