import gradio as gr import random import time import os import re import time import openai # Set up OpenAI API key #valapikey = "" system_message = "You are an assistant simulating the behavior of the participants in a focus group and answer a set of questions. Your first task will be to generate the profiles of the focus group then to simulate their answers to the question for each member." with gr.Blocks() as demo: with gr.Row(): gr.Markdown("Author: Taeko Sakai") with gr.Row(): gr.Markdown("This application generates a focus group to answer your questions.\nFirst, list your topic and questions, then generate the focus group profile, finally get their answers and access the summary report") with gr.Row(): gr.Markdown("DISCLAIMER: The content generated will be depending on the input you integrated in the respective fields and the behavior of the large language model (GPT4) used for the text generation.") with gr.Row(visible = True) as apicheck: with gr.Column(scale = 6): apikey = gr.Textbox(label='Paste here your OpenAI - API key', info='No API key is stored and only you will see it.', lines = 1) with gr.Column(scale = 1): useapi = gr.Button("Use this API key") with gr.Row(): language = gr.Textbox(label='Input your language for the results', lines = 1, value = 'English') with gr.Row(visible = False) as fullblock: with gr.Tab("Enquiry Description"): with gr.Row(): gr.Markdown("Describe your project or study") with gr.Row(): title = gr.Textbox(label='Topic you would like to submit to your focus group', lines = 5, placeholder = "ex: Ice cream tastes or smartphone features") with gr.Row(): gr.Markdown("List all your questions") with gr.Row(): question1 = gr.Textbox(label="Question 1", lines=2, placeholder = "ex: What are your favorite features for a smartphone?") with gr.Row(): question2 = gr.Textbox(label="Question 2", lines=2, placeholder = "ex: How much would you be willing to pay for x, y , z (in USD)?") with gr.Row(): question3 = gr.Textbox(label="Question 3", lines=2, placeholder = "ex: If you had no budget limit, what would be your dream functionality for a smartphone?") with gr.Tab("Focus Group Profiles Generation"): with gr.Row(): gr.Markdown("Describe types of profiles you want in your focus group") with gr.Row(): focusgroupdescription = gr.Textbox(label="Describe your focus group desired characteristics", info= "For example: women in their 30s, teenagers, mixed ethnicity from Vietnam, ...", lines=5) with gr.Row(): generategroup = gr.Button("Generate my focus group") with gr.Row(): gr.Markdown("Participants") with gr.Row(): expert1 = gr.Textbox(label="Participant 1", lines=5) expert2 = gr.Textbox(label="Participant 2", lines=5) with gr.Row(): expert3 = gr.Textbox(label="Participant 3", lines=5) expert4 = gr.Textbox(label="Participant 4", lines=5) with gr.Row(): expert5 = gr.Textbox(label="Participant 5", lines=5) expert6 = gr.Textbox(label="Participant 6", lines=5) with gr.Row(): expert7 = gr.Textbox(label="Participant 7", lines=5) expert8 = gr.Textbox(label="Participant 8", lines=5) with gr.Row(): expert9 = gr.Textbox(label="Participant 9", lines=5) expert10 = gr.Textbox(label="Participant 10", lines=5) with gr.Tab("Results"): with gr.Row(): generateresults = gr.Button("Generate focus group answers") with gr.Row(): gr.Markdown("Responses from the focus group participants") with gr.Row(): response1 = gr.Textbox(label="Response 1", lines=10) response2 = gr.Textbox(label="Response 2", lines=10) with gr.Row(): response3 = gr.Textbox(label="Response 3", lines=10) response4 = gr.Textbox(label="Response 4", lines=10) with gr.Row(): response5 = gr.Textbox(label="Response 5", lines=10) response6 = gr.Textbox(label="Response 6", lines=10) with gr.Row(): response7 = gr.Textbox(label="Response 7", lines=10) response8 = gr.Textbox(label="Response 8", lines=10) with gr.Row(): response9 = gr.Textbox(label="Response 9", lines=10) response10 = gr.Textbox(label="Response 10", lines=10) with gr.Tab("Summary"): with gr.Row(): generatesummary = gr.Button("Generate the focus group summary") with gr.Row(): summary = gr.Textbox(label="Report summary", lines=50) with gr.Row(): with gr.Accordion("Restore", open = False): restore = gr.Button("Restore data from report") clear = gr.Button("Clear", visible = False) def uploaddetailsfromreport(report): # Extract title title = re.search(r'which title is:(.+)\n', report).group(1) # Extract questions from summary report questions = re.findall(r'Question \d: (.+)', report)[:3] # Extract participant profiles and answers participant_profiles = re.findall(r'// Profile (\d+) //\n(.+?)\n={10}', report, re.DOTALL) participant_answers = re.findall(r'Participant answers:\n(.+?)\-{5}', report, re.DOTALL) # Combine all the extracted values output = [title] + questions for (profile_num, profile), answer in zip(participant_profiles, participant_answers): output.append(profile_num) output.append(profile.strip()) output.append(answer.strip()) #print(output) return output[0], output[1], output[2], output[3], output[5], output[8], output[11], output[14], output[17], output[20], output[23], output[26], output[29], output[32], output[6], output[9], output[12], output[15], output[18], output[21], output[24], output[27], output[30], output[33] def checkapiinput(apikey): if apikey != "" and apikey is not None and len(apikey) >=25 and len(apikey) <= 130: OPENAI_API_KEY =apikey openai.api_key = OPENAI_API_KEY return gr.update(visible=True), gr.update(visible=False), gr.update(visible=True), gr.update(visible=True) else: return gr.update(visible=False), gr.update(visible=True), gr.update(value="", placeholder="Use a valid API key"), gr.update(visible=False) def summarize(title, language, question1, question2, question3, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10, response1, response2, response3, response4, response5, response6, response7, response8, response9, response10): prompt = f""" You are asked to make a report summarizing the inputs from 10 participants from a focus groups on this topic: {title} The questions asked were: Question 1: {question1} Question 2: {question2} Question 3: {question3} The profiles and their answers are: Profile 1: {expert1} Participant answers: {response1} ===================== Profile 2: {expert2} Participant answers: {response2} ===================== Profile 3: {expert3} Participant answers: {response3} ===================== Profile {expert4} Participant answers: {response4} ===================== Profile 5: {expert5} Participant answers: {response5} ===================== Profile 6: {expert6} Participant answers: {response6} ===================== Profile 7: {expert7} Participant answers: {response7} ===================== Profile 8: {expert8} Participant answers: {response8} ===================== Profile 9: {expert9} Participant answers: {response9} ===================== Profile 10: {expert10} Participant answers: {response10} Follow these rules: - Combine each points from the participants answers per question, start with 'Question 1:' and repeat the question then provide the arguments brought by the participants below. Then do the same for Question 2 and Question 3 - Provide all the arguments brought by the participants per question, breaking down the nuance per demographic or profession or any social / profiling category you see fit - Keep all the points raised by the participants with details, break them down in a rational and professional way - do not loose details. - For each question, provide a recommendation for action to address the needs expressed in the answers for each question, start it with "Recommendation:" then add your prespecriptions on bullet points just asfter Now please provide your summary and recommendations for each of the questions using the following language: {language} """ formattedprompt = [{'role':'system','content':system_message},{'role':'user','content':prompt}] result = answer(formattedprompt, "gpt-4") result = f"""This is summary report on a focus group which title is: {title} --- Summary report --- {result} ----------------------------- APPENDIX / Profiles and Raw results from participants ----------------------------- // Profile 1 // {expert1} ===================== Participant answers: {response1} ------------------------------------------------------------------------------------------------------------------ // Profile 2 // {expert2} ===================== Participant answers: {response2} ------------------------------------------------------------------------------------------------------------------ // Profile 3 // {expert3} ===================== Participant answers: {response3} ------------------------------------------------------------------------------------------------------------------ // Profile 4 // {expert4} ===================== Participant answers: {response4} ------------------------------------------------------------------------------------------------------------------ // Profile 5 // {expert5} ===================== Participant answers: {response5} ------------------------------------------------------------------------------------------------------------------ // Profile 6 // {expert6} ===================== Participant answers: {response6} ------------------------------------------------------------------------------------------------------------------ // Profile 7 // {expert7} ===================== Participant answers: {response7} ------------------------------------------------------------------------------------------------------------------ // Profile 8 // {expert8} ===================== Participant answers: {response8} ------------------------------------------------------------------------------------------------------------------ // Profile 9 // {expert9} ===================== Participant answers: {response9} ------------------------------------------------------------------------------------------------------------------ // Profile 10 // {expert10} ===================== Participant answers: {response10} ------------------------------------------------------------------------------------------------------------------ """ return result def generateanswers(title, language, question1, question2, question3, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10): personalities = [expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10] results = [] for personality in personalities: prompt = f""" You are simulating this profile: {personality}. With this personality profile impersonation, please answer the 3 questions related to this topic: {title} The questions are: Question 1: {question1} Question 2: {question2} Question 3: {question3} Follow these rules: - Repeat the question first starting with "Question 1: ... then provide the answer at the line - Answer as the personality specified would, don't give answers that would not match this persona - Don't start by reminding your identity, provide your answer directly (we know who you are impersonating) - Answer in minimum 10 sentences for each question - Don't be too moralizing (environment safety, social impact...) - Use the style and vernacular language or the age and location (in English though) - Add a high level of burstiness and perplexity to your answers Here is 1 example of answers for inspiration for a focus group on outdoor activities in Hong Kong Lantau island from a profile who is Age: 19, Gender: Male, Location: Hong Kong, Occupation: University Student Marital Status: Single Question 1: What are the criteria for you to choose your outing activities? When I’m picking my activities, it boils down to three things really - fun, friends, and a bit of a workout. Like, I’m super into sports, so something like hiking or basketball is totally up my alley. And of course, my mates have got to be there, it’s always more fun when the gang’s together! Question 2: What activities would you recommend for teenagers in summer? Well, for my fellow teens in Hong Kong, I have to say, don’t miss out on the hikes on Lantau Island or any of the fab beach outings. There’s no better way to beat the heat than a dip in the sea after a killer hike. And sports, guys - just grab a ball and hit the nearest park, works every time. Summer in the city isn’t complete without a few local events too, brings everyone together. Question 3: What are your views about junk boats? In my opinion, junk boats are wicked! They’re like a slice of Old Hong Kong in the here and now. Perfect for a party with pals, you know. But, I reckon we’ve all got a part to play in looking after our nature and wildlife, so we should make sure our fun on the junks isn’t harming the aquatic life around us. Let’s party, but let’s also keep it green, folks! Now please provide your results using the following language: {language} """ formattedprompt = [{'role':'system','content':system_message},{'role':'user','content':prompt}] result = answer(formattedprompt, "gpt-4") results.append(result) return results[0], results[1], results[2], results[3], results[4], results[5], results[6], results[7], results[8], results[9] def parse_participants(input_string: str) -> list: # Replace
tags with newline characters input_string = input_string.replace("
", "\n") # Split the input string using a regular expression for “Participant X” participants = re.split(r'Participant \d+:\n', input_string)[1:] # Ignore the first split item since it’s empty # Parse each participant’s details and add them to a list participant_details = [] for participant in participants: details = '\n'.join(participant.strip().split("\n")) participant_details.append(details) return participant_details def generateprofiles(title, language, question1, question2, question3, focusgroupdescription): prompt = f""" Please generate 10 profiles for a focus group that would have the following features: - Title: {title} - Questions the focus group participants will have to answer: o Question 1: {question1} o Question 2: {question2} o Question 3: {question3} - These are the desired characteristics provided by the user for the focus group: {focusgroupdescription} Now generate 10 (ten) profiles aligned with these features following these rules: - Each profile will start with: 'Participant x:' (with x being the reference number of the profile) then the profile details would be on the following line - Profiles will be separated by an empy line, see examples below - Profiles should not be more than 20 lines long - Do not start with any introductory wording, directly provide the results, the first line should be 'Participant 1:' - Do not add any conclusion to your result Here are 2 examples of profiles for inspiration (for a focus group on sparkling drinks), One from Hong Kong, another one from Singapore: Participant 1: Name: Lai Mei Chen / Age: 30 years old / Gender: Female / Location: Hong Kong Occupation: Marketing Specialist Marital Status: Single Education: Bachelor’s Degree in Business Administration - Background: Lai Mei Chen is a young professional working in the marketing sector with a focus on consumer goods and lifestyle products. She has always been interested in the psychology of consumer behavior and how it influences purchasing decisions. During her university years, she took part in a number of focus groups for marketing research projects, which only fueled her passion for the field. - Interests: Lai Mei enjoys the everyday hustle in the busy city of Hong Kong and is always eager to try out new places and experiences. She has a particular interest in food and beverages, being an amateur at food photography and frequently post about new and upcoming trends on her personal blog and social media accounts. Lai Mei is also an environmental enthusiast and is mindful of the ecological impact of the products she consumes. This has led her to adopt a “greener” lifestyle by trying to reduce waste, recycling, and frequently supporting sustainable local businesses. - Relationship with the topic of the focus group: During her childhood, Lai Mei’s family wouldn’t consume a lot of sparkling drinks, but she still developed a love for them as an adult. She enjoys the bubbly sensation and refreshing taste, especially during the hot summer months in Hong Kong. Lai Mei perceives sparkling drinks as a treat for herself after a long day at work. She is always interested in discovering new brands and flavors, and she often chooses those with unique or exotic ingredients. - Attitude Towards the topic of the focus group: Lai Mei prefers sparkling drinks that are made with natural ingredients and use less artificial sweeteners. She believes that indulging in these drinks should not compromise her health or have detrimental effects on the environment. Therefore, she searches for drinks that come in recyclable packaging and have a reduced carbon footprint. What Lai Mei Can Offer As A Participant In The Focus Group: Coming from a marketing background gives Lai Mei the expertise to provide feedback on product packaging, messaging, and market positioning strategies. Additionally, being a social media-savvy individual and an influencer in her circle, she can suggest innovative ways to engage with the target audience and advocate for sustainable and healthier options in the sparkling drinks market. Furthermore, Lai Mei’s environment-conscious attitude and keen interest in the F&B industry allows her to provide valuable insights and preferences, which cater to the ever-growing eco-aware consumer base. Participant 2: Name: Nurul Amira Binti Iskandar / Age: 30 years old / Gender: Female / Location: Singapore Occupation: Interior Designer Marital Status: Married Education: Bachelor’s Degree in Interior Design - Background: Nurul Amira is a talented interior designer working for a reputable design firm in Singapore, with several successful projects under her belt. She enjoys working with various clients to create beautiful and functional spaces in homes, offices, and commercial establishments. Nurul Amira is married to her husband, Syafiq, and together they share a love for traveling and exploring diverse cultures. They often participate in local events and community programs as a way of giving back to their society. - Interests: In her spare time, Nurul Amira enjoys visiting art exhibitions and galleries to stay updated on the latest design trends and draw inspiration for her projects. She also has a strong interest in fashion and follows several local and international designers on social media platforms. Nurul Amira is also health-conscious and actively practices yoga and Pilates to maintain a balanced lifestyle. She is an advocate for healthy eating and often cooks nutritious meals for herself and her husband. - Relationship with the topic of the focus group: Coming from a tropical country, Nurul Amira is no stranger to the refreshing quality of sparkling drinks. She enjoys their effervescent texture and often indulges in them during social gatherings, family dinners, and festive occasions. Nurul Amira prefers fruity flavors in her sparkling drinks but also likes to experiment with different combinations. She often goes for sugar-free or reduced sugar options to maintain a healthier lifestyle. - Attitude Towards the topic of the focus group: As a health-conscious individual, Nurul Amira is particular about the sparkling drinks she consumes, especially when it comes to ingredients and calorie content. She looks for options that are made from natural ingredients and have lower sugar levels, without compromising on taste and flavor. What Nurul Amira Can Offer as a Participant in the Focus Group: As an interior designer with a keen eye for detail, Nurul Amira can provide valuable insights into the packaging, visual appeal, and design elements of sparkling drinks. Her understanding of contemporary lifestyle trends and her focus on healthy living can help brands identify potential avenues for product improvement and promotion. Nurul Amira’s experience in social events and gatherings also allows her to gauge how specific products may fare in various social scenarios and how they may fit into, or be adapted to, the ever-evolving preferences and tastes of the Singaporean consumer. Her participation in the focus group would provide an accurate representation of a health-conscious, modern consumer in Singapore and contribute meaningfully to the discussion. Now please provide your results using the following language: {language}. """ formattedprompt = [{'role':'system','content':system_message},{'role':'user','content':prompt}] list = [] while len(list) <10: result = answer(formattedprompt, "gpt-4") #break it down list = parse_participants(result) return list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], list[8], list[9] def answer(formattedprompt, model): #Now let's try 10 times for attempt in range(10): try: response = openai.ChatCompletion.create( model=model, messages=formattedprompt ) result = response['choices'][0]['message']['content'] break except Exception as e: print(f"Error occurred on attempt {attempt + 1}: {e}") if attempt < 10: time.sleep(10) else: raise e return result def init_history(title): return "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" generategroup.click(generateprofiles, [title, language, question1, question2, question3, focusgroupdescription], [expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10]) generateresults.click(generateanswers, [title, language, question1, question2, question3, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10], [response1, response2, response3, response4, response5, response6, response7, response8, response9, response10]) generatesummary.click(summarize, [title, language, question1, question2, question3, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10, response1, response2, response3, response4, response5, response6, response7, response8, response9, response10], summary) useapi.click(checkapiinput, apikey, [fullblock, apicheck, apikey, clear]) restore.click(uploaddetailsfromreport, summary, [title, question1, question2, question3, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10, response1, response2, response3, response4, response5, response6, response7, response8, response9, response10]) clear.click(init_history, title, [title, question1, question2, question3, focusgroupdescription, expert1, expert2, expert3, expert4, expert5, expert6, expert7, expert8, expert9, expert10, response1, response2, response3, response4, response5, response6, response7, response8, response9, response10, summary]) demo.launch()