|
import gradio as gr |
|
import matplotlib.pyplot as plt |
|
from io import BytesIO |
|
from PIL import Image as PILImage |
|
|
|
|
|
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" |
|
] |
|
|
|
|
|
def compute_bfi_scores(*args): |
|
responses = list(args) |
|
|
|
processed = [] |
|
for r in responses: |
|
if r == "No response": |
|
processed.append(None) |
|
else: |
|
processed.append(int(r)) |
|
|
|
|
|
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: |
|
|
|
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 |
|
|
|
|
|
score = (mean_pos * info['formula_pos_mult']) + (info['formula_reverse_const'] - (mean_rev * info['formula_reverse_mult'])) |
|
score = round(score, 2) |
|
scores[trait] = score |
|
|
|
|
|
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." |
|
} |
|
|
|
markdown_output = "## Your Big Five Personality Traits Scores\n\n" |
|
|
|
|
|
trait_names = [] |
|
trait_scores = [] |
|
for trait, score in scores.items(): |
|
markdown_output += f"### **{trait}**\n" |
|
if score == "Incomplete": |
|
markdown_output += "Insufficient responses to compute this trait.\n\n" |
|
else: |
|
markdown_output += f"**Score**: {score}\n\n" |
|
markdown_output += f"{explanations[trait]}\n\n" |
|
trait_names.append(trait) |
|
trait_scores.append(score) |
|
|
|
|
|
image = None |
|
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') |
|
|
|
|
|
for bar in bars: |
|
height = bar.get_height() |
|
ax.annotate(f'{height}', |
|
xy=(bar.get_x() + bar.get_width() / 2, height), |
|
xytext=(0, 3), |
|
textcoords="offset points", |
|
ha='center', va='bottom') |
|
|
|
plt.tight_layout() |
|
|
|
buf = BytesIO() |
|
plt.savefig(buf, format='png') |
|
buf.seek(0) |
|
plt.close(fig) |
|
|
|
image = PILImage.open(buf) |
|
buf.close() |
|
|
|
markdown_output += "### **Trait Scores Visualization**\n\n" |
|
|
|
return markdown_output, image |
|
|
|
|
|
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'**. |
|
""" |
|
) |
|
|
|
|
|
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] |
|
} |
|
|
|
inputs = [] |
|
|
|
with gr.Accordion("Answer the Questions", open=True): |
|
for trait, q_indices in trait_question_map.items(): |
|
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 |
|
) |
|
inputs.append(radio) |
|
|
|
|
|
submit_btn = gr.Button("Submit", variant="primary") |
|
|
|
|
|
with gr.Row(): |
|
markdown_result = gr.Markdown(label="Textual Results") |
|
image_result = gr.Image(label="Trait Scores Visualization") |
|
|
|
|
|
submit_btn.click( |
|
fn=compute_bfi_scores, |
|
inputs=inputs, |
|
outputs=[markdown_result, image_result] |
|
) |
|
|
|
return demo |
|
|
|
|
|
demo = create_interface() |
|
demo.launch() |
|
|