Spaces:
Sleeping
Sleeping
File size: 10,749 Bytes
757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f f4384d6 757671f 9d4945e 757671f e77124a 757671f e77124a 757671f 7b0cf58 757671f 7b0cf58 757671f c26abff 7b0cf58 c26abff 9d4945e 536c044 9d4945e 536c044 9d4945e 536c044 9d4945e 757671f c26abff 7b0cf58 50a14be 7b0cf58 536c044 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | import json
from typing import List, Dict
from pydantic import BaseModel
from concurrent.futures import ThreadPoolExecutor
from utils import call_llm
LLM_MODEL = "gpt-4o-mini"
def generate_user_parameters(audience: str, scope: str) -> List[str]:
standard_parameters = ["Name", "Age", "Location", "Profession"]
prompt = f"""
You are an expert customer researcher.
Your task is to help define user personas for a specific audience and a specific research scope.
This is the desired audience: {audience}
This is the research scope: {scope}
Start from the following 4 standard demographic parameters: {standard_parameters}
Your goal is to suggest 4 additional parameters that are especially relevant for capturing behaviors, attitudes, or characteristics important for this audience and scope.
Only suggest parameters that will meaningfully help differentiate users in this specific context. The parameters should be tailored for the audience and scope but also not too specific.
"""
class Response(BaseModel):
additional_parameters: list[str]
response = call_llm(prompt=prompt, response_format=Response)
additional_parameters = json.loads(response)["additional_parameters"]
return standard_parameters + additional_parameters
def generate_synthetic_personas(parameters: List[str], num_personas: int, audience: str, batch_size: int = 10) -> Dict:
"""
Generate synthetic personas in batches, ensuring variability by considering previously generated personas.
Args:
parameters: List of parameters to include in each persona
num_personas: Total number of personas to generate
audience: Target audience for the personas
batch_size: Number of personas to generate in each batch
Returns:
Dictionary containing the list of generated personas
"""
all_personas = []
remaining_personas = num_personas
while remaining_personas > 0:
current_batch_size = min(batch_size, remaining_personas)
# Create context about previously generated personas
previous_personas_context = ""
if all_personas:
previous_personas_context = "\nAs a context, here are the previously generated personas:\n"
for i, persona in enumerate(all_personas, 1):
previous_personas_context += f"\nPersona {i}:\n"
for param, value in persona.items():
previous_personas_context += f"{param}: {value}\n"
prompt = f"""
You are an expert in user persona creation.
Generate {current_batch_size} diversified user personas based on the following parameters:
{parameters}
Each persona should be unique and realistic, ensure variability. Take into account that the desired audience is the following: {audience}.
{previous_personas_context}
Important requirements:
1. Each new persona should be significantly different from the previously generated ones
2. Ensure diversity in all parameters, especially in key demographic factors
3. Avoid creating personas that are too similar to existing ones
4. Make sure the personas are realistic and representative of the target audience
5. Ensure the list contains exactly {current_batch_size} personas
"""
class Parameter(BaseModel):
parameter_name: str
value: str
class User(BaseModel):
user_persona: list[Parameter]
class Response(BaseModel):
users_personas: list[User]
response = call_llm(prompt=prompt, response_format=Response)
response = json.loads(response)
# Transform the response and add to all personas
batch_personas = [
{item["parameter_name"]: item["value"] for item in user["user_persona"]}
for user in response["users_personas"]
]
all_personas.extend(batch_personas)
remaining_personas -= current_batch_size
return {"users_personas": all_personas}
def ask_questions_to_persona(persona: dict, questions: List[str]) -> List[str]:
def ask_single_question(question: str) -> str:
prompt = f"""
Act as if you were this user persona:
{persona}
You need to impersonate this user persona and answer the following question as if you were that user:
{question}
Never sart the sentences in the following way: As "name of the person"...
Try to sound natural and authentic, as if you were the user persona.
Make sure to answer the question in a way that is relevant to the user persona.
"""
return call_llm(prompt, False)
max_workers = min(8, len(questions))
with ThreadPoolExecutor(max_workers=max_workers) as executor:
answers = list(executor.map(ask_single_question, questions))
return answers
def generate_fleet(n: int, parameters: Dict, questions: List[str], audience: str) -> List[Dict]:
users_personas = generate_synthetic_personas(parameters=parameters, num_personas=n, audience=audience)["users_personas"]
return generate_fleet_from_users(users_personas=users_personas, questions=questions)
def generate_fleet_from_users(users_personas: Dict, questions: List[str]) -> List[Dict]:
fleet = []
for persona_dict in users_personas:
answers = ask_questions_to_persona(persona_dict, questions)
persona_dict["answers"] = answers
fleet.append(persona_dict)
return fleet
def generate_content(fleet,questions=None,scope=None) -> str:
content = ""
if scope:
content += f"Scope of Research:\n{scope}\n\n"
if questions:
content += "Questions:\n"
for i, question in enumerate(questions, 1):
content += f"Q{i}: {question}\n"
content += "\n"
for i, user in enumerate(fleet, 1):
content += f"### User {i} ###\n"
for key, value in user.items():
if key != "answers":
content += f"{key}: {value}\n"
content += "\n"
for j, answer in enumerate(user.get("answers", []), 1):
content += f"Q{j}: {answer}\n\n"
content += "\n---\n\n"
return content
def generate_report(questions,fleet,scope) -> str:
content=generate_content(questions=questions,fleet=fleet,scope=scope)
prompt = f"""
You are an expert in customer and market research. Your task is to write a research report based on the following interviews:
{content}
You have to follow the following scope of research:
{scope}
The report should be structured and include the following sections:
- Introduction: describe the purpose of the research and the audience.
- Methodology: describe how the interviews were conducted.
- Demography: summarize the personas that were interviewed. Add also some examples of the users that were interviewed.
- Findings: summarize the key insights and themes that emerged from the interviews focusing on the scope of research. If possible and relevant, include quotes from the interviews to support your findings.
- Insights: summarize the key insights and themes that emerged from the interviews going beyond the scope of research. Be creative and think outside the box analysing trends and patterns. If possible and relevant, include quotes from the interviews to support your insights.
- Conclusion: summarize the main findings and their implications.
- Recommendations: provide actionable recommendations based on the findings and insights.
- Improvements: suggest improvements for the research process and the interview questions.
"""
report_text = call_llm(prompt, False)
return report_text
def chat_with_persona(persona: dict, question: str, conversation_history: List[dict] = None) -> str:
"""
Chat with a specific persona, taking into account conversation history if provided.
Args:
persona: The user persona to chat with
question: The current question to ask
conversation_history: List of previous Q&A pairs, if any
Returns:
The persona's answer to the question
"""
history_context = ""
if conversation_history:
history_context = "\nPrevious conversation:\n"
for chat in conversation_history:
history_context += f"Q: {chat['question']}\n"
history_context += f"A: {chat['answer']}\n"
prompt = f"""
Act as if you were this user persona:
{persona}
You need to impersonate this user persona and answer the following question as if you were that user:
{question}
Never start the sentences in the following way: As "name of the person"...
Try to sound natural and authentic, as if you were the user persona.
Make sure to answer the question in a way that is relevant to the user persona and consistent with any previous conversation.
"""
if conversation_history:
prompt += f"\nPrevious conversation:\n{history_context}"
return call_llm(prompt)
def chat_with_report(users: List[dict], question: str, questions: List[str]) -> str:
"""
Chat with the content of a report, using the provided users' data.
Args:
users: List of user personas with their answers (fleet)
question: The question to ask about the report content
questions: List of questions that were asked to the users
Returns:
The answer based on the report content
"""
# Generate the content string that would be used in the report
content = generate_content(fleet=users, questions=questions)
prompt = f"""
You are an expert in customer and market research. You have access to the following interview data:
{content}
You need to answer the following question based on the interview data:
{question}
Provide a detailed answer that synthesizes the information from the interviews.
If relevant, include specific examples or quotes from the interviews to support your answer.
Make sure your response is well-structured and professional.
If the question is not relevant to the interview data, please say that you cannot answer it based on the provided information.
"""
return call_llm(prompt)
def generate_audience_name(audience: str, scope: str) -> str:
"""
Generate a concise, descriptive name for the audience based on the research scope.
Args:
audience: The target audience description
scope: The research scope
Returns:
A concise, descriptive name for the audience
"""
prompt = f"""
You are an expert in creating concise, descriptive names for research audiences.
Given the following audience and research scope:
Audience: {audience}
Scope: {scope}
Create a very concise name (max one sentence) that captures the essence of this audience for the given scope.
Respond with ONLY the name, nothing else.
"""
return call_llm(prompt, False).strip() |