adikwok commited on
Commit
122f4a0
Β·
verified Β·
1 Parent(s): c9d52c6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -68
app.py CHANGED
@@ -32,7 +32,6 @@ DATABASE_FILE = STORAGE_DIR / "chat_database.db"
32
 
33
  @dataclass
34
  class ChatMessage:
35
- """Data class untuk pesan chat"""
36
  role: str
37
  content: str
38
  topic: str
@@ -50,15 +49,12 @@ class ChatMessage:
50
  self.message_id = str(uuid.uuid4())
51
 
52
  class DatabaseManager:
53
- """Mengelola database SQLite untuk pencarian yang lebih efisien"""
54
-
55
  def __init__(self):
56
  self.db_path = DATABASE_FILE
57
  self.lock = threading.Lock()
58
  self.init_database()
59
 
60
  def init_database(self):
61
- """Inisialisasi tabel database"""
62
  try:
63
  with sqlite3.connect(self.db_path) as conn:
64
  conn.execute('''
@@ -76,7 +72,6 @@ class DatabaseManager:
76
  content_hash TEXT
77
  )
78
  ''')
79
-
80
  conn.execute('''
81
  CREATE TABLE IF NOT EXISTS sessions (
82
  session_id TEXT PRIMARY KEY,
@@ -86,19 +81,16 @@ class DatabaseManager:
86
  message_count INTEGER DEFAULT 0
87
  )
88
  ''')
89
-
90
  conn.execute('CREATE INDEX IF NOT EXISTS idx_content ON messages(content)')
91
  conn.execute('CREATE INDEX IF NOT EXISTS idx_topic ON messages(topic)')
92
  conn.execute('CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp)')
93
  conn.execute('CREATE INDEX IF NOT EXISTS idx_session ON messages(session_id)')
94
  conn.execute('CREATE INDEX IF NOT EXISTS idx_role ON messages(role)')
95
-
96
  conn.commit()
97
  except sqlite3.Error as e:
98
  raise Exception(f"Failed to initialize database: {str(e)}")
99
 
100
  def add_message(self, message: ChatMessage):
101
- """Menambah pesan ke database"""
102
  try:
103
  with self.lock:
104
  content_hash = hashlib.md5(message.content.encode('utf-8')).hexdigest()
@@ -112,7 +104,6 @@ class DatabaseManager:
112
  message.timestamp, message.word_count, message.char_count,
113
  message.session_id, json.dumps(message.tags), content_hash
114
  ))
115
-
116
  conn.execute('''
117
  INSERT OR REPLACE INTO sessions (session_id, title, created_at, last_activity, message_count)
118
  VALUES (?, ?, ?, ?,
@@ -127,17 +118,14 @@ class DatabaseManager:
127
  raise Exception(f"Failed to add message to database: {str(e)}")
128
 
129
  def search_messages(self, query: str, filters: Dict = None) -> List[Dict]:
130
- """Pencarian pesan dengan berbagai filter"""
131
  try:
132
  with sqlite3.connect(self.db_path) as conn:
133
  conn.row_factory = sqlite3.Row
134
-
135
  base_query = '''
136
  SELECT * FROM messages
137
  WHERE content LIKE ? COLLATE NOCASE
138
  '''
139
  params = [f'%{query}%']
140
-
141
  if filters:
142
  if filters.get('topic'):
143
  base_query += ' AND topic = ?'
@@ -154,26 +142,21 @@ class DatabaseManager:
154
  if filters.get('date_to'):
155
  base_query += ' AND timestamp <= ?'
156
  params.append(filters['date_to'])
157
-
158
  base_query += ' ORDER BY timestamp DESC LIMIT 100'
159
-
160
  cursor = conn.execute(base_query, params)
161
  results = []
162
  for row in cursor.fetchall():
163
  result = dict(row)
164
  result['tags'] = json.loads(result['tags']) if result['tags'] else []
165
  results.append(result)
166
-
167
  return results
168
  except sqlite3.Error as e:
169
  raise Exception(f"Failed to search messages: {str(e)}")
170
 
171
  def get_all_messages(self, session_id: str = None) -> List[Dict]:
172
- """Mengambil semua pesan"""
173
  try:
174
  with sqlite3.connect(self.db_path) as conn:
175
  conn.row_factory = sqlite3.Row
176
-
177
  if session_id:
178
  cursor = conn.execute(
179
  'SELECT * FROM messages WHERE session_id = ? ORDER BY timestamp',
@@ -181,19 +164,16 @@ class DatabaseManager:
181
  )
182
  else:
183
  cursor = conn.execute('SELECT * FROM messages ORDER BY timestamp')
184
-
185
  results = []
186
  for row in cursor.fetchall():
187
  result = dict(row)
188
  result['tags'] = json.loads(result['tags']) if result['tags'] else []
189
  results.append(result)
190
-
191
  return results
192
  except sqlite3.Error as e:
193
  raise Exception(f"Failed to get messages: {str(e)}")
194
 
195
  def get_sessions(self) -> List[Dict]:
196
- """Mengambil semua sesi chat"""
197
  try:
198
  with sqlite3.connect(self.db_path) as conn:
199
  conn.row_factory = sqlite3.Row
@@ -206,7 +186,6 @@ class DatabaseManager:
206
  raise Exception(f"Failed to get sessions: {str(e)}")
207
 
208
  def delete_session(self, session_id: str):
209
- """Menghapus sesi dan semua pesannya"""
210
  try:
211
  with self.lock:
212
  with sqlite3.connect(self.db_path) as conn:
@@ -217,20 +196,15 @@ class DatabaseManager:
217
  raise Exception(f"Failed to delete session: {str(e)}")
218
 
219
  def get_statistics(self) -> Dict:
220
- """Statistik database"""
221
  try:
222
  with sqlite3.connect(self.db_path) as conn:
223
  stats = {}
224
-
225
  cursor = conn.execute('SELECT COUNT(*) FROM messages')
226
  stats['total_messages'] = cursor.fetchone()[0]
227
-
228
  cursor = conn.execute('SELECT role, COUNT(*) FROM messages GROUP BY role')
229
  stats['by_role'] = dict(cursor.fetchall())
230
-
231
  cursor = conn.execute('SELECT topic, COUNT(*) FROM messages GROUP BY topic ORDER BY COUNT(*) DESC LIMIT 10')
232
  stats['by_topic'] = dict(cursor.fetchall())
233
-
234
  cursor = conn.execute('''
235
  SELECT DATE(timestamp) as date, COUNT(*)
236
  FROM messages
@@ -238,17 +212,13 @@ class DatabaseManager:
238
  ORDER BY date DESC LIMIT 30
239
  ''')
240
  stats['by_date'] = dict(cursor.fetchall())
241
-
242
  cursor = conn.execute('SELECT COUNT(*) FROM sessions')
243
  stats['total_sessions'] = cursor.fetchone()[0]
244
-
245
  return stats
246
  except sqlite3.Error as e:
247
  raise Exception(f"Failed to get statistics: {str(e)}")
248
 
249
  class ChatStorage:
250
- """Handles persistent JSON storage dan database untuk chat history"""
251
-
252
  def __init__(self):
253
  self.history_file = HISTORY_FILE
254
  self.analytics_file = ANALYTICS_FILE
@@ -259,7 +229,6 @@ class ChatStorage:
259
  self.sync_to_database()
260
 
261
  def sync_to_database(self):
262
- """Sinkronisasi data dari JSON ke database"""
263
  try:
264
  if self.chat_history and not self.db.get_all_messages():
265
  print("πŸ”„ Syncing JSON data to database...")
@@ -318,7 +287,6 @@ class ChatStorage:
318
  print(f"❌ Error saving analytics: {e}")
319
 
320
  def add_message(self, role: str, content: str, topic: str = "general", tags: List[str] = None):
321
- """Menambah pesan ke storage dan database"""
322
  if not content.strip():
323
  raise ValueError("Content cannot be empty")
324
  if len(topic) > 100:
@@ -416,7 +384,6 @@ class ChatStorage:
416
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
417
  backup_dir = STORAGE_DIR / "backups"
418
  backup_dir.mkdir(exist_ok=True)
419
-
420
  for file in [HISTORY_FILE, ANALYTICS_FILE]:
421
  if file.exists():
422
  backup_path = backup_dir / f"{file.name}.{timestamp}.bak"
@@ -424,14 +391,12 @@ class ChatStorage:
424
  dst.write(src.read())
425
  if not backup_path.exists():
426
  raise Exception(f"Failed to create backup for {file.name}")
427
-
428
  db_backup_path = backup_dir / f"chat_database.db.{timestamp}.bak"
429
  with sqlite3.connect(self.db.db_path) as src_conn:
430
  with sqlite3.connect(db_backup_path) as dst_conn:
431
  src_conn.backup(dst_conn)
432
  if not db_backup_path.exists():
433
  raise Exception("Failed to create database backup")
434
-
435
  return f"βœ… Backup created at {backup_dir}"
436
  except Exception as e:
437
  return f"❌ Backup failed: {str(e)}"
@@ -468,8 +433,6 @@ class ChatStorage:
468
  print(f"❌ Error updating analytics from import: {e}")
469
 
470
  class AdvancedSearchManager:
471
- """Manager untuk pencarian lanjutan"""
472
-
473
  def __init__(self, storage: ChatStorage):
474
  self.storage = storage
475
 
@@ -569,8 +532,6 @@ class AdvancedSearchManager:
569
  raise Exception(f"Failed to get conversation thread: {str(e)}")
570
 
571
  class SmartAnalyzer:
572
- """Advanced analytics untuk chat history dengan database"""
573
-
574
  def __init__(self, storage: ChatStorage):
575
  self.storage = storage
576
 
@@ -739,7 +700,7 @@ class SmartAnalyzer:
739
  "avg_messages_per_session": len(all_messages) / len(set(msg.get("session_id", "default") for msg in all_messages)) if all_messages else 0
740
  }
741
  except Exception as e:
742
- return {"error": f"Failed to get productivity insights: {str(e)}"}
743
 
744
  def _calculate_consistency(self, daily_activity: Dict) -> float:
745
  try:
@@ -753,13 +714,12 @@ class SmartAnalyzer:
753
  except Exception as e:
754
  raise Exception(f"Failed to calculate consistency: {str(e)}")
755
 
756
- # Initialize storage dan components
757
  storage = ChatStorage()
758
  analyzer = SmartAnalyzer(storage)
759
  search_manager = AdvancedSearchManager(storage)
760
 
761
  def count_tokens_rough(text: str) -> int:
762
- """Estimasi token count"""
763
  try:
764
  return len(text) // 4
765
  except Exception as e:
@@ -767,7 +727,6 @@ def count_tokens_rough(text: str) -> int:
767
  return 0
768
 
769
  def groq_with_memory(message: str, topic: str = "general", retries: int = 3) -> tuple:
770
- """Main chat function dengan Groq API"""
771
  if not API_KEY:
772
  return "❌ No API Key found. Please set GROQ_API_KEY environment variable.", ""
773
 
@@ -824,7 +783,7 @@ def groq_with_memory(message: str, topic: str = "general", retries: int = 3) ->
824
  return f"❌ No response: {result}", ""
825
  except HTTPError as e:
826
  if response.status_code == 429 and attempt < retries - 1:
827
- sleep(2 ** attempt) # Exponential backoff
828
  continue
829
  return f"❌ HTTP {response.status_code}: {response.text}", ""
830
 
@@ -834,7 +793,6 @@ def groq_with_memory(message: str, topic: str = "general", retries: int = 3) ->
834
  return f"❌ Error: {str(e)}", ""
835
 
836
  def cleanup_old_messages(days: int = 30) -> str:
837
- """Hapus pesan yang lebih lama dari jumlah hari tertentu"""
838
  try:
839
  cutoff = (datetime.now() - timedelta(days=days)).isoformat()
840
  with sqlite3.connect(storage.db.db_path) as conn:
@@ -846,8 +804,7 @@ def cleanup_old_messages(days: int = 30) -> str:
846
  except Exception as e:
847
  return f"❌ Failed to clean old messages: {str(e)}"
848
 
849
- # ... all imports, classes (ChatMessage, DatabaseManager, ChatStorage, AdvancedSearchManager, SmartAnalyzer), and other code ...
850
-
851
  def get_topics_list() -> List[str]:
852
  """Retrieve a list of unique topics from the database, ensuring 'journal' is included."""
853
  try:
@@ -863,20 +820,22 @@ def get_topics_list() -> List[str]:
863
  print(f"❌ Error retrieving topics: {str(e)}")
864
  return ["All Topics", "journal"]
865
 
866
- def send_message(user_input: str, topic_input: str) -> Tuple[str, str]:
867
- """Handle sending a user message and getting AI response."""
868
  try:
869
  if not user_input.strip():
870
- return "❌ Please enter a message", user_input
871
  if not topic_input.strip():
872
- return "❌ Please enter a topic", user_input
873
 
874
  response, error = groq_with_memory(user_input, topic_input)
875
  if error:
876
- return f"❌ {error}", user_input
877
- return response, "" # Clear user input after successful submission
 
 
878
  except Exception as e:
879
- return f"❌ Error processing message: {str(e)}", user_input
880
 
881
  def show_current_context() -> str:
882
  """Show the current session's conversation context."""
@@ -1002,7 +961,7 @@ def export_data() -> str:
1002
  except Exception as e:
1003
  return f"❌ Error exporting data: {str(e)}"
1004
 
1005
- # Define custom CSS
1006
  custom_css = """
1007
  /* Full-screen layout: remove padding and margins, use full width */
1008
  .gradio-container {
@@ -1010,8 +969,8 @@ custom_css = """
1010
  max-width: 100% !important;
1011
  padding: 0 !important;
1012
  margin: 0 !important;
1013
- background-color: #000000 !important; /* Black background */
1014
- color: #ffffff !important; /* White text for contrast */
1015
  }
1016
 
1017
  /* Remove padding and ensure full-width components */
@@ -1020,14 +979,14 @@ custom_css = """
1020
  margin: 0 !important;
1021
  width: 100% !important;
1022
  box-sizing: border-box !important;
1023
- border: 1px solid #333333 !important; /* Subtle border for visibility */
1024
  }
1025
 
1026
  /* Textbox and input styling */
1027
  .response-area, .history-display, .analytics-display {
1028
- background-color: #1a1a1a !important; /* Dark gray for textboxes to improve readability */
1029
  color: #ffffff !important;
1030
- border-radius: 0 !important; /* Remove rounded corners for full-screen look */
1031
  }
1032
 
1033
  /* Input area */
@@ -1040,10 +999,10 @@ custom_css = """
1040
  /* Font styling */
1041
  * {
1042
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
1043
- font-size: 16px !important; /* Slightly larger for readability */
1044
  }
1045
 
1046
- /* Button styling for contrast */
1047
  button {
1048
  background-color: #333333 !important;
1049
  color: #ffffff !important;
@@ -1066,11 +1025,6 @@ select {
1066
  }
1067
  """
1068
 
1069
- # Initialize storage and components
1070
- storage = ChatStorage()
1071
- analyzer = SmartAnalyzer(storage)
1072
- search_manager = AdvancedSearchManager(storage)
1073
-
1074
  # Main Gradio Interface
1075
  with gr.Blocks(
1076
  title="πŸ€– AI Journal Chat with Analytics",
@@ -1189,7 +1143,7 @@ with gr.Blocks(
1189
  send_btn.click(
1190
  fn=send_message,
1191
  inputs=[user_input, topic_input],
1192
- outputs=[ai_response, user_input]
1193
  )
1194
 
1195
  clear_response_btn.click(
 
32
 
33
  @dataclass
34
  class ChatMessage:
 
35
  role: str
36
  content: str
37
  topic: str
 
49
  self.message_id = str(uuid.uuid4())
50
 
51
  class DatabaseManager:
 
 
52
  def __init__(self):
53
  self.db_path = DATABASE_FILE
54
  self.lock = threading.Lock()
55
  self.init_database()
56
 
57
  def init_database(self):
 
58
  try:
59
  with sqlite3.connect(self.db_path) as conn:
60
  conn.execute('''
 
72
  content_hash TEXT
73
  )
74
  ''')
 
75
  conn.execute('''
76
  CREATE TABLE IF NOT EXISTS sessions (
77
  session_id TEXT PRIMARY KEY,
 
81
  message_count INTEGER DEFAULT 0
82
  )
83
  ''')
 
84
  conn.execute('CREATE INDEX IF NOT EXISTS idx_content ON messages(content)')
85
  conn.execute('CREATE INDEX IF NOT EXISTS idx_topic ON messages(topic)')
86
  conn.execute('CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp)')
87
  conn.execute('CREATE INDEX IF NOT EXISTS idx_session ON messages(session_id)')
88
  conn.execute('CREATE INDEX IF NOT EXISTS idx_role ON messages(role)')
 
89
  conn.commit()
90
  except sqlite3.Error as e:
91
  raise Exception(f"Failed to initialize database: {str(e)}")
92
 
93
  def add_message(self, message: ChatMessage):
 
94
  try:
95
  with self.lock:
96
  content_hash = hashlib.md5(message.content.encode('utf-8')).hexdigest()
 
104
  message.timestamp, message.word_count, message.char_count,
105
  message.session_id, json.dumps(message.tags), content_hash
106
  ))
 
107
  conn.execute('''
108
  INSERT OR REPLACE INTO sessions (session_id, title, created_at, last_activity, message_count)
109
  VALUES (?, ?, ?, ?,
 
118
  raise Exception(f"Failed to add message to database: {str(e)}")
119
 
120
  def search_messages(self, query: str, filters: Dict = None) -> List[Dict]:
 
121
  try:
122
  with sqlite3.connect(self.db_path) as conn:
123
  conn.row_factory = sqlite3.Row
 
124
  base_query = '''
125
  SELECT * FROM messages
126
  WHERE content LIKE ? COLLATE NOCASE
127
  '''
128
  params = [f'%{query}%']
 
129
  if filters:
130
  if filters.get('topic'):
131
  base_query += ' AND topic = ?'
 
142
  if filters.get('date_to'):
143
  base_query += ' AND timestamp <= ?'
144
  params.append(filters['date_to'])
 
145
  base_query += ' ORDER BY timestamp DESC LIMIT 100'
 
146
  cursor = conn.execute(base_query, params)
147
  results = []
148
  for row in cursor.fetchall():
149
  result = dict(row)
150
  result['tags'] = json.loads(result['tags']) if result['tags'] else []
151
  results.append(result)
 
152
  return results
153
  except sqlite3.Error as e:
154
  raise Exception(f"Failed to search messages: {str(e)}")
155
 
156
  def get_all_messages(self, session_id: str = None) -> List[Dict]:
 
157
  try:
158
  with sqlite3.connect(self.db_path) as conn:
159
  conn.row_factory = sqlite3.Row
 
160
  if session_id:
161
  cursor = conn.execute(
162
  'SELECT * FROM messages WHERE session_id = ? ORDER BY timestamp',
 
164
  )
165
  else:
166
  cursor = conn.execute('SELECT * FROM messages ORDER BY timestamp')
 
167
  results = []
168
  for row in cursor.fetchall():
169
  result = dict(row)
170
  result['tags'] = json.loads(result['tags']) if result['tags'] else []
171
  results.append(result)
 
172
  return results
173
  except sqlite3.Error as e:
174
  raise Exception(f"Failed to get messages: {str(e)}")
175
 
176
  def get_sessions(self) -> List[Dict]:
 
177
  try:
178
  with sqlite3.connect(self.db_path) as conn:
179
  conn.row_factory = sqlite3.Row
 
186
  raise Exception(f"Failed to get sessions: {str(e)}")
187
 
188
  def delete_session(self, session_id: str):
 
189
  try:
190
  with self.lock:
191
  with sqlite3.connect(self.db_path) as conn:
 
196
  raise Exception(f"Failed to delete session: {str(e)}")
197
 
198
  def get_statistics(self) -> Dict:
 
199
  try:
200
  with sqlite3.connect(self.db_path) as conn:
201
  stats = {}
 
202
  cursor = conn.execute('SELECT COUNT(*) FROM messages')
203
  stats['total_messages'] = cursor.fetchone()[0]
 
204
  cursor = conn.execute('SELECT role, COUNT(*) FROM messages GROUP BY role')
205
  stats['by_role'] = dict(cursor.fetchall())
 
206
  cursor = conn.execute('SELECT topic, COUNT(*) FROM messages GROUP BY topic ORDER BY COUNT(*) DESC LIMIT 10')
207
  stats['by_topic'] = dict(cursor.fetchall())
 
208
  cursor = conn.execute('''
209
  SELECT DATE(timestamp) as date, COUNT(*)
210
  FROM messages
 
212
  ORDER BY date DESC LIMIT 30
213
  ''')
214
  stats['by_date'] = dict(cursor.fetchall())
 
215
  cursor = conn.execute('SELECT COUNT(*) FROM sessions')
216
  stats['total_sessions'] = cursor.fetchone()[0]
 
217
  return stats
218
  except sqlite3.Error as e:
219
  raise Exception(f"Failed to get statistics: {str(e)}")
220
 
221
  class ChatStorage:
 
 
222
  def __init__(self):
223
  self.history_file = HISTORY_FILE
224
  self.analytics_file = ANALYTICS_FILE
 
229
  self.sync_to_database()
230
 
231
  def sync_to_database(self):
 
232
  try:
233
  if self.chat_history and not self.db.get_all_messages():
234
  print("πŸ”„ Syncing JSON data to database...")
 
287
  print(f"❌ Error saving analytics: {e}")
288
 
289
  def add_message(self, role: str, content: str, topic: str = "general", tags: List[str] = None):
 
290
  if not content.strip():
291
  raise ValueError("Content cannot be empty")
292
  if len(topic) > 100:
 
384
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
385
  backup_dir = STORAGE_DIR / "backups"
386
  backup_dir.mkdir(exist_ok=True)
 
387
  for file in [HISTORY_FILE, ANALYTICS_FILE]:
388
  if file.exists():
389
  backup_path = backup_dir / f"{file.name}.{timestamp}.bak"
 
391
  dst.write(src.read())
392
  if not backup_path.exists():
393
  raise Exception(f"Failed to create backup for {file.name}")
 
394
  db_backup_path = backup_dir / f"chat_database.db.{timestamp}.bak"
395
  with sqlite3.connect(self.db.db_path) as src_conn:
396
  with sqlite3.connect(db_backup_path) as dst_conn:
397
  src_conn.backup(dst_conn)
398
  if not db_backup_path.exists():
399
  raise Exception("Failed to create database backup")
 
400
  return f"βœ… Backup created at {backup_dir}"
401
  except Exception as e:
402
  return f"❌ Backup failed: {str(e)}"
 
433
  print(f"❌ Error updating analytics from import: {e}")
434
 
435
  class AdvancedSearchManager:
 
 
436
  def __init__(self, storage: ChatStorage):
437
  self.storage = storage
438
 
 
532
  raise Exception(f"Failed to get conversation thread: {str(e)}")
533
 
534
  class SmartAnalyzer:
 
 
535
  def __init__(self, storage: ChatStorage):
536
  self.storage = storage
537
 
 
700
  "avg_messages_per_session": len(all_messages) / len(set(msg.get("session_id", "default") for msg in all_messages)) if all_messages else 0
701
  }
702
  except Exception as e:
703
+ return {"error": f"Failed to get productivity insights: {str(e)}")
704
 
705
  def _calculate_consistency(self, daily_activity: Dict) -> float:
706
  try:
 
714
  except Exception as e:
715
  raise Exception(f"Failed to calculate consistency: {str(e)}")
716
 
717
+ # Initialize storage and components
718
  storage = ChatStorage()
719
  analyzer = SmartAnalyzer(storage)
720
  search_manager = AdvancedSearchManager(storage)
721
 
722
  def count_tokens_rough(text: str) -> int:
 
723
  try:
724
  return len(text) // 4
725
  except Exception as e:
 
727
  return 0
728
 
729
  def groq_with_memory(message: str, topic: str = "general", retries: int = 3) -> tuple:
 
730
  if not API_KEY:
731
  return "❌ No API Key found. Please set GROQ_API_KEY environment variable.", ""
732
 
 
783
  return f"❌ No response: {result}", ""
784
  except HTTPError as e:
785
  if response.status_code == 429 and attempt < retries - 1:
786
+ sleep(2 ** attempt)
787
  continue
788
  return f"❌ HTTP {response.status_code}: {response.text}", ""
789
 
 
793
  return f"❌ Error: {str(e)}", ""
794
 
795
  def cleanup_old_messages(days: int = 30) -> str:
 
796
  try:
797
  cutoff = (datetime.now() - timedelta(days=days)).isoformat()
798
  with sqlite3.connect(storage.db.db_path) as conn:
 
804
  except Exception as e:
805
  return f"❌ Failed to clean old messages: {str(e)}"
806
 
807
+ # Helper Functions
 
808
  def get_topics_list() -> List[str]:
809
  """Retrieve a list of unique topics from the database, ensuring 'journal' is included."""
810
  try:
 
820
  print(f"❌ Error retrieving topics: {str(e)}")
821
  return ["All Topics", "journal"]
822
 
823
+ def send_message(user_input: str, topic_input: str) -> Tuple[str, str, List[str]]:
824
+ """Handle sending a user message, getting AI response, and updating topic list."""
825
  try:
826
  if not user_input.strip():
827
+ return "❌ Please enter a message", user_input, get_topics_list()
828
  if not topic_input.strip():
829
+ return "❌ Please enter a topic", user_input, get_topics_list()
830
 
831
  response, error = groq_with_memory(user_input, topic_input)
832
  if error:
833
+ return f"❌ {error}", user_input, get_topics_list()
834
+
835
+ # Return updated topic list to refresh dropdown
836
+ return response, "", get_topics_list()
837
  except Exception as e:
838
+ return f"❌ Error processing message: {str(e)}", user_input, get_topics_list()
839
 
840
  def show_current_context() -> str:
841
  """Show the current session's conversation context."""
 
961
  except Exception as e:
962
  return f"❌ Error exporting data: {str(e)}"
963
 
964
+ # Define custom CSS for full-screen, readable font, and black background
965
  custom_css = """
966
  /* Full-screen layout: remove padding and margins, use full width */
967
  .gradio-container {
 
969
  max-width: 100% !important;
970
  padding: 0 !important;
971
  margin: 0 !important;
972
+ background-color: #000000 !important;
973
+ color: #ffffff !important;
974
  }
975
 
976
  /* Remove padding and ensure full-width components */
 
979
  margin: 0 !important;
980
  width: 100% !important;
981
  box-sizing: border-box !important;
982
+ border: 1px solid #333333 !important;
983
  }
984
 
985
  /* Textbox and input styling */
986
  .response-area, .history-display, .analytics-display {
987
+ background-color: #1a1a1a !important;
988
  color: #ffffff !important;
989
+ border-radius: 0 !important;
990
  }
991
 
992
  /* Input area */
 
999
  /* Font styling */
1000
  * {
1001
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
1002
+ font-size: 16px !important;
1003
  }
1004
 
1005
+ /* Button styling */
1006
  button {
1007
  background-color: #333333 !important;
1008
  color: #ffffff !important;
 
1025
  }
1026
  """
1027
 
 
 
 
 
 
1028
  # Main Gradio Interface
1029
  with gr.Blocks(
1030
  title="πŸ€– AI Journal Chat with Analytics",
 
1143
  send_btn.click(
1144
  fn=send_message,
1145
  inputs=[user_input, topic_input],
1146
+ outputs=[ai_response, user_input, topic_filter]
1147
  )
1148
 
1149
  clear_response_btn.click(