cassandrasestier commited on
Commit
22ecdd5
Β·
verified Β·
1 Parent(s): f6dfb38

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -4
app.py CHANGED
@@ -1,7 +1,6 @@
1
  # ================================
2
  # πŸͺž MoodMirror+ β€” Text Emotion β€’ Advice-only + brief intros & reasons
3
- # - Adds an English "Emergency numbers" tab by country
4
- # - Adds a "Breathing" guided exercise tab
5
  # ================================
6
  import os
7
  import re
@@ -123,10 +122,19 @@ def get_conn():
123
 
124
  def init_db():
125
  conn = get_conn()
 
126
  conn.execute("""CREATE TABLE IF NOT EXISTS sessions(
127
  id INTEGER PRIMARY KEY AUTOINCREMENT,
128
  ts TEXT, country TEXT, user_text TEXT, main_emotion TEXT
129
  )""")
 
 
 
 
 
 
 
 
130
  conn.commit()
131
  conn.close()
132
 
@@ -137,6 +145,77 @@ def log_session(country, msg, emotion):
137
  conn.commit()
138
  conn.close()
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  # ---------------- Model ----------------
141
  def load_goemotions_dataset():
142
  ds = load_dataset("google-research-datasets/go_emotions", "simplified")
@@ -273,8 +352,7 @@ with gr.Blocks(title="πŸͺž MoodMirror+ β€” Text Emotion β€’ Advice-only") as dem
273
 
274
  # ---- Tab 3: Breathing ----
275
  with gr.Tab("Breathing"):
276
- gr.Markdown("#### 🌬️ Guided breathing\nPick a pattern and cycles, then press **Start**. "
277
- "If you feel dizzy, stop and breathe normally.")
278
  with gr.Row():
279
  pattern = gr.Dropdown(
280
  choices=["4-7-8", "Box (4-4-4-4)", "Coherent (5-5, ~6 breaths/min)"],
@@ -302,6 +380,84 @@ with gr.Blocks(title="πŸͺž MoodMirror+ β€” Text Emotion β€’ Advice-only") as dem
302
  yield "βœ… Done. Notice how your body feels."
303
  start_btn.click(run_breathing, inputs=[pattern, cycles], outputs=[breathe_out])
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  if __name__ == "__main__":
 
306
  demo.queue()
307
  demo.launch()
 
1
  # ================================
2
  # πŸͺž MoodMirror+ β€” Text Emotion β€’ Advice-only + brief intros & reasons
3
+ # - Tabs: Advice β€’ Emergency numbers β€’ Breathing β€’ Journal (with export & delete)
 
4
  # ================================
5
  import os
6
  import re
 
122
 
123
  def init_db():
124
  conn = get_conn()
125
+ # sessions
126
  conn.execute("""CREATE TABLE IF NOT EXISTS sessions(
127
  id INTEGER PRIMARY KEY AUTOINCREMENT,
128
  ts TEXT, country TEXT, user_text TEXT, main_emotion TEXT
129
  )""")
130
+ # journal
131
+ conn.execute("""CREATE TABLE IF NOT EXISTS journal(
132
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
133
+ ts TEXT NOT NULL,
134
+ emotion TEXT,
135
+ title TEXT,
136
+ content TEXT
137
+ )""")
138
  conn.commit()
139
  conn.close()
140
 
 
145
  conn.commit()
146
  conn.close()
147
 
148
+ # ---- Journal helpers ----
149
+ def journal_save(title: str, content: str, emotion: str):
150
+ title = (title or "").strip()
151
+ content = (content or "").strip()
152
+ if not content:
153
+ return False, "Please write something before saving."
154
+ ts = datetime.utcnow().isoformat(timespec='seconds')
155
+ conn = get_conn()
156
+ conn.execute("INSERT INTO journal(ts, emotion, title, content) VALUES (?,?,?,?)",
157
+ (ts, emotion or "", title, content))
158
+ conn.commit()
159
+ conn.close()
160
+ return True, f"Saved βœ“ ({ts} UTC)."
161
+
162
+ def journal_list(search: str = "", limit: int = 50):
163
+ q = "SELECT id, ts, emotion, title, content FROM journal"
164
+ params = []
165
+ if search:
166
+ q += " WHERE (LOWER(title) LIKE ? OR LOWER(content) LIKE ? OR LOWER(emotion) LIKE ?)"
167
+ s = f"%{search.lower()}%"
168
+ params = [s, s, s]
169
+ q += " ORDER BY ts DESC LIMIT ?"
170
+ params.append(int(limit))
171
+ conn = get_conn()
172
+ rows = list(conn.execute(q, params))
173
+ conn.close()
174
+ options = []
175
+ table = []
176
+ for (id_, ts, emo, title, content) in rows:
177
+ label = f"{ts} β€” [{(emo or 'neutral')}] {title or (content[:30] + ('…' if len(content) > 30 else ''))}"
178
+ options.append((label, id_))
179
+ preview = (content or "").replace("\n", " ")
180
+ if len(preview) > 120: preview = preview[:120] + "…"
181
+ table.append([ts, emo or "β€”", title or "β€”", preview])
182
+ return options, table
183
+
184
+ def journal_get(entry_id: int):
185
+ conn = get_conn()
186
+ cur = conn.execute("SELECT ts, emotion, title, content FROM journal WHERE id = ?", (int(entry_id),))
187
+ row = cur.fetchone()
188
+ conn.close()
189
+ if not row: return None
190
+ ts, emo, title, content = row
191
+ return {"ts": ts, "emotion": emo or "", "title": title or "", "content": content or ""}
192
+
193
+ def journal_delete(entry_id: int):
194
+ conn = get_conn()
195
+ cur = conn.execute("DELETE FROM journal WHERE id = ?", (int(entry_id),))
196
+ conn.commit()
197
+ changes = conn.total_changes
198
+ conn.close()
199
+ return changes > 0
200
+
201
+ def journal_export_txt(entry_id: int):
202
+ data = journal_get(entry_id)
203
+ if not data:
204
+ return None, "Entry not found."
205
+ fname = f"journal_{entry_id}_{data['ts'].replace(':','-')}.txt"
206
+ fpath = os.path.join(DATA_DIR, fname)
207
+ # Build plain text
208
+ lines = []
209
+ title = data["title"] or "(Untitled)"
210
+ lines.append(f"Title: {title}")
211
+ lines.append(f"Emotion: {data['emotion'] or '-'}")
212
+ lines.append(f"Saved (UTC): {data['ts']}")
213
+ lines.append("-" * 40)
214
+ lines.append(data["content"])
215
+ with open(fpath, "w", encoding="utf-8") as f:
216
+ f.write("\n".join(lines))
217
+ return fpath, f"Ready: {fname}"
218
+
219
  # ---------------- Model ----------------
220
  def load_goemotions_dataset():
221
  ds = load_dataset("google-research-datasets/go_emotions", "simplified")
 
352
 
353
  # ---- Tab 3: Breathing ----
354
  with gr.Tab("Breathing"):
355
+ gr.Markdown("#### 🌬️ Guided breathing\nPick a pattern and cycles, then press **Start**. If you feel dizzy, stop and breathe normally.")
 
356
  with gr.Row():
357
  pattern = gr.Dropdown(
358
  choices=["4-7-8", "Box (4-4-4-4)", "Coherent (5-5, ~6 breaths/min)"],
 
380
  yield "βœ… Done. Notice how your body feels."
381
  start_btn.click(run_breathing, inputs=[pattern, cycles], outputs=[breathe_out])
382
 
383
+ # ---- Tab 4: Journal (with export & delete) ----
384
+ with gr.Tab("Journal"):
385
+ gr.Markdown("#### πŸ“ Personal journal\nWrite freely for a couple of minutes, then save. Entries are stored locally.")
386
+
387
+ with gr.Row():
388
+ j_title = gr.Textbox(label="Title (optional)", placeholder="e.g., A tough day at work")
389
+ j_emotion = gr.Dropdown(
390
+ choices=["neutral","sadness","fear","anger","nervousness","boredom","grief","love","joy","curiosity","gratitude"],
391
+ value="neutral", label="Emotion tag"
392
+ )
393
+ j_text = gr.Textbox(lines=10, label="Your entry", placeholder="Write whatever you want to get off your chest...")
394
+
395
+ with gr.Row():
396
+ j_save = gr.Button("Save entry", variant="primary")
397
+ j_status = gr.Markdown()
398
+
399
+ gr.Markdown("##### Your entries")
400
+ with gr.Row():
401
+ j_search = gr.Textbox(label="Search (title, text or emotion)", placeholder="e.g., anxiety, work, joy")
402
+ j_refresh = gr.Button("Refresh list")
403
+ j_entries = gr.Dropdown(label="Entries (newest first)", choices=[], value=None, interactive=True)
404
+ j_table = gr.Dataframe(headers=["UTC time","Emotion","Title","Preview"], value=[], interactive=False, wrap=True, height=200)
405
+ j_view = gr.Markdown()
406
+
407
+ # Export + Delete UI
408
+ with gr.Row():
409
+ j_export_btn = gr.Button("Export .txt")
410
+ j_export_file = gr.File(label="Download exported entry", visible=True)
411
+ j_delete_btn = gr.Button("Delete entry", variant="stop")
412
+
413
+ # Backend glue
414
+ def _refresh_entries(search):
415
+ options, table = journal_list(search or "", 50)
416
+ return gr.Dropdown(choices=options, value=None), table
417
+
418
+ def _save_entry(title, text, emotion, search):
419
+ ok, msg = journal_save(title, text, emotion)
420
+ drop, table = _refresh_entries(search)
421
+ clear_text = "" if ok else text
422
+ clear_title = "" if ok else title
423
+ return msg, drop, table, clear_text, clear_title
424
+
425
+ def _load_entry(entry_id):
426
+ if entry_id is None: return ""
427
+ data = journal_get(entry_id)
428
+ if not data: return "Entry not found."
429
+ title_line = f"### {data['title']}" if data['title'] else "### (Untitled)"
430
+ emo_line = f"**Emotion:** {data['emotion'] or 'β€”'} \n**Saved (UTC):** {data['ts']}"
431
+ return f"{title_line}\n\n{emo_line}\n\n---\n\n{data['content']}"
432
+
433
+ def _export_entry(entry_id):
434
+ if entry_id is None:
435
+ return None, "Select an entry to export."
436
+ path, msg = journal_export_txt(int(entry_id))
437
+ return path, msg
438
+
439
+ def _delete_entry(entry_id, search):
440
+ if entry_id is None:
441
+ status = "Select an entry to delete."
442
+ drop, table = _refresh_entries(search)
443
+ return status, drop, table, ""
444
+ ok = journal_delete(int(entry_id))
445
+ status = "Deleted βœ“" if ok else "Entry not found."
446
+ drop, table = _refresh_entries(search)
447
+ return status, drop, table, ""
448
+
449
+ # Wire actions
450
+ j_save.click(_save_entry, inputs=[j_title, j_text, j_emotion, j_search],
451
+ outputs=[j_status, j_entries, j_table, j_text, j_title])
452
+ j_refresh.click(_refresh_entries, inputs=[j_search], outputs=[j_entries, j_table])
453
+ j_search.submit(_refresh_entries, inputs=[j_search], outputs=[j_entries, j_table])
454
+ j_entries.change(_load_entry, inputs=[j_entries], outputs=[j_view])
455
+
456
+ j_export_btn.click(_export_entry, inputs=[j_entries], outputs=[j_export_file, j_status])
457
+ j_delete_btn.click(_delete_entry, inputs=[j_entries, j_search],
458
+ outputs=[j_status, j_entries, j_table, j_view])
459
+
460
  if __name__ == "__main__":
461
+ gr.set_theme("default")
462
  demo.queue()
463
  demo.launch()