|
| 1 | +import gradio as gr |
| 2 | +import json |
| 3 | +from openai import OpenAI |
| 4 | +import os |
| 5 | +import logging |
| 6 | +from dotenv import load_dotenv |
| 7 | +from src.json_2_video.json_2_video import PyJson2Video # Import the process_video function |
| 8 | +import asyncio |
| 9 | +import uuid |
| 10 | + |
| 11 | +logging.basicConfig(level=logging.INFO) |
| 12 | + |
| 13 | +load_dotenv() |
| 14 | + |
| 15 | +# Load the reference JSON |
| 16 | +with open('src/json_2_video/tests/json2video_template_clean.json', 'r') as f: |
| 17 | + reference_json = json.load(f) |
| 18 | + |
| 19 | +# Initialize the OpenAI client |
| 20 | +openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) |
| 21 | + |
| 22 | +def generate_from_json(json_input): |
| 23 | + try: |
| 24 | + output_filename = f"output_{uuid.uuid4()}.mp4" |
| 25 | + output_path = os.path.join(os.path.abspath("result"), output_filename) |
| 26 | + pyjson2video = PyJson2Video(json_input, output_path) |
| 27 | + output_path = asyncio.run(pyjson2video.convert()) |
| 28 | + return {"status": "success", "message": "Video generated successfully", "output_path": output_path} |
| 29 | + except Exception as e: |
| 30 | + return {"status": "error", "message": f"Error processing video: {str(e)}"} |
| 31 | + |
| 32 | +def generate_and_process_video(instructions): |
| 33 | + try: |
| 34 | + messages = [ |
| 35 | + {"role": "system", "content": f"""You are an AI assistant that generates JSON structures for video creation based on user instructions. Use the provided reference JSON as a template. Focus on the following key points: |
| 36 | + 1. Generate a script that is at least 100 words long. |
| 37 | + 2. Always synchronize image timings with the script by using dynamic references: |
| 38 | + - For start times: use ["script_id"].start_time or ["script_id"].voice_start_time |
| 39 | + - For end times: use ["script_id"].end_time or ["script_id"].voice_end_time |
| 40 | + 3. Ensure the JSON structure includes images, text, and script elements. |
| 41 | + Reference JSON structure for a video:\n\n{json.dumps(reference_json, indent=2)} |
| 42 | + """}, |
| 43 | + {"role": "user", "content": f"Please generate a similar JSON structure based on the following instructions:\n\n{instructions}"} |
| 44 | + ] |
| 45 | + |
| 46 | + response = openai.chat.completions.create( |
| 47 | + model="gpt-3.5-turbo-0125", |
| 48 | + messages=messages, |
| 49 | + max_tokens=2000, |
| 50 | + n=1, |
| 51 | + temperature=0.3, |
| 52 | + response_format={"type": "json_object"} # Ensure JSON response |
| 53 | + ) |
| 54 | + |
| 55 | + generated_json = json.loads(response.choices[0].message.content) |
| 56 | + verification = json_verification(generated_json) |
| 57 | + |
| 58 | + if verification["status"] == "corrected": |
| 59 | + generated_json = verification["data"] |
| 60 | + elif verification["status"] == "feedback": |
| 61 | + return None, verification["message"] |
| 62 | + |
| 63 | + output_filename = f"output_{uuid.uuid4()}.mp4" |
| 64 | + output_path = os.path.join(os.path.abspath("result"), output_filename) |
| 65 | + pyjson2video = PyJson2Video(generated_json, output_path) |
| 66 | + output_path = asyncio.run(pyjson2video.convert()) |
| 67 | + |
| 68 | + return {"status": "success", "message": "Video generated successfully", "output_path": output_path}, json.dumps(generated_json, indent=2) |
| 69 | + except Exception as e: |
| 70 | + return {"status": "error", "message": f"Error processing video: {str(e)}"}, None |
| 71 | + |
| 72 | +def json_verification(json_data): |
| 73 | + try: |
| 74 | + parsed_json = json.loads(json_data) if isinstance(json_data, str) else json_data |
| 75 | + verification_prompt = f""" |
| 76 | + Please verify the following JSON structure for a video creation template: |
| 77 | + 1. Ensure all required elements (images, text, script) are present. |
| 78 | + 2. Verify that the timing is correct and synchronized. |
| 79 | + 3. Check that image and text timings use script_id references (e.g., 'script_id.start_time', 'script_id.end_time') instead of hard-coded numbers. |
| 80 | + 4. Validate that the script is at least 100 words long. |
| 81 | + Reference JSON structure:\n{json.dumps(reference_json, indent=2)} |
| 82 | + JSON structure to verify:\n{json.dumps(parsed_json, indent=2)} |
| 83 | + """ |
| 84 | + |
| 85 | + verification = openai.chat.completions.create( |
| 86 | + model="gpt-3.5-turbo-0125", |
| 87 | + messages=[ |
| 88 | + {"role": "system", "content": "You are an AI assistant specialized in verifying JSON structures for video creation."}, |
| 89 | + {"role": "user", "content": verification_prompt} |
| 90 | + ], |
| 91 | + response_format={"type": "json_object"}, |
| 92 | + max_tokens=2000, |
| 93 | + n=1, |
| 94 | + temperature=0.3, |
| 95 | + ) |
| 96 | + |
| 97 | + verification_result = json.loads(verification.choices[0].message.content) |
| 98 | + |
| 99 | + if verification_result["status"] == "corrected": |
| 100 | + return {"status": "corrected", "message": "JSON structure corrected.", "data": verification_result["data"]} |
| 101 | + else: |
| 102 | + return {"status": "feedback", "message": verification_result["message"]} |
| 103 | + except json.JSONDecodeError: |
| 104 | + return {"status": "error", "message": "Error: Input is not valid JSON. Please provide a valid JSON structure."} |
| 105 | + except Exception as e: |
| 106 | + return {"status": "error", "message": f"Error during verification: {str(e)}"} |
| 107 | + |
| 108 | +def download_json_template(): |
| 109 | + return json.dumps(reference_json, indent=2) |
| 110 | + |
| 111 | +def process_result(result): |
| 112 | + if isinstance(result, str): |
| 113 | + try: |
| 114 | + result = eval(result) |
| 115 | + except: |
| 116 | + return {"status": "error", "message": result}, gr.update(visible=False), None |
| 117 | + |
| 118 | + if result["status"] == "success": |
| 119 | + output_message = f"Status: {result['status']}\nMessage: {result['message']}\nOutput Path: {result['output_path']}" |
| 120 | + return output_message, gr.update(visible=True), gr.update(value=result['output_path'], visible=True) |
| 121 | + else: |
| 122 | + return f"Status: {result['status']}\nMessage: {result['message']}", gr.update(visible=False), None |
| 123 | + |
| 124 | +# Update the Gradio interface |
| 125 | +with gr.Blocks() as iface: |
| 126 | + gr.Markdown("# Mind") |
| 127 | + gr.Markdown("Enter instructions for your video or provide a JSON structure directly. The AI will generate and process the video based on the input.") |
| 128 | + |
| 129 | + with gr.Tab("Text Instructions"): |
| 130 | + input_text = gr.Textbox(lines=5, label="Enter your video instructions") |
| 131 | + generate_button_text = gr.Button("Generate Video from Text", variant="primary") |
| 132 | + text_output = gr.Textbox(label="Result") |
| 133 | + video_output_text = gr.File(label="Download Generated Video", visible=False) |
| 134 | + json_output = gr.Textbox(label="JSON template or Error Message", lines=10) |
| 135 | + |
| 136 | + with gr.Tab("JSON Input"): |
| 137 | + json_input = gr.Textbox(lines=10, label="Enter your JSON structure directly") |
| 138 | + json_template = gr.File(label="JSON Template", file_count="single", file_types=[".json"]) |
| 139 | + generate_button_json = gr.Button("Generate Video from JSON", variant="primary") |
| 140 | + json_output_result = gr.Textbox(label="Result") |
| 141 | + video_output_json = gr.File(label="Download Generated Video", visible=False) |
| 142 | + |
| 143 | + generate_button_text.click( |
| 144 | + generate_and_process_video, |
| 145 | + inputs=[input_text], |
| 146 | + outputs=[text_output, json_output] |
| 147 | + ).then( |
| 148 | + process_result, |
| 149 | + inputs=text_output, |
| 150 | + outputs=[text_output, generate_button_text, video_output_text] |
| 151 | + ) |
| 152 | + |
| 153 | + generate_button_json.click( |
| 154 | + generate_from_json, |
| 155 | + inputs=[json_input], |
| 156 | + outputs=json_output_result |
| 157 | + ).then( |
| 158 | + process_result, |
| 159 | + inputs=json_output_result, |
| 160 | + outputs=[json_output_result, generate_button_json, video_output_json] |
| 161 | + ) |
| 162 | + |
| 163 | +# Launch the interface |
| 164 | +iface.launch() |
0 commit comments