import re import gradio as gr from openai import OpenAI from config import API_KEY, MODEL, SYSTEM_PROMPT, ENDPOINT, EXAMPLES, DEFAULT_LOCALE, DEFAULT_THEME client = OpenAI(api_key=API_KEY, base_url=ENDPOINT) react_imports = { "lucide-react": "https://esm.sh/lucide-react@0.525.0", "recharts": "https://esm.sh/recharts@3.1.0", "framer-motion": "https://esm.sh/framer-motion@12.23.6", "matter-js": "https://esm.sh/matter-js@0.20.0", "p5": "https://esm.sh/p5@2.0.3", "konva": "https://esm.sh/konva@9.3.22", "react-konva": "https://esm.sh/react-konva@19.0.7", "three": "https://esm.sh/three@0.178.0", "@react-three/fiber": "https://esm.sh/@react-three/fiber@9.2.0", "@react-three/drei": "https://esm.sh/@react-three/drei@10.5.2", "@tailwindcss/browser": "https://esm.sh/@tailwindcss/browser@4.1.11", "react": "https://esm.sh/react@^19.0.0", "react/": "https://esm.sh/react@^19.0.0/", "react-dom": "https://esm.sh/react-dom@^19.0.0", "react-dom/": "https://esm.sh/react-dom@^19.0.0/", "react-dom/client": "https://esm.sh/react-dom@^19.0.0/client" } class GradioEvents: @staticmethod def generate_code(input_value, system_prompt_input_value, state_value): def get_generated_files(text): patterns = { 'html': r'```html\n(.+?)\n```', 'jsx': r'```jsx\n(.+?)\n```', 'tsx': r'```tsx\n(.+?)\n```', } result = {} for ext, pattern in patterns.items(): matches = re.findall(pattern, text, re.DOTALL) if matches: content = '\n'.join(matches).strip() result[f'index.{ext}'] = content if len(result) == 0: result["index.html"] = text.strip() return result def process_react_imports(code): """Process React code to work with ES modules and import map""" # Remove export default and replace with const App processed_code = code.replace("export default", "const App =") # Process imports to use the import map import_lines = [] code_lines = [] for line in processed_code.split('\n'): line = line.strip() if line.startswith('import '): # Extract import statement import_lines.append(line) else: code_lines.append(line) # Combine processed imports and code if import_lines: processed_code = '\n'.join(import_lines) + '\n\n' + '\n'.join(code_lines) else: processed_code = '\n'.join(code_lines) return processed_code yield { empty_output: gr.update(visible=False), loading_output: gr.update(visible=True), sandbox: gr.update(visible=False), output: gr.update(value=None) } if input_value is None: input_value = '' messages = [{ 'role': "system", "content": SYSTEM_PROMPT # 'content': system_prompt_input_value }] + state_value["history"] messages.append({'role': "user", 'content': input_value}) generator = client.chat.completions.create(model=MODEL, messages=messages, stream=True) response = "" for chunk in generator: content = chunk.choices[0].delta.content if content is not None: response += content if chunk.choices[0].finish_reason == 'stop': state_value["history"] = messages + [{ 'role': "assistant", 'content': response }] generated_files = get_generated_files(response) react_code = generated_files.get( "index.tsx") or generated_files.get("index.jsx") html_code = generated_files.get("index.html") # Completed # Create HTML content for sandbox if react_code: # For React code, create a complete HTML page that renders React with ES modules processed_react_code = process_react_imports(react_code) escaped_react_code = processed_react_code.replace("`", "`").replace("'", "'") # Create import map from react_imports import_map = '{\n "imports": {\n' for package, url in react_imports.items(): import_map += f' "{package}": "{url}",\n' import_map = import_map.rstrip(',\n') + '\n }\n }' sandbox_content = f""" """ else: # For HTML code, just display it in iframe escaped_html_code = html_code.replace("'", "'") sandbox_content = f""" """ yield { output: gr.update(value=response), download_content: gr.update(value=react_code or html_code), empty_output: gr.update(visible=False), loading_output: gr.update(visible=False), sandbox: gr.update(value=sandbox_content, visible=True), download_btn: gr.update(interactive=True), state: gr.update(value=state_value) } else: # Generating yield { output: gr.update(value=response), } @staticmethod def select_example(example: dict): return lambda: gr.update(value=example["description"]) @staticmethod def toggle_visibility(visible_state): return gr.update(visible=not visible_state) @staticmethod def disable_btns(btns: list): return lambda: [gr.update(disabled=True) for _ in btns] @staticmethod def enable_btns(btns: list): return lambda: [gr.update(disabled=False) for _ in btns] @staticmethod def update_system_prompt(system_prompt_input_value, state_value): state_value["system_prompt"] = system_prompt_input_value return gr.update(value=state_value) @staticmethod def reset_system_prompt(state_value): return gr.update(value=state_value["system_prompt"]) @staticmethod def render_history(statue_value): return gr.update(value=statue_value["history"]) @staticmethod def clear_history(state_value): gr.Success("History Cleared.") state_value["history"] = [] return gr.update(value=state_value) css = """ .output-empty, .output-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; min-height: 680px; } .output-html { display: flex; flex-direction: column; width: 100%; min-height: 680px; max-height: 1200px; } .output-html > iframe { flex: 1; width: 100% !important; margin: 0 !important; padding: 0 !important; } .output-code { flex: 1; min-height: 100%; } .gradio-container { max-width: none !important; width: 100% !important; } """ with gr.Blocks(css=css, title="GPT5 Vibe Tester") as demo: # Global State state = gr.State({"system_prompt": "", "history": []}) # Header with gr.Row(): with gr.Column(): gr.HTML("""
Test your creative vibes with GPT5
Note: Test your vibes through interactive prototypes. The app supports multi-round dialogue to refine your ideas.
""") # Submit Button submit_btn = gr.Button( "Submit", variant="primary", size="lg", elem_id="submit-btn" ) # Settings gr.HTML("Enter your request to generate code
Please wait while I create your application