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() @app.post("/api/create") 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)} ) @app.post("/api/health") async def api_health(): """Health check endpoint""" return JSONResponse(content=health_check()) @app.post("/api/search") 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)} ) @app.get("/") 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)