import gradio as gr import matplotlib.pyplot as plt import numpy as np # Define the 44 BFI questions questions = [ "1. Talks a lot", "2. Notices other people’s weak points", "3. Does things carefully and completely", "4. Is sad, depressed", "5. Is original, comes up with new ideas", "6. Keeps their thoughts to themselves", "7. Is helpful and not selfish with others", "8. Can be kind of careless", "9. Is relaxed, handles stress well", "10. Is curious about lots of different things", "11. Has a lot of energy", "12. Starts arguments with others", "13. Is a good, hard worker", "14. Can be tense; not always easy going", "15. Clever; thinks a lot", "16. Makes things exciting", "17. Forgives others easily", "18. Isn’t very organized", "19. Worries a lot", "20. Has a good, active imagination", "21. Tends to be quiet", "22. Usually trusts people", "23. Tends to be lazy", "24. Doesn’t get upset easily; steady", "25. Is creative and inventive", "26. Has a good, strong personality", "27. Can be cold and distant with others", "28. Keeps working until things are done", "29. Can be moody", "30. Likes artistic and creative experiences", "31. Is kind of shy", "32. Kind and considerate to almost everyone", "33. Does things quickly and carefully", "34. Stays calm in difficult situations", "35. Likes work that is the same every time", "36. Is outgoing; likes to be with people", "37. Is sometimes rude to others", "38. Makes plans and sticks to them", "39. Get nervous easily", "40. Likes to think and play with ideas", "41. Doesn’t like artistic things (plays, music)", "42. Likes to cooperate; goes along with others", "43. Has trouble paying attention", "44. Knows a lot about art, music and books" ] # Scoring function based on the provided SPSS syntax def compute_bfi_scores(*args): responses = list(args) # Convert 'No response' to None, else to int processed = [] for r in responses: if r == "No response": processed.append(None) else: processed.append(int(r)) # Define traits with their respective items and scoring parameters traits = { 'Extraversion': { 'positive': [1, 11, 16, 26, 36], 'reverse': [6, 21, 31], 'threshold': 1, 'formula_pos_mult': 5, 'formula_reverse_mult': 3, 'formula_reverse_const': 12 }, 'Agreeableness': { 'positive': [7, 17, 22, 32, 42], 'reverse': [2, 12, 27, 37], 'threshold': 1, 'formula_pos_mult': 5, 'formula_reverse_mult':4, 'formula_reverse_const':16 }, 'Conscientiousness': { 'positive': [3, 13, 28, 33, 38], 'reverse': [8, 18, 23, 43], 'threshold': 1, 'formula_pos_mult':5, 'formula_reverse_mult':4, 'formula_reverse_const':16 }, 'Neuroticism':{ 'positive':[4, 14, 19, 29, 39], 'reverse':[9, 24, 34], 'threshold':1, 'formula_pos_mult':5, 'formula_reverse_mult':3, 'formula_reverse_const':12 }, 'Openness':{ 'positive':[5, 10, 15, 20, 25, 30, 40, 44], 'reverse':[35, 41], 'threshold':2, 'formula_pos_mult':8, 'formula_reverse_mult':2, 'formula_reverse_const':8 } } scores = {} for trait, info in traits.items(): pos_items = [processed[i-1] for i in info['positive']] rev_items = [processed[i-1] for i in info['reverse']] missing_pos = pos_items.count(None) missing_rev = rev_items.count(None) total_missing = missing_pos + missing_rev if total_missing > info['threshold']: scores[trait] = "Incomplete" else: # Compute means, ignoring None pos_values = [x for x in pos_items if x is not None] rev_values = [x for x in rev_items if x is not None] mean_pos = sum(pos_values) / len(pos_values) if pos_values else 0 mean_rev = sum(rev_values) / len(rev_values) if rev_values else 0 # Apply the scoring formula score = (mean_pos * info['formula_pos_mult']) + (info['formula_reverse_const'] - (mean_rev * info['formula_reverse_mult'])) score = round(score, 2) scores[trait] = score # Prepare the output in Markdown format with explanations explanations = { 'Extraversion': "Extraversion reflects how outgoing and energetic you are. High scores indicate sociability and enthusiasm, while low scores suggest a more reserved and solitary nature.", 'Agreeableness': "Agreeableness measures your tendency to be compassionate and cooperative. High scores signify kindness and trust, whereas low scores may indicate competitiveness or skepticism.", 'Conscientiousness': "Conscientiousness assesses your level of self-discipline and organization. High scores denote reliability and thoroughness, while low scores might reflect a more spontaneous or disorganized approach.", 'Neuroticism': "Neuroticism indicates emotional stability and susceptibility to stress. High scores suggest a tendency towards anxiety and moodiness, whereas low scores imply calmness and resilience.", 'Openness': "Openness measures your openness to new experiences and creativity. High scores are associated with imagination and curiosity, while low scores may indicate practicality and preference for routine." } output = "## Your Big Five Personality Traits Scores\n\n" # Prepare data for visualization trait_names = [] trait_scores = [] for trait, score in scores.items(): output += f"### **{trait}**\n" if score == "Incomplete": output += "Insufficient responses to compute this trait.\n\n" else: output += f"**Score**: {score}\n\n" output += f"{explanations[trait]}\n\n" trait_names.append(trait) trait_scores.append(score) # Generate bar chart if trait_scores: fig, ax = plt.subplots(figsize=(8, 4)) bars = ax.bar(trait_names, trait_scores, color='skyblue') ax.set_ylim(0, max(trait_scores) + 10) ax.set_ylabel('Score') ax.set_title('Big Five Traits Scores') # Add score labels on top of bars for bar in bars: height = bar.get_height() ax.annotate(f'{height}', xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), # 3 points vertical offset textcoords="offset points", ha='center', va='bottom') plt.tight_layout() # Save the plot to a PNG image in memory from io import BytesIO buf = BytesIO() plt.savefig(buf, format='png') buf.seek(0) plt.close(fig) output += "### **Trait Scores Visualization**\n\n" output += f"![Trait Scores]({gr.Image.update(value=buf.getvalue())})\n\n" return output # Create the Gradio interface def create_interface(): with gr.Blocks() as demo: gr.Markdown("# Big Five Inventory (BFI) Quiz") gr.Markdown( """ Please rate the following statements on a scale from **1 (Disagree a lot)** to **5 (Agree a lot)**. If you prefer not to respond to a particular statement, select **'No response'**. """ ) # Organize questions into expandable sections by trait trait_question_map = { 'Extraversion': [1, 6, 11, 16, 21, 26, 31, 36], 'Agreeableness': [2, 7, 12, 17, 22, 27, 32, 37, 42], 'Conscientiousness': [3, 8, 13, 18, 23, 28, 33, 38, 43], 'Neuroticism': [4, 9, 14, 19, 24, 29, 34, 39], 'Openness': [5, 10, 15, 20, 25, 30, 35, 40, 41, 44] } dropdowns = [] with gr.Accordion("Answer the Questions", open=True): for trait, q_indices in trait_question_map.items(): with gr.Group(): with gr.Accordion(trait, open=False): for i in q_indices: q = questions[i-1] radio = gr.Radio( choices=["No response", 1, 2, 3, 4, 5], label=q, value="No response", interactive=True ) dropdowns.append(radio) # Submit button submit_btn = gr.Button("Submit", variant="primary") # Results display result = gr.Markdown() # Link the button to the function submit_btn.click(fn=compute_bfi_scores, inputs=dropdowns, outputs=result) return demo # Launch the interface demo = create_interface() demo.launch()