import os import sys import subprocess from pathlib import Path import gradio as gr # Clear proxy settings to avoid connection issues os.environ.pop('http_proxy', None) os.environ.pop('https_proxy', None) os.environ.pop('HTTP_PROXY', None) os.environ.pop('HTTPS_PROXY', None) # Add code directory to path current_dir = Path(__file__).parent # Use the improved generation method from generate_user_profile_final code_dir = current_dir / "generate_user_profile_final" / "code" sys.path.insert(0, str(code_dir)) # Import necessary modules from web_api_bridge import generate_profile_from_input def check_api_key(): """Check if API key is set""" api_key = os.environ.get("OPENAI_API_KEY") if not api_key: return False return True def generate_persona(age, gender, occupation, city, country, custom_values, custom_life_attitude, life_story, interests_hobbies, attribute_count): """Generate persona""" if not check_api_key(): return "❌ Error: OpenAI API key not set. Please add OPENAI_API_KEY in Hugging Face Space settings." # Build input data # Build location dict - only include if both city and country are provided location_dict = {} if city and city.strip() and country and country.strip(): location_dict = { "city": city.strip(), "country": country.strip() } input_data = { "basic_info": { "age": int(age) if age else None, "gender": gender.strip() if gender and gender.strip() else None, "occupation": {"status": occupation.strip()} if occupation and occupation.strip() else {}, "location": location_dict }, "custom_values": { "personal_values": custom_values.strip() if custom_values and custom_values.strip() else None, "life_attitude": custom_life_attitude.strip() if custom_life_attitude and custom_life_attitude.strip() else None, "life_story": life_story.strip() if life_story and life_story.strip() else None, "interests_hobbies": interests_hobbies.strip() if interests_hobbies and interests_hobbies.strip() else None } } # Generate persona with specified attribute count try: profile = generate_profile_from_input(input_data, attribute_count=int(attribute_count)) if "Summary" in profile: return profile["Summary"] else: return "❌ Error generating persona, could not get summary." except Exception as e: import traceback return f"❌ Error generating persona: {str(e)}\n{traceback.format_exc()}" # Custom CSS for better styling custom_css = """ body, html { background: white !important; min-height: 100vh; margin: 0 !important; padding: 0 !important; } /* Force all text to be dark and readable */ body, p, span, div, label, input, textarea, select { color: #222 !important; } /* Exception: keep white text on colored backgrounds */ .section-header, .section-header * { color: white !important; } .generate-btn, .generate-btn * { color: white !important; } .warning-box, .warning-box * { color: #856404 !important; } .info-box, .info-box * { color: #004085 !important; } .gradio-container { width: 100% !important; max-width: none !important; margin: 0 auto !important; background: transparent !important; padding: 0 20px !important; } .main { background: transparent !important; } /* Force all backgrounds to be light */ div, section, form, .app, .contain, .wrap { background: transparent !important; } /* Override Gradio's default dark theme */ .dark, [data-theme="dark"], .gradio-container.dark { background: transparent !important; } /* Force light background on root elements */ #root, .app, body > div { background: white !important; } /* Only keep white backgrounds for main columns */ .input-column, .output-column { background: rgba(255, 255, 255, 0.95) !important; } .header-text { text-align: center; color: #222 !important; font-size: 3.2em !important; font-weight: bold; margin-bottom: 0.2em; } .subtitle-text { text-align: center; color: #333; font-size: 1.5em; margin-bottom: 0.8em; } .section-header { background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white !important; padding: 12px 20px; border-radius: 8px; margin: 0 0 12px 0; font-weight: 700; font-size: 1.5em; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } /* h3 elements */ h3 { font-size: 1.8em !important; color: #333 !important; font-weight: 700 !important; } /* Ensure section headers inside h3 are visible */ h3 .section-header { display: inline-block; width: 100%; } .input-column { background: #f8f9fa; padding: 20px; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); border: 1px solid #e8e8e8; } .output-column { background: #f8f9fa; padding: 20px; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); border: 1px solid #e8e8e8; } .generate-btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border: none !important; color: white !important; font-size: 1.6em !important; font-weight: 600 !important; padding: 10px 20px !important; border-radius: 8px !important; margin-top: 8px !important; transition: transform 0.2s !important; width: 100% !important; } .generate-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4) !important; } .warning-box { background: rgba(255, 243, 205, 0.9); border-left: 4px solid #ffc107; padding: 8px; border-radius: 8px; margin: 8px 0; font-size: 1.2em; color: #856404; } .info-box { background: rgba(231, 243, 255, 0.9); border-left: 4px solid #2196F3; padding: 8px; border-radius: 8px; margin: 8px 0; font-size: 1.2em; color: #004085; } /* Adjust input field spacing */ .input-column label { margin-bottom: 4px !important; margin-top: 8px !important; font-size: 1.4em !important; color: #222 !important; font-weight: 600 !important; display: block !important; padding-top: 0px !important; } .input-column input, .input-column textarea, .input-column select { font-size: 1.0em !important; background: white !important; color: #333 !important; border: 1px solid #d0d0d0 !important; border-radius: 6px !important; padding: 8px 12px !important; margin-bottom: 0px !important; } /* Style for number inputs and dropdowns */ input[type="number"], select { background: white !important; color: #333 !important; border: 1px solid #d0d0d0 !important; font-size: 1.2em !important; } /* Remove special styling from dropdown */ .input-column select, .input-column .dropdown { border: 1px solid #e0e0e0 !important; box-shadow: none !important; } /* Dropdown container */ .input-column div[class*="dropdown"] { border: none !important; } /* Output text area */ .output-column textarea { background: white !important; color: #333 !important; border: 1px solid #d0d0d0 !important; border-radius: 6px !important; padding: 10px !important; margin-top: 0px !important; font-size: 1.1em !important; } /* Remove spacing in output column */ .output-column .block, .output-column .gr-form > div, .output-column [class*="field"] { padding: 0 !important; margin: 0 !important; } /* Output column label */ .output-column label { font-size: 1.2em !important; margin-bottom: 0px !important; } /* Placeholder text */ ::placeholder { color: #999 !important; } /* Remove ALL dark backgrounds from Gradio containers */ .input-column .block, .input-column .form, .input-column > div, .input-column div[class*="block"], .input-column div[class*="form"], .output-column .block, .output-column .form, .output-column > div, .output-column div[class*="block"], .output-column div[class*="form"] { background: transparent !important; border: none !important; box-shadow: none !important; } /* Target ALL row containers */ div[class*="gr-row"], .gr-row, .input-column .gr-row, .output-column .gr-row { background: transparent !important; border: none !important; padding: 0 !important; gap: 12px !important; margin: 0 !important; align-items: flex-start !important; } /* Ensure columns in rows align properly */ .input-column .gr-row > div { flex: 1 1 0 !important; min-width: 0 !important; } /* Remove padding from form containers */ div[class*="gr-form"], .gr-form, .input-column .gr-form { background: transparent !important; gap: 0px !important; margin: 0 !important; } /* Style for individual input containers */ div[class*="gr-box"], .gr-box, .input-column .gr-box { background: transparent !important; border: none !important; margin: 0 !important; padding: 0 !important; } /* Reduce padding in all Gradio field containers */ .input-column .gr-form > div, .input-column [class*="field"], .input-column .block { padding: 0 !important; margin: 0 !important; } /* Target specific Gradio component wrappers */ .input-column .wrap, .input-column .contain, .output-column .wrap, .output-column .contain { padding: 0 !important; margin: 0 !important; gap: 0 !important; } /* Minimize spacing between form fields */ .input-column > div > div > div { margin: 0 !important; padding: 0 !important; } /* Remove extra spacing from Gradio's internal divs */ .input-column div[data-testid], .input-column div[class*="svelte"] { padding: 0 !important; margin: 0 !important; } /* Column spacing in rows */ .input-column .gr-row > div { margin: 0 !important; padding: 0 2px !important; flex: 1 1 0 !important; min-width: 0 !important; } /* Ensure equal width for inputs in the same row */ .input-column .gr-row > div > div { width: 100% !important; } /* Make all inputs in rows have equal height */ .input-column .gr-row input, .input-column .gr-row select, .input-column .gr-row textarea { height: 42px !important; min-height: 42px !important; } /* Target container divs more aggressively */ .input-column > div > div, .output-column > div > div { background: transparent !important; } /* Specific fix for dropdown and number input containers */ .input-column label + div, .output-column label + div { background: transparent !important; border: none !important; } """ # Create Gradio interface with modern design with gr.Blocks( css=custom_css, title="DeepPersona - AI Character Generator", theme=gr.themes.Default(primary_hue="purple", secondary_hue="blue") ) as demo: # Header gr.Markdown("

🎭 DeepPersona

") gr.Markdown("

Generate Realistic AI Characters with Rich Personalities

") # Main Content with gr.Row(equal_height=True): # Left Column - Inputs with gr.Column(scale=2, elem_classes="input-column"): gr.Markdown("

👤 Basic Information

") with gr.Row(): age = gr.Number( label="Age", minimum=1, maximum=120, placeholder="25" ) gender = gr.Textbox( label="Gender", placeholder="Male, Female..." ) occupation = gr.Textbox( label="Occupation", placeholder="Software Engineer, Teacher, Artist..." ) with gr.Row(): city = gr.Textbox( label="City", placeholder="Mumbai, New York..." ) country = gr.Textbox( label="Country", placeholder="India, USA..." ) gr.Markdown("

✨ Custom Values (Optional)

") custom_values = gr.Textbox( label="Personal Values", lines=2, placeholder="Values family, creativity, continuous learning..." ) custom_life_attitude = gr.Textbox( label="Life Attitude", lines=2, placeholder="Optimistic and solution-oriented..." ) life_story = gr.Textbox( label="Life Story", lines=2, placeholder="Born in a small town, moved to the city for education..." ) interests_hobbies = gr.Textbox( label="Interests and Hobbies", lines=2, placeholder="Reading, hiking, photography, cooking..." ) gr.Markdown("

⚙️ Advanced Settings

") attribute_count = gr.Slider( minimum=100, maximum=350, value=200, step=50, label="Attribute Richness" ) # Right Column - Output with gr.Column(scale=3, elem_classes="output-column"): gr.Markdown("

📝 Generated Character Profile

") output = gr.Textbox( label="", lines=30, placeholder="Your generated character profile will appear here...\n\nClick 'Generate Character Profile' to start!", show_label=False, container=False ) # Generate Button - Full Width generate_btn = gr.Button( "🚀 Generate Character Profile", variant="primary", size="lg", elem_classes="generate-btn" ) # Footer gr.Markdown( """

🌐 Project Homepage | 📊 Dataset | 💻 GitHub

Powered by GPT-4.1-mini • Built with ❤️ by DeepPersona Team

""" ) # Event Handler generate_btn.click( fn=generate_persona, inputs=[age, gender, occupation, city, country, custom_values, custom_life_attitude, life_story, interests_hobbies, attribute_count], outputs=output ) # Launch application if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)