Update app.py
Browse files
app.py
CHANGED
@@ -3,39 +3,51 @@ import streamlit as st
|
|
3 |
from groq import Groq
|
4 |
from textblob import TextBlob
|
5 |
from transformers import pipeline
|
|
|
6 |
import re
|
7 |
import random
|
8 |
from datetime import datetime
|
9 |
from reportlab.lib.pagesizes import letter
|
10 |
from reportlab.pdfgen import canvas
|
11 |
import io
|
|
|
12 |
|
13 |
-
#
|
14 |
-
|
|
|
|
|
|
|
15 |
groq_client = Groq(api_key=st.secrets["GROQ_API_KEY"])
|
16 |
-
|
17 |
-
st.error("GROQ_API_KEY missing in secrets
|
18 |
-
st.stop()
|
19 |
|
20 |
-
#
|
21 |
try:
|
22 |
personality_classifier = pipeline(
|
23 |
"text-classification",
|
24 |
model="j-hartmann/emotion-english-distilroberta-base"
|
25 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
big5_model = pipeline(
|
27 |
"text-classification",
|
28 |
-
model="m3hrdadfi/bigfive-personality
|
29 |
top_k=5
|
30 |
)
|
31 |
except Exception as e:
|
32 |
-
st.error(f"
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
|
|
|
|
37 |
|
38 |
-
# Custom CSS
|
39 |
st.markdown("""
|
40 |
<style>
|
41 |
@keyframes rainbow {
|
@@ -46,10 +58,12 @@ st.markdown("""
|
|
46 |
80% { color: #0000ff; }
|
47 |
100% { color: #ff00ff; }
|
48 |
}
|
|
|
49 |
.personality-title {
|
50 |
animation: rainbow 3s infinite;
|
51 |
font-size: 2.5em !important;
|
52 |
}
|
|
|
53 |
.progress-bar {
|
54 |
height: 25px;
|
55 |
border-radius: 15px;
|
@@ -58,7 +72,7 @@ st.markdown("""
|
|
58 |
</style>
|
59 |
""", unsafe_allow_html=True)
|
60 |
|
61 |
-
# Dynamic questions pool
|
62 |
QUESTION_BANK = [
|
63 |
{"text": "What's your most creative procrastination method? π¨π", "trait": "openness"},
|
64 |
{"text": "How do you react when plans change suddenly? πͺοΈπ€", "trait": "neuroticism"},
|
@@ -73,28 +87,98 @@ QUESTION_BANK = [
|
|
73 |
]
|
74 |
|
75 |
def analyze_big5(text):
|
76 |
-
"""
|
77 |
results = big5_model(text[:512])
|
78 |
-
|
79 |
-
|
80 |
-
'NEUROTICISM': 'neuroticism',
|
81 |
-
'CONSCIENTIOUSNESS': 'conscientiousness',
|
82 |
-
'OPENNESS': 'openness',
|
83 |
-
'AGREEABLENESS': 'agreeableness'
|
84 |
-
}
|
85 |
-
return {trait_map[res['label']: res['score'] for res in results}
|
86 |
|
87 |
def get_dynamic_questions(responses):
|
88 |
-
"""Select questions based on personality patterns"""
|
89 |
-
if
|
90 |
return random.sample(QUESTION_BANK, 5)
|
91 |
|
92 |
traits = analyze_big5("\n".join(responses))
|
93 |
dominant_trait = max(traits, key=traits.get)
|
94 |
return [q for q in QUESTION_BANK if q['trait'] == dominant_trait][:3] + random.sample(QUESTION_BANK, 2)
|
95 |
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
# Session state management
|
100 |
if 'responses' not in st.session_state:
|
@@ -104,17 +188,89 @@ if 'current_q' not in st.session_state:
|
|
104 |
if 'questions' not in st.session_state:
|
105 |
st.session_state.questions = get_dynamic_questions([])
|
106 |
|
107 |
-
# Main UI
|
108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
|
110 |
-
#
|
111 |
-
if st.
|
112 |
-
st.session_state.
|
113 |
-
st.session_state.current_q += 1
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
st.
|
118 |
-
|
|
|
119 |
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
from groq import Groq
|
4 |
from textblob import TextBlob
|
5 |
from transformers import pipeline
|
6 |
+
import numpy as np
|
7 |
import re
|
8 |
import random
|
9 |
from datetime import datetime
|
10 |
from reportlab.lib.pagesizes import letter
|
11 |
from reportlab.pdfgen import canvas
|
12 |
import io
|
13 |
+
from transformers import AutoModel, AutoTokenizer
|
14 |
|
15 |
+
# Set page configuration as the very first command
|
16 |
+
st.set_page_config(page_title="π§ Personality Prodigy", layout="wide", page_icon="π€")
|
17 |
+
|
18 |
+
# Initialize Groq client (ensure API key is available in Streamlit secrets)
|
19 |
+
if "GROQ_API_KEY" in st.secrets:
|
20 |
groq_client = Groq(api_key=st.secrets["GROQ_API_KEY"])
|
21 |
+
else:
|
22 |
+
st.error("GROQ_API_KEY is missing in Streamlit secrets.")
|
|
|
23 |
|
24 |
+
# Emotion Classification Model
|
25 |
try:
|
26 |
personality_classifier = pipeline(
|
27 |
"text-classification",
|
28 |
model="j-hartmann/emotion-english-distilroberta-base"
|
29 |
)
|
30 |
+
except Exception as e:
|
31 |
+
st.error(f"Error loading emotion classifier: {e}")
|
32 |
+
|
33 |
+
# Big Five Personality Model
|
34 |
+
try:
|
35 |
+
# Attempt to load the Big Five personality model from Hugging Face.
|
36 |
big5_model = pipeline(
|
37 |
"text-classification",
|
38 |
+
model="m3hrdadfi/bigfive-personality", # This identifier may not be valid.
|
39 |
top_k=5
|
40 |
)
|
41 |
except Exception as e:
|
42 |
+
st.error(f"Error loading Big Five personality model: {e}")
|
43 |
+
# Fallback: Define a dummy function that simulates Big Five personality analysis.
|
44 |
+
def dummy_big5_model(text):
|
45 |
+
traits = ["openness", "conscientiousness", "extraversion", "agreeableness", "neuroticism"]
|
46 |
+
# Return a list of dictionaries similar to a pipeline's output.
|
47 |
+
return [{"label": f"BIGFIVE_{trait.upper()}", "score": random.uniform(0, 1)} for trait in traits]
|
48 |
+
big5_model = dummy_big5_model
|
49 |
|
50 |
+
# Custom CSS for styling
|
51 |
st.markdown("""
|
52 |
<style>
|
53 |
@keyframes rainbow {
|
|
|
58 |
80% { color: #0000ff; }
|
59 |
100% { color: #ff00ff; }
|
60 |
}
|
61 |
+
|
62 |
.personality-title {
|
63 |
animation: rainbow 3s infinite;
|
64 |
font-size: 2.5em !important;
|
65 |
}
|
66 |
+
|
67 |
.progress-bar {
|
68 |
height: 25px;
|
69 |
border-radius: 15px;
|
|
|
72 |
</style>
|
73 |
""", unsafe_allow_html=True)
|
74 |
|
75 |
+
# Dynamic questions pool
|
76 |
QUESTION_BANK = [
|
77 |
{"text": "What's your most creative procrastination method? π¨π", "trait": "openness"},
|
78 |
{"text": "How do you react when plans change suddenly? πͺοΈπ€", "trait": "neuroticism"},
|
|
|
87 |
]
|
88 |
|
89 |
def analyze_big5(text):
|
90 |
+
"""Analyze Big Five personality traits using the provided model or dummy fallback."""
|
91 |
results = big5_model(text[:512])
|
92 |
+
# Process returned labels assuming they are in the form "BIGFIVE_<TRAIT>"
|
93 |
+
return {result['label'].split("_")[-1].lower(): result['score'] for result in results}
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
def get_dynamic_questions(responses):
|
96 |
+
"""Select questions based on emerging personality patterns."""
|
97 |
+
if len(responses) == 0:
|
98 |
return random.sample(QUESTION_BANK, 5)
|
99 |
|
100 |
traits = analyze_big5("\n".join(responses))
|
101 |
dominant_trait = max(traits, key=traits.get)
|
102 |
return [q for q in QUESTION_BANK if q['trait'] == dominant_trait][:3] + random.sample(QUESTION_BANK, 2)
|
103 |
|
104 |
+
def analyze_emotions(text):
|
105 |
+
"""Detect emotional tone using the emotion classifier."""
|
106 |
+
return personality_classifier(text[:512])
|
107 |
+
|
108 |
+
def generate_quote(traits):
|
109 |
+
"""Generate a personality-specific quote using Groq/Mistral."""
|
110 |
+
prompt = f"""Create a motivational quote for someone with these traits:
|
111 |
+
{traits}
|
112 |
+
Make it inspirational, funny, and include an emoji."""
|
113 |
+
|
114 |
+
response = groq_client.chat.completions.create(
|
115 |
+
model="mixtral-8x7b-32768",
|
116 |
+
messages=[{"role": "user", "content": prompt}],
|
117 |
+
temperature=0.7
|
118 |
+
)
|
119 |
+
return response.choices[0].message.content
|
120 |
+
|
121 |
+
def generate_tips(traits):
|
122 |
+
"""Generate evidence-based psychological tips."""
|
123 |
+
tips = []
|
124 |
+
if traits.get('openness', 0) > 0.7:
|
125 |
+
tips.extend([
|
126 |
+
"π¨ Try creative cross-training (write a poem about your work)",
|
127 |
+
"π Learn something new daily about different cultures"
|
128 |
+
])
|
129 |
+
if traits.get('neuroticism', 0) > 0.6:
|
130 |
+
tips.extend([
|
131 |
+
"π§ Practice box breathing: 4s in, 4s hold, 4s out",
|
132 |
+
"π Keep a worry journal to externalize anxieties"
|
133 |
+
])
|
134 |
+
return tips[:10]
|
135 |
+
|
136 |
+
def create_personality_report(responses):
|
137 |
+
"""Generate a comprehensive personality analysis."""
|
138 |
+
text = "\n".join(responses)
|
139 |
+
big5_results = analyze_big5(text)
|
140 |
+
return {
|
141 |
+
"big5": big5_results,
|
142 |
+
"emotions": analyze_emotions(text),
|
143 |
+
"quote": generate_quote(big5_results),
|
144 |
+
"tips": generate_tips(big5_results)
|
145 |
+
}
|
146 |
+
|
147 |
+
def create_pdf_report(report):
|
148 |
+
"""Generate a downloadable PDF report."""
|
149 |
+
buffer = io.BytesIO()
|
150 |
+
p = canvas.Canvas(buffer, pagesize=letter)
|
151 |
+
|
152 |
+
# Header
|
153 |
+
p.setFont("Helvetica-Bold", 16)
|
154 |
+
p.drawString(100, 750, "π Personality Prodigy Report π")
|
155 |
+
p.setFont("Helvetica", 12)
|
156 |
+
|
157 |
+
# Content
|
158 |
+
y_position = 700
|
159 |
+
content = [
|
160 |
+
f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
|
161 |
+
"",
|
162 |
+
"Big Five Personality Traits:",
|
163 |
+
*[f"- {trait.upper()}: {score:.2f}" for trait, score in report['big5'].items()],
|
164 |
+
"",
|
165 |
+
"Emotional Analysis:",
|
166 |
+
*[f"- {emo['label']}: {emo['score']:.2f}" for emo in report['emotions']],
|
167 |
+
"",
|
168 |
+
"Personalized Quote:",
|
169 |
+
report['quote'],
|
170 |
+
"",
|
171 |
+
"Growth Tips:",
|
172 |
+
*[f"{i+1}. {tip}" for i, tip in enumerate(report['tips'])]
|
173 |
+
]
|
174 |
+
|
175 |
+
for line in content:
|
176 |
+
p.drawString(100, y_position, line)
|
177 |
+
y_position -= 15
|
178 |
+
|
179 |
+
p.save()
|
180 |
+
buffer.seek(0)
|
181 |
+
return buffer
|
182 |
|
183 |
# Session state management
|
184 |
if 'responses' not in st.session_state:
|
|
|
188 |
if 'questions' not in st.session_state:
|
189 |
st.session_state.questions = get_dynamic_questions([])
|
190 |
|
191 |
+
# Main UI
|
192 |
+
st.title("π§ Personality Prodigy")
|
193 |
+
st.markdown("### Your AI-Powered Mirror for Self-Discovery πβ¨")
|
194 |
+
|
195 |
+
# Progress tracker
|
196 |
+
progress = st.session_state.current_q / len(st.session_state.questions)
|
197 |
+
st.markdown(f"""
|
198 |
+
<div style="background: #f0f2f6; border-radius: 15px; padding: 5px;">
|
199 |
+
<div class="progress-bar" style="width: {progress*100}%; height: 25px;"></div>
|
200 |
+
</div>
|
201 |
+
""", unsafe_allow_html=True)
|
202 |
|
203 |
+
# Dynamic question flow
|
204 |
+
if st.session_state.current_q < len(st.session_state.questions):
|
205 |
+
q = st.session_state.questions[st.session_state.current_q]
|
|
|
206 |
|
207 |
+
with st.chat_message("assistant"):
|
208 |
+
st.markdown(f"### {q['text']}")
|
209 |
+
st.markdown(f"*What's your answer?* {'π€' if q['trait'] in ['neuroticism','conscientiousness'] else 'π'}")
|
210 |
+
|
211 |
+
user_input = st.text_input("Your response:", key=f"q{st.session_state.current_q}")
|
212 |
|
213 |
+
if st.button("Next β‘οΈ"):
|
214 |
+
st.session_state.responses.append(user_input)
|
215 |
+
st.session_state.current_q += 1
|
216 |
+
|
217 |
+
# Update questions based on responses
|
218 |
+
if st.session_state.current_q == len(st.session_state.questions):
|
219 |
+
st.session_state.questions = get_dynamic_questions(st.session_state.responses)
|
220 |
+
st.session_state.current_q = 0
|
221 |
+
|
222 |
+
st.experimental_rerun()
|
223 |
+
else:
|
224 |
+
# Generate and display report
|
225 |
+
report = create_personality_report(st.session_state.responses)
|
226 |
+
st.balloons()
|
227 |
+
|
228 |
+
st.markdown(f"## <div class='personality-title'>π Your Personality Report π</div>", unsafe_allow_html=True)
|
229 |
+
|
230 |
+
# Big Five Traits Visualization
|
231 |
+
with st.expander("π Big Five Personality Traits"):
|
232 |
+
cols = st.columns(5)
|
233 |
+
traits = report['big5']
|
234 |
+
for i, (trait, score) in enumerate(traits.items()):
|
235 |
+
cols[i].metric(label=trait.upper(), value=f"{score:.0%}",
|
236 |
+
help=f"{['Low','Moderate','High'][int(score//0.33)]} {trait}")
|
237 |
+
|
238 |
+
# Emotional Analysis
|
239 |
+
with st.expander("π Emotional Tone Analysis"):
|
240 |
+
emotion = max(report['emotions'], key=lambda x: x['score'])
|
241 |
+
st.markdown(f"**Dominant Emotion**: {emotion['label']} ({emotion['score']:.0%})")
|
242 |
+
st.progress(emotion['score'])
|
243 |
+
|
244 |
+
# Personalized Content
|
245 |
+
col1, col2 = st.columns(2)
|
246 |
+
with col1:
|
247 |
+
st.markdown("### π¬ Your Personality Quote")
|
248 |
+
st.success(f'"{report["quote"]}"')
|
249 |
+
with col2:
|
250 |
+
st.markdown("### π οΈ Growth Strategies")
|
251 |
+
for tip in report['tips'][:5]:
|
252 |
+
st.markdown(f"- {tip}")
|
253 |
+
|
254 |
+
# Downloadable Report
|
255 |
+
pdf_buffer = create_pdf_report(report)
|
256 |
+
st.download_button(
|
257 |
+
"π₯ Download Full Report",
|
258 |
+
data=pdf_buffer,
|
259 |
+
file_name="personality_report.pdf",
|
260 |
+
mime="application/pdf"
|
261 |
+
)
|
262 |
+
|
263 |
+
# Sidebar
|
264 |
+
with st.sidebar:
|
265 |
+
st.markdown("## π How It Works")
|
266 |
+
st.markdown("""
|
267 |
+
1. Answer dynamic personality questions
|
268 |
+
2. Get real-time psychological analysis
|
269 |
+
3. Receive personalized growth strategies
|
270 |
+
4. Download/share your unique report
|
271 |
+
|
272 |
+
**Scientific Backing:**
|
273 |
+
- Big Five Personality Model (OCEAN)
|
274 |
+
- Emotion Recognition (RoBERTa)
|
275 |
+
- Cognitive Behavioral Therapy (CBT)
|
276 |
+
""")
|