awacke1 commited on
Commit
3117ef3
β€’
1 Parent(s): 22ec79b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -133
app.py CHANGED
@@ -18,7 +18,7 @@ from openai import OpenAI
18
  import extra_streamlit_components as stx
19
  from streamlit.runtime.scriptrunner import get_script_run_ctx
20
  import asyncio
21
- import edge_tts # ensure this is installed (pip install edge-tts)
22
 
23
  # πŸ”§ Config & Setup
24
  st.set_page_config(
@@ -45,6 +45,10 @@ st.session_state.setdefault('chat_history', [])
45
  st.session_state.setdefault('openai_model', "gpt-4o-2024-05-13")
46
  st.session_state.setdefault('messages', [])
47
  st.session_state.setdefault('last_voice_input', "")
 
 
 
 
48
 
49
  # 🎨 Minimal Custom CSS
50
  st.markdown("""
@@ -57,7 +61,11 @@ st.markdown("""
57
  </style>
58
  """, unsafe_allow_html=True)
59
 
60
- # πŸ”‘ Common Utilities
 
 
 
 
61
  def generate_filename(prompt, file_type="md"):
62
  ctz = pytz.timezone('US/Central')
63
  date_str = datetime.now(ctz).strftime("%m%d_%H%M")
@@ -68,7 +76,7 @@ def generate_filename(prompt, file_type="md"):
68
  def create_file(filename, prompt, response):
69
  with open(filename, 'w', encoding='utf-8') as f:
70
  f.write(prompt + "\n\n" + response)
71
- st.experimental_rerun()
72
 
73
  def get_download_link(file):
74
  with open(file, "rb") as f:
@@ -87,8 +95,6 @@ def speech_synthesis_html(result):
87
  """
88
  components.html(html_code, height=0)
89
 
90
- #------------add EdgeTTS
91
- # --- NEW FUNCTIONS FOR EDGE TTS ---
92
  async def edge_tts_generate_audio(text, voice="en-US-AriaNeural", rate=0, pitch=0):
93
  if not text.strip():
94
  return None
@@ -97,7 +103,7 @@ async def edge_tts_generate_audio(text, voice="en-US-AriaNeural", rate=0, pitch=
97
  communicate = edge_tts.Communicate(text, voice, rate=rate_str, pitch=pitch_str)
98
  out_fn = generate_filename(text,"mp3")
99
  await communicate.save(out_fn)
100
- st.experimental_rerun()
101
  return out_fn
102
 
103
  def speak_with_edge_tts(text, voice="en-US-AriaNeural", rate=0, pitch=0):
@@ -129,7 +135,7 @@ def process_audio(audio_path):
129
  with open(audio_path, "rb") as f:
130
  transcription = openai_client.audio.transcriptions.create(model="whisper-1", file=f)
131
  st.session_state.messages.append({"role": "user", "content": transcription.text})
132
- st.experimental_rerun()
133
  return transcription.text
134
 
135
  def process_video(video_path, seconds_per_frame=1):
@@ -182,26 +188,21 @@ def perform_ai_lookup(q, vocal_summary=True, extended_refs=False, titles_summary
182
 
183
  st.markdown(result)
184
 
185
- # Main Vocal Summary (Short Answer)
186
  if vocal_summary:
187
- start_main_part = time.time()
188
  audio_file_main = speak_with_edge_tts(r2, voice="en-US-AriaNeural", rate=0, pitch=0)
189
  st.write("### πŸŽ™οΈ Vocal Summary (Short Answer)")
190
  play_and_download_audio(audio_file_main)
191
- st.write(f"**Elapsed (Short Answer):** {time.time() - start_main_part:.2f} s")
192
 
193
- # Extended References & Summaries (optional)
194
  if extended_refs:
195
- start_refs_part = time.time()
196
  summaries_text = "Here are the summaries from the references: " + refs.replace('"','')
197
  audio_file_refs = speak_with_edge_tts(summaries_text, voice="en-US-AriaNeural", rate=0, pitch=0)
198
  st.write("### πŸ“œ Extended References & Summaries")
199
  play_and_download_audio(audio_file_refs)
200
- st.write(f"**Elapsed (Extended References):** {time.time() - start_refs_part:.2f} s")
201
 
202
- # Paper Titles Only (short)
203
  if titles_summary:
204
- start_titles_part = time.time()
205
  titles = []
206
  for line in refs.split('\n'):
207
  m = re.search(r"\[([^\]]+)\]", line)
@@ -212,7 +213,6 @@ def perform_ai_lookup(q, vocal_summary=True, extended_refs=False, titles_summary
212
  audio_file_titles = speak_with_edge_tts(titles_text, voice="en-US-AriaNeural", rate=0, pitch=0)
213
  st.write("### πŸ”– Paper Titles")
214
  play_and_download_audio(audio_file_titles)
215
- st.write(f"**Elapsed (Titles):** {time.time() - start_titles_part:.2f} s")
216
 
217
  elapsed = time.time()-start
218
  st.write(f"**Total Elapsed:** {elapsed:.2f} s")
@@ -235,8 +235,7 @@ def process_with_gpt(text):
235
  st.write("GPT-4o: " + ans)
236
  create_file(generate_filename(text,"md"),text,ans)
237
  st.session_state.messages.append({"role":"assistant","content":ans})
238
- st.experimental_rerun()
239
- return ans
240
 
241
  def process_with_claude(text):
242
  if not text: return
@@ -252,18 +251,17 @@ def process_with_claude(text):
252
  st.write("Claude: " + ans)
253
  create_file(generate_filename(text,"md"),text,ans)
254
  st.session_state.chat_history.append({"user":text,"claude":ans})
255
- st.experimental_rerun()
256
- return ans
257
 
258
  def create_zip_of_files():
259
- md_files = glob.glob("Media/*.md")
260
- mp3_files = glob.glob("Media/*.mp3")
261
  all_files = md_files + mp3_files
262
  zip_name = "all_files.zip"
263
  with zipfile.ZipFile(zip_name,'w') as z:
264
  for f in all_files:
265
  z.write(f)
266
- st.experimental_rerun()
267
  return zip_name
268
 
269
  def get_media_html(p,typ="video",w="100%"):
@@ -273,109 +271,109 @@ def get_media_html(p,typ="video",w="100%"):
273
  else:
274
  return f'<audio controls style="width:{w};"><source src="data:audio/mpeg;base64,{d}" type="audio/mpeg"></audio>'
275
 
276
- MEDIA_DIR = "Media"
277
-
278
- def load_md_mp3_pairs():
279
- # This function groups .md and .mp3 files by their filename stem
280
- files = glob.glob(os.path.join(MEDIA_DIR,"*.md")) + glob.glob(os.path.join(MEDIA_DIR,"*.mp3"))
281
- grouped = defaultdict(dict)
282
- for f in files:
283
- base = os.path.basename(f)
284
- stem, ext = os.path.splitext(base)
285
- ext = ext.lower()
286
- if ext == '.md':
287
- grouped[stem]['md'] = f
288
- elif ext == '.mp3':
289
- grouped[stem]['mp3'] = f
290
- return grouped
291
-
292
- def display_files_sidebar():
293
- st.sidebar.title("πŸ“‚ Files")
294
- pairs = load_md_mp3_pairs()
295
-
296
- # Sort by modification time of the MD if exists, else mp3. Descending by latest mod time.
297
- def mod_time(pair):
298
- # Return the newest mod time of available files in the pair
299
- times = []
300
- for f in pair.values():
301
- times.append(os.path.getmtime(f))
302
- return max(times)
303
- sorted_pairs = sorted(pairs.items(), key=lambda x: mod_time(x[1]), reverse=True)
304
-
305
- for stem, files_dict in sorted_pairs:
306
- with st.sidebar.expander(f"**{stem}**"):
307
- # Display action buttons per file type
308
- # If MD file exists:
309
- if 'md' in files_dict:
310
- md_file = files_dict['md']
311
- c1, c2, c3, c4 = st.columns([2,1,1,1])
312
- with c1:
313
- st.write("**Markdown File**")
314
- with c2:
315
- if st.button("πŸ‘€ View", key="view_md_"+stem):
316
- content = open(md_file,'r',encoding='utf-8').read()
317
- st.markdown("**MD File Content:**")
318
- st.markdown(content)
319
- with c3:
320
- # Edit name/content
321
- if st.button("✏️ Edit", key="edit_md_"+stem):
322
- st.session_state.editing_md = stem
323
- st.experimental_rerun()
324
- with c4:
325
- if st.button("πŸ—‘ Delete", key="del_md_"+stem):
326
- os.remove(md_file)
327
- st.experimental_rerun()
328
- else:
329
- st.write("No .md file for this stem.")
330
-
331
- # If MP3 file exists:
332
- if 'mp3' in files_dict:
333
- mp3_file = files_dict['mp3']
334
- c1, c2, c3 = st.columns([2,1,1])
335
- with c1:
336
- st.write("**Audio File**")
337
- with c2:
338
- if st.button("πŸ‘€ View", key="view_mp3_"+stem):
339
- st.audio(mp3_file)
340
- with c3:
341
- if st.button("πŸ—‘ Delete", key="del_mp3_"+stem):
342
- os.remove(mp3_file)
343
- st.experimental_rerun()
344
- else:
345
- st.write("No .mp3 file for this stem.")
346
-
347
- # Button to create a zip of all files
348
- if len(pairs) > 0:
349
- if st.sidebar.button("⬇️ Download All (.md and .mp3)"):
350
- z = create_zip_of_files()
351
- st.sidebar.markdown(get_download_link(z),unsafe_allow_html=True)
352
-
353
- # If editing an MD file:
354
- if 'editing_md' in st.session_state:
355
- stem = st.session_state.editing_md
356
- pairs = load_md_mp3_pairs()
357
- files_dict = pairs.get(stem, {})
358
- if 'md' in files_dict:
359
- md_file = files_dict['md']
360
- content = open(md_file,'r',encoding='utf-8').read()
361
- st.sidebar.subheader(f"Editing: {stem}.md")
362
- new_stem = st.sidebar.text_input("New stem (filename without extension):", value=stem)
363
- new_content = st.sidebar.text_area("Content:", content, height=200)
364
- if st.sidebar.button("Save Changes"):
365
- # If name changed, rename the file
366
- if new_stem != stem:
367
- new_path = os.path.join(MEDIA_DIR, new_stem+".md")
368
- os.rename(md_file, new_path)
369
- md_file = new_path
370
  # Update content
371
- with open(md_file,'w',encoding='utf-8') as f:
372
- f.write(new_content)
373
- del st.session_state.editing_md
374
- st.experimental_rerun()
375
- if st.sidebar.button("Cancel"):
376
- del st.session_state.editing_md
377
  st.experimental_rerun()
378
-
 
 
 
379
 
380
  def main():
381
  st.sidebar.markdown("### 🚲BikeAIπŸ† Multi-Agent Research AI")
@@ -469,36 +467,42 @@ def main():
469
  st.header("🎬 Media Gallery - Images and Videos")
470
  tabs = st.tabs(["πŸ–ΌοΈ Images", "πŸŽ₯ Video"])
471
  with tabs[0]:
472
- imgs = glob.glob("Media/*.png")+glob.glob("Media/*.jpg")
473
  if imgs:
474
  c = st.slider("Cols",1,5,3)
475
  cols = st.columns(c)
476
  for i,f in enumerate(imgs):
477
  with cols[i%c]:
478
  st.image(Image.open(f),use_container_width=True)
479
- if st.button(f"πŸ‘€ Analyze {os.path.basename(f)}", key=f"analyze_{f}"):
480
  a = process_image(f,"Describe this image.")
481
  st.markdown(a)
482
  else:
483
  st.write("No images found.")
484
  with tabs[1]:
485
- vids = glob.glob("Media/*.mp4")
486
  if vids:
487
  for v in vids:
488
  with st.expander(f"πŸŽ₯ {os.path.basename(v)}"):
489
  st.markdown(get_media_html(v,"video"),unsafe_allow_html=True)
490
- if st.button(f"Analyze {os.path.basename(v)}", key=f"analyze_{v}"):
491
  a = process_video_with_gpt(v,"Describe video.")
492
  st.markdown(a)
493
  else:
494
  st.write("No videos found.")
495
 
496
  elif tab_main == "πŸ“ File Editor":
497
- st.write("Use the sidebar to edit .md files by clicking the ✏️ button on the desired file.")
498
-
499
-
500
- # Display file list last to ensure updates
501
- display_files_sidebar()
 
 
 
 
 
 
502
 
503
  if __name__=="__main__":
504
  main()
 
18
  import extra_streamlit_components as stx
19
  from streamlit.runtime.scriptrunner import get_script_run_ctx
20
  import asyncio
21
+ import edge_tts
22
 
23
  # πŸ”§ Config & Setup
24
  st.set_page_config(
 
45
  st.session_state.setdefault('openai_model', "gpt-4o-2024-05-13")
46
  st.session_state.setdefault('messages', [])
47
  st.session_state.setdefault('last_voice_input', "")
48
+ # For editing .md files
49
+ st.session_state.setdefault('editing_file', None)
50
+ st.session_state.setdefault('edit_new_name', "")
51
+ st.session_state.setdefault('edit_new_content', "")
52
 
53
  # 🎨 Minimal Custom CSS
54
  st.markdown("""
 
61
  </style>
62
  """, unsafe_allow_html=True)
63
 
64
+ FILE_EMOJIS = {
65
+ "md": "πŸ“",
66
+ "mp3": "🎡",
67
+ }
68
+
69
  def generate_filename(prompt, file_type="md"):
70
  ctz = pytz.timezone('US/Central')
71
  date_str = datetime.now(ctz).strftime("%m%d_%H%M")
 
76
  def create_file(filename, prompt, response):
77
  with open(filename, 'w', encoding='utf-8') as f:
78
  f.write(prompt + "\n\n" + response)
79
+ st.rerun()
80
 
81
  def get_download_link(file):
82
  with open(file, "rb") as f:
 
95
  """
96
  components.html(html_code, height=0)
97
 
 
 
98
  async def edge_tts_generate_audio(text, voice="en-US-AriaNeural", rate=0, pitch=0):
99
  if not text.strip():
100
  return None
 
103
  communicate = edge_tts.Communicate(text, voice, rate=rate_str, pitch=pitch_str)
104
  out_fn = generate_filename(text,"mp3")
105
  await communicate.save(out_fn)
106
+ st.rerun()
107
  return out_fn
108
 
109
  def speak_with_edge_tts(text, voice="en-US-AriaNeural", rate=0, pitch=0):
 
135
  with open(audio_path, "rb") as f:
136
  transcription = openai_client.audio.transcriptions.create(model="whisper-1", file=f)
137
  st.session_state.messages.append({"role": "user", "content": transcription.text})
138
+ st.rerun()
139
  return transcription.text
140
 
141
  def process_video(video_path, seconds_per_frame=1):
 
188
 
189
  st.markdown(result)
190
 
191
+ # Vocal summary
192
  if vocal_summary:
 
193
  audio_file_main = speak_with_edge_tts(r2, voice="en-US-AriaNeural", rate=0, pitch=0)
194
  st.write("### πŸŽ™οΈ Vocal Summary (Short Answer)")
195
  play_and_download_audio(audio_file_main)
 
196
 
197
+ # Extended refs
198
  if extended_refs:
 
199
  summaries_text = "Here are the summaries from the references: " + refs.replace('"','')
200
  audio_file_refs = speak_with_edge_tts(summaries_text, voice="en-US-AriaNeural", rate=0, pitch=0)
201
  st.write("### πŸ“œ Extended References & Summaries")
202
  play_and_download_audio(audio_file_refs)
 
203
 
204
+ # Titles only
205
  if titles_summary:
 
206
  titles = []
207
  for line in refs.split('\n'):
208
  m = re.search(r"\[([^\]]+)\]", line)
 
213
  audio_file_titles = speak_with_edge_tts(titles_text, voice="en-US-AriaNeural", rate=0, pitch=0)
214
  st.write("### πŸ”– Paper Titles")
215
  play_and_download_audio(audio_file_titles)
 
216
 
217
  elapsed = time.time()-start
218
  st.write(f"**Total Elapsed:** {elapsed:.2f} s")
 
235
  st.write("GPT-4o: " + ans)
236
  create_file(generate_filename(text,"md"),text,ans)
237
  st.session_state.messages.append({"role":"assistant","content":ans})
238
+ return ans
 
239
 
240
  def process_with_claude(text):
241
  if not text: return
 
251
  st.write("Claude: " + ans)
252
  create_file(generate_filename(text,"md"),text,ans)
253
  st.session_state.chat_history.append({"user":text,"claude":ans})
254
+ return ans
 
255
 
256
  def create_zip_of_files():
257
+ md_files = glob.glob("*.md")
258
+ mp3_files = glob.glob("*.mp3")
259
  all_files = md_files + mp3_files
260
  zip_name = "all_files.zip"
261
  with zipfile.ZipFile(zip_name,'w') as z:
262
  for f in all_files:
263
  z.write(f)
264
+ st.rerun()
265
  return zip_name
266
 
267
  def get_media_html(p,typ="video",w="100%"):
 
271
  else:
272
  return f'<audio controls style="width:{w};"><source src="data:audio/mpeg;base64,{d}" type="audio/mpeg"></audio>'
273
 
274
+ def display_file_manager():
275
+ st.sidebar.title("🎡 Audio & Document Manager")
276
+ st.sidebar.markdown("Lists .mp3 and .md files with emojis and sorted by file type count and mod time.")
277
+
278
+ # Gather all md and mp3 files
279
+ md_files = glob.glob("*.md")
280
+ mp3_files = glob.glob("*.mp3")
281
+
282
+ # Group by extension
283
+ files_by_ext = defaultdict(list)
284
+ for f in md_files:
285
+ ext = "md"
286
+ files_by_ext[ext].append(f)
287
+ for f in mp3_files:
288
+ ext = "mp3"
289
+ files_by_ext[ext].append(f)
290
+
291
+ # Sort each extension group by modification time descending
292
+ for ext in files_by_ext:
293
+ files_by_ext[ext].sort(key=lambda x: os.path.getmtime(x), reverse=True)
294
+
295
+ # Sort extensions by number of files descending
296
+ sorted_ext = sorted(files_by_ext.keys(), key=lambda x: len(files_by_ext[x]), reverse=True)
297
+
298
+ # Delete all buttons
299
+ del_col = st.sidebar.columns(2)
300
+ with del_col[0]:
301
+ if st.button("πŸ—‘ Delete All MD"):
302
+ for f in md_files:
303
+ os.remove(f)
304
+ st.rerun()
305
+ with del_col[1]:
306
+ if st.button("πŸ—‘ Delete All MP3"):
307
+ for f in mp3_files:
308
+ os.remove(f)
309
+ st.rerun()
310
+
311
+ # Show groups
312
+ for ext in sorted_ext:
313
+ emoji = FILE_EMOJIS.get(ext, "πŸ“¦")
314
+ count = len(files_by_ext[ext])
315
+ with st.sidebar.expander(f"{emoji} {ext.upper()} Files ({count})"):
316
+ for f in files_by_ext[ext]:
317
+ fname = os.path.basename(f)
318
+ ctime = datetime.fromtimestamp(os.path.getmtime(f)).strftime("%Y-%m-%d %H:%M:%S")
319
+ col1, col2, col3, col4 = st.columns([2,1,1,1])
320
+ with col1:
321
+ st.write(f"**{fname}** - {ctime}")
322
+ with col2:
323
+ # View button
324
+ if ext == "md":
325
+ if st.button("πŸ‘€", key="view_"+f):
326
+ content = open(f,'r',encoding='utf-8').read()
327
+ st.write("**Viewing file content:**")
328
+ st.markdown(content)
329
+ else: # mp3
330
+ if st.button("πŸ‘€", key="view_"+f):
331
+ st.write(f"Playing: {fname}")
332
+ st.audio(f)
333
+ with col3:
334
+ # Edit button for MD
335
+ if ext == "md":
336
+ if st.button("✏️", key="edit_"+f):
337
+ st.session_state.editing_file = f
338
+ st.session_state.edit_new_name = fname.replace(".md","")
339
+ st.session_state.edit_new_content = open(f,'r',encoding='utf-8').read()
340
+ st.rerun()
341
+ else:
342
+ # No edit for mp3
343
+ pass
344
+ with col4:
345
+ # Delete button
346
+ if st.button("πŸ—‘", key="del_"+f):
347
+ os.remove(f)
348
+ st.rerun()
349
+
350
+ # Download all as zip
351
+ if (len(md_files) > 0 or len(mp3_files) > 0) and st.sidebar.button("⬇️ Download All (.md and .mp3)"):
352
+ z = create_zip_of_files()
353
+ st.sidebar.markdown(get_download_link(z),unsafe_allow_html=True)
354
+
355
+ # If editing an md file
356
+ if st.session_state.editing_file and os.path.exists(st.session_state.editing_file):
357
+ st.sidebar.subheader(f"Editing: {os.path.basename(st.session_state.editing_file)}")
358
+ st.session_state.edit_new_name = st.sidebar.text_input("New name (without extension):", value=st.session_state.edit_new_name)
359
+ st.session_state.edit_new_content = st.sidebar.text_area("Content:", st.session_state.edit_new_content, height=200)
360
+ c1,c2 = st.sidebar.columns(2)
361
+ with c1:
362
+ if st.button("Save Changes"):
363
+ old_path = st.session_state.editing_file
364
+ new_path = st.session_state.edit_new_name + ".md"
365
+ # Rename file if name changed
366
+ if new_path != os.path.basename(old_path):
367
+ os.rename(old_path, new_path)
368
  # Update content
369
+ with open(new_path,'w',encoding='utf-8') as f:
370
+ f.write(st.session_state.edit_new_content)
371
+ st.session_state.editing_file = None
 
 
 
372
  st.experimental_rerun()
373
+ with c2:
374
+ if st.button("Cancel"):
375
+ st.session_state.editing_file = None
376
+ st.rerun()
377
 
378
  def main():
379
  st.sidebar.markdown("### 🚲BikeAIπŸ† Multi-Agent Research AI")
 
467
  st.header("🎬 Media Gallery - Images and Videos")
468
  tabs = st.tabs(["πŸ–ΌοΈ Images", "πŸŽ₯ Video"])
469
  with tabs[0]:
470
+ imgs = glob.glob("*.png")+glob.glob("*.jpg")
471
  if imgs:
472
  c = st.slider("Cols",1,5,3)
473
  cols = st.columns(c)
474
  for i,f in enumerate(imgs):
475
  with cols[i%c]:
476
  st.image(Image.open(f),use_container_width=True)
477
+ if st.button(f"πŸ‘€ Analyze {os.path.basename(f)}"):
478
  a = process_image(f,"Describe this image.")
479
  st.markdown(a)
480
  else:
481
  st.write("No images found.")
482
  with tabs[1]:
483
+ vids = glob.glob("*.mp4")
484
  if vids:
485
  for v in vids:
486
  with st.expander(f"πŸŽ₯ {os.path.basename(v)}"):
487
  st.markdown(get_media_html(v,"video"),unsafe_allow_html=True)
488
+ if st.button(f"Analyze {os.path.basename(v)}"):
489
  a = process_video_with_gpt(v,"Describe video.")
490
  st.markdown(a)
491
  else:
492
  st.write("No videos found.")
493
 
494
  elif tab_main == "πŸ“ File Editor":
495
+ if getattr(st.session_state,'current_file',None):
496
+ st.subheader(f"Editing: {st.session_state.current_file}")
497
+ new_text = st.text_area("Content:", st.session_state.file_content, height=300)
498
+ if st.button("Save"):
499
+ with open(st.session_state.current_file,'w',encoding='utf-8') as f:
500
+ f.write(new_text)
501
+ st.success("Updated!")
502
+ else:
503
+ st.write("Select a file from the sidebar to edit.")
504
+
505
+ display_file_manager()
506
 
507
  if __name__=="__main__":
508
  main()