BasitAliii commited on
Commit
7b64bbd
Β·
verified Β·
1 Parent(s): 95965a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -97
app.py CHANGED
@@ -15,7 +15,9 @@ from matching import calculate_local_matches
15
  from feedback import save_feedback
16
  from ui_styles import BASE_CSS
17
 
18
- # ---------- Streamlit Config ----------
 
 
19
  st.set_page_config(
20
  page_title="AI Skill Swap",
21
  page_icon="🀝",
@@ -26,21 +28,24 @@ st.markdown(f"<style>{BASE_CSS}</style>", unsafe_allow_html=True)
26
 
27
  store = ProfileStore()
28
 
29
- # ---------- Header ----------
 
 
30
  col_logo, col_title = st.columns([1, 6])
31
  with col_logo:
32
  try:
33
- st.image("logo.jpg", width=90) # Use uploaded logo
 
34
  except:
35
- st.image(
36
- "https://via.placeholder.com/100x100/4F46E5/FFFFFF?text=🀝",
37
- width=90,
38
- )
39
  with col_title:
40
  st.title("AI Skill Swap")
41
  st.caption("Teach what you know β€’ Learn what you love β€’ Match intelligently")
42
 
43
- # ---------- Sidebar: Profile Management ----------
 
 
44
  with st.sidebar:
45
  st.header("πŸ‘€ Profile Manager")
46
 
@@ -50,10 +55,11 @@ with st.sidebar:
50
  selected_user = st.selectbox(
51
  "Select profile",
52
  ["β€” Create New β€”"] + usernames,
53
- key="selected_user",
54
  )
55
 
56
  st.markdown("### πŸ“ Profile Details")
 
57
  username = st.text_input(
58
  "Username",
59
  value="" if selected_user == "β€” Create New β€”" else selected_user,
@@ -96,23 +102,23 @@ with st.sidebar:
96
  key="avatar_uploader"
97
  )
98
 
99
- # ---------- Avatar Preview ----------
100
  if avatar_file:
101
- st.image(avatar_file, width=150, caption="Preview of avatar")
102
- if avatar_file.size > 800 * 1024: # 800KB max
103
- st.error("File exceeds maximum size of 800KB!")
104
  avatar_file = None
105
 
106
  st.markdown("---")
107
  col_create, col_update = st.columns(2)
108
 
109
- # ---------- CREATE PROFILE ----------
110
  with col_create:
111
- if st.button("βž• Create", use_container_width=True, key="create_button"):
112
  if not username.strip():
113
  st.error("Username is required!")
114
  elif store.find_by_username(username):
115
- st.error("Profile already exists. Use Update.")
116
  else:
117
  avatar_path = None
118
  if avatar_file:
@@ -137,22 +143,24 @@ with st.sidebar:
137
  ok, msg = store.add_or_update(profile)
138
  if ok:
139
  st.success(msg)
140
- # Clear fields
141
- for key in ["offers_text", "wants_text", "availability", "preferences", "username_input"]:
142
  if key in st.session_state:
143
  del st.session_state[key]
144
  if "avatar_uploader" in st.session_state:
145
  del st.session_state["avatar_uploader"]
 
 
146
  st.experimental_rerun()
147
  else:
148
  st.error(msg)
149
 
150
- # ---------- UPDATE PROFILE ----------
151
  with col_update:
152
- if st.button("πŸ’Ύ Update", use_container_width=True, key="update_button"):
153
  existing = store.find_by_username(username)
154
  if not existing:
155
- st.error("Profile does not exist. Use Create.")
156
  else:
157
  existing.offers = normalize_skill_list(offers_text)
158
  existing.wants = normalize_skill_list(wants_text)
@@ -175,34 +183,33 @@ with st.sidebar:
175
  del st.session_state["avatar_uploader"]
176
  st.experimental_rerun()
177
 
178
- # ---------- DELETE PROFILE ----------
179
  if selected_user != "β€” Create New β€”":
180
- if st.button("πŸ—‘οΈ Delete Profile", type="secondary", key="delete_button"):
181
- profiles = store.load_all()
182
- profile_to_delete = next((p for p in profiles if p.username == selected_user), None)
183
- if profile_to_delete:
184
- profiles.remove(profile_to_delete)
185
- store.save_all(profiles)
186
- st.warning(f"Profile '{selected_user}' deleted")
187
- for key in ["offers_text", "wants_text", "availability", "preferences", "username_input"]:
188
  if key in st.session_state:
189
  del st.session_state[key]
190
  if "avatar_uploader" in st.session_state:
191
  del st.session_state["avatar_uploader"]
192
  st.experimental_rerun()
193
  else:
194
- st.error("Profile not found")
195
 
196
- # ---------- MAIN CONTENT ----------
 
 
197
  left, right = st.columns([2, 3])
198
 
199
- # ---------- COMMUNITY PROFILES ----------
200
  with left:
201
  st.subheader("🌍 Community Profiles")
202
  profiles = store.load_all()
203
 
204
  if not profiles:
205
- st.info("No profiles yet. Create one from the sidebar.")
206
  else:
207
  for p in profiles:
208
  st.markdown("<div class='card'>", unsafe_allow_html=True)
@@ -212,10 +219,7 @@ with left:
212
  if p.avatar and Path(p.avatar).exists():
213
  st.image(p.avatar, width=120)
214
  else:
215
- st.image(
216
- "https://via.placeholder.com/120",
217
- width=120,
218
- )
219
 
220
  with cols[1]:
221
  st.markdown(f"**{p.username}**")
@@ -224,7 +228,9 @@ with left:
224
  st.markdown(f"🎯 **Wants:** {', '.join(p.wants) or 'β€”'}")
225
  st.markdown("</div>", unsafe_allow_html=True)
226
 
227
- # ---------- AI MATCHMAKING ----------
 
 
228
  with right:
229
  st.subheader("πŸ€– AI Matchmaking")
230
 
@@ -232,75 +238,73 @@ with right:
232
  st.info("Add profiles to enable matchmaking.")
233
  else:
234
  pick = st.selectbox(
235
- "Choose your profile",
236
  [p.username for p in profiles],
237
  key="matchmaking_select"
238
  )
239
 
240
  if st.button("✨ Find Best Matches", key="find_matches_button"):
241
- with st.spinner("Analyzing profiles..."):
242
- current = store.find_by_username(pick)
243
- matches = []
244
-
245
- try:
246
- sys_msg, user_msg = make_prompt_for_matching(current, profiles, 3)
247
- raw_matches = ask_groq_for_matches(sys_msg, user_msg)
248
- # Enrich Groq matches with full profile info
249
- for rm in raw_matches:
250
- profile = store.find_by_username(rm.get("username", ""))
251
- if profile:
252
- matches.append({
253
- "username": profile.username,
254
- "offers": profile.offers,
255
- "wants": profile.wants,
256
- "avatar": profile.avatar,
257
- "score": int(float(rm.get("score", 0)) * 100),
258
- "reason": rm.get("reason", "AI Match")
259
- })
260
- except Exception:
261
- matches = calculate_local_matches(
262
- current,
263
- [p for p in profiles if p.id != current.id],
264
- 3,
265
- )
266
- # Convert score 0-1 to 0-100%
267
- for m in matches:
268
- m["score"] = int(m["score"] * 100)
269
-
270
- # Display matches
271
- for m in matches:
272
- st.markdown("<div class='card'>", unsafe_allow_html=True)
273
- cols = st.columns([1, 4])
274
- with cols[0]:
275
- if m.get("avatar") and Path(m["avatar"]).exists():
276
- st.image(m["avatar"], width=100)
277
- else:
278
- st.image(
279
- "https://via.placeholder.com/100",
280
- width=100
281
- )
282
- with cols[1]:
283
- st.markdown(f"### {m.get('username')}")
284
- st.markdown(f"🧠 **Offers:** {', '.join(m.get('offers', [])) or 'β€”'}")
285
- st.markdown(f"🎯 **Wants:** {', '.join(m.get('wants', [])) or 'β€”'}")
286
- st.markdown(f"**Match Score:** {m.get('score', 0)}%")
287
- st.markdown(f"Match Reason: {m.get('reason', 'AI Match')}")
288
- st.markdown("</div>", unsafe_allow_html=True)
289
-
290
- # ---------- FEEDBACK ----------
291
  with st.sidebar:
292
  st.markdown("---")
293
  with st.expander("πŸ’¬ Feedback"):
294
  fb = st.text_area("Your feedback", key="feedback_text")
295
  if st.button("Submit Feedback", key="submit_feedback_button"):
296
  if fb.strip():
297
- save_feedback(
298
- {
299
- "timestamp": time.time(),
300
- "feedback": fb,
301
- "username": username if username.strip() else "anonymous",
302
- }
303
- )
304
  st.success("Thank you!")
305
  if "feedback_text" in st.session_state:
306
  del st.session_state["feedback_text"]
 
15
  from feedback import save_feedback
16
  from ui_styles import BASE_CSS
17
 
18
+ # ----------------------------------------------
19
+ # Streamlit Config
20
+ # ----------------------------------------------
21
  st.set_page_config(
22
  page_title="AI Skill Swap",
23
  page_icon="🀝",
 
28
 
29
  store = ProfileStore()
30
 
31
+ # ----------------------------------------------
32
+ # Header Section
33
+ # ----------------------------------------------
34
  col_logo, col_title = st.columns([1, 6])
35
  with col_logo:
36
  try:
37
+ # Use uploaded logo if available
38
+ st.image("logo.jpg", width=90)
39
  except:
40
+ st.image("https://via.placeholder.com/100x100/4F46E5/FFFFFF?text=🀝", width=90)
41
+
 
 
42
  with col_title:
43
  st.title("AI Skill Swap")
44
  st.caption("Teach what you know β€’ Learn what you love β€’ Match intelligently")
45
 
46
+ # ----------------------------------------------
47
+ # Sidebar: Profile Management
48
+ # ----------------------------------------------
49
  with st.sidebar:
50
  st.header("πŸ‘€ Profile Manager")
51
 
 
55
  selected_user = st.selectbox(
56
  "Select profile",
57
  ["β€” Create New β€”"] + usernames,
58
+ key="selected_user"
59
  )
60
 
61
  st.markdown("### πŸ“ Profile Details")
62
+
63
  username = st.text_input(
64
  "Username",
65
  value="" if selected_user == "β€” Create New β€”" else selected_user,
 
102
  key="avatar_uploader"
103
  )
104
 
105
+ # ---------- Avatar Preview & Size Check
106
  if avatar_file:
107
+ st.image(avatar_file, width=150, caption="Preview Avatar")
108
+ if avatar_file.size > 800 * 1024: # 800KB limit
109
+ st.error("File exceeds 800KB!")
110
  avatar_file = None
111
 
112
  st.markdown("---")
113
  col_create, col_update = st.columns(2)
114
 
115
+ # ---------- Create Button
116
  with col_create:
117
+ if st.button("βž• Create", key="create_button"):
118
  if not username.strip():
119
  st.error("Username is required!")
120
  elif store.find_by_username(username):
121
+ st.error("Already exists β€” use Update!")
122
  else:
123
  avatar_path = None
124
  if avatar_file:
 
143
  ok, msg = store.add_or_update(profile)
144
  if ok:
145
  st.success(msg)
146
+ # Clear fields on create
147
+ for key in ["offers_text", "wants_text", "availability", "preferences"]:
148
  if key in st.session_state:
149
  del st.session_state[key]
150
  if "avatar_uploader" in st.session_state:
151
  del st.session_state["avatar_uploader"]
152
+ # Clear previous matches
153
+ st.session_state["matches"] = []
154
  st.experimental_rerun()
155
  else:
156
  st.error(msg)
157
 
158
+ # ---------- Update Button
159
  with col_update:
160
+ if st.button("πŸ’Ύ Update", key="update_button"):
161
  existing = store.find_by_username(username)
162
  if not existing:
163
+ st.error("Profile does not exist.")
164
  else:
165
  existing.offers = normalize_skill_list(offers_text)
166
  existing.wants = normalize_skill_list(wants_text)
 
183
  del st.session_state["avatar_uploader"]
184
  st.experimental_rerun()
185
 
186
+ # ---------- Delete Button
187
  if selected_user != "β€” Create New β€”":
188
+ if st.button("πŸ—‘οΈ Delete Profile", key="delete_button"):
189
+ ok, msg = store.delete(selected_user)
190
+ if ok:
191
+ st.warning(msg)
192
+ # Clear sidebar fields
193
+ for key in ["username_input", "offers_input", "wants_input", "availability_input", "preferences_input"]:
 
 
194
  if key in st.session_state:
195
  del st.session_state[key]
196
  if "avatar_uploader" in st.session_state:
197
  del st.session_state["avatar_uploader"]
198
  st.experimental_rerun()
199
  else:
200
+ st.error(msg)
201
 
202
+ # ----------------------------------------------
203
+ # Main Content - Community Profiles
204
+ # ----------------------------------------------
205
  left, right = st.columns([2, 3])
206
 
 
207
  with left:
208
  st.subheader("🌍 Community Profiles")
209
  profiles = store.load_all()
210
 
211
  if not profiles:
212
+ st.info("No profiles yet. Create one above.")
213
  else:
214
  for p in profiles:
215
  st.markdown("<div class='card'>", unsafe_allow_html=True)
 
219
  if p.avatar and Path(p.avatar).exists():
220
  st.image(p.avatar, width=120)
221
  else:
222
+ st.image("https://via.placeholder.com/120", width=120)
 
 
 
223
 
224
  with cols[1]:
225
  st.markdown(f"**{p.username}**")
 
228
  st.markdown(f"🎯 **Wants:** {', '.join(p.wants) or 'β€”'}")
229
  st.markdown("</div>", unsafe_allow_html=True)
230
 
231
+ # ----------------------------------------------
232
+ # AI Matchmaking (Profile Cards)
233
+ # ----------------------------------------------
234
  with right:
235
  st.subheader("πŸ€– AI Matchmaking")
236
 
 
238
  st.info("Add profiles to enable matchmaking.")
239
  else:
240
  pick = st.selectbox(
241
+ "Match for profile",
242
  [p.username for p in profiles],
243
  key="matchmaking_select"
244
  )
245
 
246
  if st.button("✨ Find Best Matches", key="find_matches_button"):
247
+ current = store.find_by_username(pick)
248
+
249
+ try:
250
+ sys_msg, user_msg = make_prompt_for_matching(current, profiles, 3)
251
+ raw_matches = ask_groq_for_matches(sys_msg, user_msg)
252
+ except Exception:
253
+ raw_matches = calculate_local_matches(
254
+ current,
255
+ [p for p in profiles if p.id != current.id],
256
+ 3,
257
+ )
258
+
259
+ # Enrich returned matches
260
+ enriched = []
261
+ for rm in raw_matches:
262
+ prof = store.find_by_username(rm.get("username", ""))
263
+ if prof:
264
+ enriched.append({
265
+ "username": prof.username,
266
+ "offers": prof.offers,
267
+ "wants": prof.wants,
268
+ "avatar": prof.avatar,
269
+ "score": int(float(rm.get("score", 0)) * 100),
270
+ "reason": rm.get("reason", "AI Match")
271
+ })
272
+ st.session_state["matches"] = enriched
273
+
274
+ matches_list = st.session_state.get("matches", [])
275
+ for m in matches_list:
276
+ st.markdown("<div class='card'>", unsafe_allow_html=True)
277
+ cols = st.columns([1, 4])
278
+
279
+ with cols[0]:
280
+ if m.get("avatar") and Path(m["avatar"]).exists():
281
+ st.image(m["avatar"], width=120)
282
+ else:
283
+ st.image("https://via.placeholder.com/120", width=120)
284
+
285
+ with cols[1]:
286
+ st.markdown(f"### {m.get('username')}")
287
+ st.markdown(f"🧠 **Offers:** {', '.join(m.get('offers', [])) or 'β€”'}")
288
+ st.markdown(f"🎯 **Wants:** {', '.join(m.get('wants', [])) or 'β€”'}")
289
+ st.markdown(f"**Match Score:** {m.get('score', 0)}%")
290
+ st.markdown(f"**Reason:** {m.get('reason', '')}")
291
+
292
+ st.markdown("</div>", unsafe_allow_html=True)
293
+
294
+ # ----------------------------------------------
295
+ # Feedback
296
+ # ----------------------------------------------
297
  with st.sidebar:
298
  st.markdown("---")
299
  with st.expander("πŸ’¬ Feedback"):
300
  fb = st.text_area("Your feedback", key="feedback_text")
301
  if st.button("Submit Feedback", key="submit_feedback_button"):
302
  if fb.strip():
303
+ save_feedback({
304
+ "timestamp": time.time(),
305
+ "feedback": fb,
306
+ "username": username if username.strip() else "anonymous",
307
+ })
 
 
308
  st.success("Thank you!")
309
  if "feedback_text" in st.session_state:
310
  del st.session_state["feedback_text"]