Yufan_Zhou
Update footer text to show correct model name (GPT-4.1-mini)
de4ba6a
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("<h1 class='header-text'>🎭 DeepPersona</h1>")
gr.Markdown("<p class='subtitle-text'>Generate Realistic AI Characters with Rich Personalities</p>")
# Main Content
with gr.Row(equal_height=True):
# Left Column - Inputs
with gr.Column(scale=2, elem_classes="input-column"):
gr.Markdown("<h3 class='section-header'>πŸ‘€ Basic Information</h3>")
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("<h3 class='section-header'>✨ Custom Values (Optional)</h3>")
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("<h3 class='section-header'>βš™οΈ Advanced Settings</h3>")
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("<h3 class='section-header'>πŸ“ Generated Character Profile</h3>")
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(
"""
<div style='text-align: center; margin-top: 30px; padding: 20px; background: rgba(255, 255, 255, 0.9); border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);'>
<p style='color: #555; margin: 5px 0;'>
🌐 <a href='https://thzva.github.io/deeppersona.github.io/' target='_blank' style='color: #667eea; text-decoration: none; font-weight: 500;'>Project Homepage</a> |
πŸ“Š <a href='https://huggingface.co/datasets/THzva/deeppersona_dataset' target='_blank' style='color: #667eea; text-decoration: none; font-weight: 500;'>Dataset</a> |
πŸ’» <a href='https://github.com/thzva/Deeppersona' target='_blank' style='color: #667eea; text-decoration: none; font-weight: 500;'>GitHub</a>
</p>
<p style='color: #888; font-size: 0.9em; margin-top: 10px;'>
Powered by GPT-4.1-mini β€’ Built with ❀️ by DeepPersona Team
</p>
</div>
"""
)
# 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)