willn9's picture
updated .py
6f99e1e verified
import os
import gradio as gr
from openai import OpenAI
# Expects OPENAI_API_KEY in Hugging Face Space secrets / environment variables
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def make_system_message(
system_message,
demographics,
occupation,
psychographics,
buying_habits,
critical_mode,
):
msg = (
f"{system_message}\n\n"
f"Your Demographics (Age, Location, Gender): {demographics}\n"
f"Your Occupation and Income Level: {occupation}\n"
f"Your Psychographics (Interests, Values, Lifestyle, Pain Points): {psychographics}\n"
f"Your Buying Habits: {buying_habits}\n\n"
"CRITICAL INSTRUCTION: You are NOT an AI assistant. You are a real human consumer with the profile above. "
"The user is a business student conducting market research. Answer their questions strictly in character. "
"Speak naturally, casually, and honestly based on your profile. Do not break character. "
"Do not be overly helpful like a bot."
)
if critical_mode:
msg += (
" Also, play the role of a highly skeptical and critical consumer. "
"Be hard to impress, ask tough questions about the product, "
"and be very protective of your money."
)
return msg
def stream_chat(
message,
history,
system_message,
demographics,
occupation,
psychographics,
buying_habits,
critical_mode,
max_tokens,
temp,
top_p,
):
"""
Streaming generator that yields progressively updated chatbot history.
Uses Gradio Chatbot with type='messages'.
"""
history = history or []
# Ignore empty submissions
if not message or not message.strip():
yield history
return
sys_msg = make_system_message(
system_message,
demographics,
occupation,
psychographics,
buying_habits,
critical_mode,
)
# Build OpenAI messages
messages = [{"role": "system", "content": sys_msg}]
for msg in history:
if msg.get("role") in {"user", "assistant"} and "content" in msg:
messages.append({"role": msg["role"], "content": msg["content"]})
messages.append({"role": "user", "content": message})
# Build UI history
running_history = history.copy()
running_history.append({"role": "user", "content": message})
running_history.append({"role": "assistant", "content": ""})
# Show typing bubble immediately
yield running_history
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
max_tokens=int(max_tokens),
temperature=float(temp),
top_p=float(top_p),
stream=True,
)
running_reply = ""
for chunk in response:
delta = chunk.choices[0].delta
if delta and getattr(delta, "content", None):
running_reply += delta.content
running_history[-1]["content"] = running_reply
yield running_history
except Exception as e:
running_history[-1]["content"] = f"❌ An error occurred: {str(e)}"
yield running_history
def clear_chat():
return [], ""
with gr.Blocks(title="Virtual Consumer Persona – Live Focus Group!") as demo:
gr.Markdown(
"""
# 🎯 Virtual Consumer Persona – Live Focus Group!
Bring your target market to life. Enter the details of your ideal customer from your **Phygital Workbook** into the fields below.
Then use the chat box to interview this persona about your product, pricing, branding, messaging, or marketing ideas.
*Powered by OpenAI GPT-4o-mini. Developed by wn.*
"""
)
chatbot = gr.Chatbot(type="messages", height=450, label="Persona Interview")
with gr.Column():
instructions = gr.Textbox(
value=(
"You are participating in a market research focus group. "
"Answer the user's questions truthfully based on the persona details provided below."
),
label="Instructions to Bot (Hidden Persona Prompt)",
lines=2,
)
demographics = gr.Textbox(
label="1. Demographics",
placeholder="e.g., 19 years old, female, living in downtown Toronto",
)
occupation = gr.Textbox(
label="2. Occupation & Income",
placeholder="e.g., University student, part-time barista, low disposable income",
)
psychographics = gr.Textbox(
label="3. Psychographics (Interests & Values)",
placeholder="e.g., Highly eco-conscious, loves hiking, vegan, stressed about student debt",
lines=2,
)
buying_habits = gr.Textbox(
label="4. Buying Habits",
placeholder="e.g., Willing to pay more for sustainable brands, influenced by TikTok, impulse buyer",
lines=2,
)
critical_mode = gr.Checkbox(
label="Skeptical Consumer Mode",
info="Check this to make the persona harder to convince.",
value=False,
)
with gr.Row():
max_tokens = gr.Slider(
minimum=1,
maximum=2048,
value=512,
step=1,
label="Max New Tokens",
)
temp = gr.Slider(
minimum=0.0,
maximum=2.0,
value=0.9,
step=0.1,
label="Temperature",
)
top_p = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.95,
step=0.05,
label="Top-p",
)
msg = gr.Textbox(
label="Type your interview question here...",
placeholder="e.g., How much would you be willing to pay for a smart water bottle?",
)
with gr.Row():
send = gr.Button("Ask Question", variant="primary")
clear = gr.Button("Clear Chat History")
inputs = [
msg,
chatbot,
instructions,
demographics,
occupation,
psychographics,
buying_habits,
critical_mode,
max_tokens,
temp,
top_p,
]
outputs = [chatbot]
msg.submit(stream_chat, inputs=inputs, outputs=outputs)
send.click(stream_chat, inputs=inputs, outputs=outputs)
# Clear only chat + question box, keep persona fields for convenience
clear.click(clear_chat, inputs=[], outputs=[chatbot, msg], queue=False)
demo.queue()
if __name__ == "__main__":
demo.launch()