awacke1 commited on
Commit
579d117
Β·
verified Β·
1 Parent(s): 0cc168b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +247 -259
app.py CHANGED
@@ -106,15 +106,9 @@ if 'last_query' not in st.session_state:
106
  if 'marquee_content' not in st.session_state:
107
  st.session_state['marquee_content'] = "πŸš€ Welcome to TalkingAIResearcher | πŸ€– Your Research Assistant"
108
 
109
- # To track user checkboxes for Claude / Arxiv / Autorun / AutoSave
110
- if 'run_claude' not in st.session_state:
111
- st.session_state['run_claude'] = True # enabled by default
112
- if 'run_arxiv' not in st.session_state:
113
- st.session_state['run_arxiv'] = False # disabled by default
114
- if 'autorun_searches' not in st.session_state:
115
- st.session_state['autorun_searches'] = False
116
- if 'autosave_output' not in st.session_state:
117
- st.session_state['autosave_output'] = False
118
 
119
  # API Keys
120
  openai_api_key = os.getenv('OPENAI_API_KEY', "")
@@ -134,7 +128,14 @@ API_URL = os.getenv('API_URL')
134
  FILE_EMOJIS = {
135
  "md": "πŸ“",
136
  "mp3": "🎡",
137
- "wav": "πŸ”Š"
 
 
 
 
 
 
 
138
  }
139
 
140
  # ─────────────────────────────────────────────────────────
@@ -305,23 +306,18 @@ def play_and_download_audio(file_path, file_type="mp3"):
305
  st.markdown(dl_link, unsafe_allow_html=True)
306
 
307
  def save_qa_with_audio(question, answer, voice=None):
308
- """Save Q&A to markdown and also generate audio, returning file paths."""
309
  if not voice:
310
  voice = st.session_state['tts_voice']
311
 
312
  combined_text = f"# Question\n{question}\n\n# Answer\n{answer}"
313
- md_file = None
314
- audio_file = None
315
-
316
- # Only create the files if autosave is enabled
317
- if st.session_state['autosave_output']:
318
- md_file = create_file(question, answer, "md")
319
- audio_text = f"{question}\n\nAnswer: {answer}"
320
- audio_file = speak_with_edge_tts(
321
- audio_text,
322
- voice=voice,
323
- file_format=st.session_state['audio_format']
324
- )
325
  return md_file, audio_file
326
 
327
  # ─────────────────────────────────────────────────────────
@@ -392,12 +388,9 @@ def create_paper_links_md(papers):
392
 
393
  def create_paper_audio_files(papers, input_question):
394
  """
395
- For each paper, generate TTS audio summary if autosave is on,
396
- store the path in `paper['full_audio']`,
397
- and store a base64 link for stable downloading.
398
  """
399
- if not st.session_state['autosave_output']:
400
- return
401
  for paper in papers:
402
  try:
403
  audio_text = f"{paper['title']} by {paper['authors']}. {paper['summary']}"
@@ -457,35 +450,45 @@ def display_papers_in_sidebar(papers):
457
  st.markdown(f"**Summary:** {paper['summary'][:300]}...")
458
 
459
  # ─────────────────────────────────────────────────────────
460
- # 4. ZIP FUNCTION
461
  # ─────────────────────────────────────────────────────────
462
 
463
- def create_zip_of_files(md_files, mp3_files, wav_files, input_question):
464
  """
465
- Zip up all relevant files, limiting the final zip name to ~20 chars
466
  to avoid overly long base64 strings.
467
  """
468
- md_files = [f for f in md_files if os.path.basename(f).lower() != 'readme.md']
469
- all_files = md_files + mp3_files + wav_files
 
 
 
 
 
 
 
 
470
  if not all_files:
471
  return None
472
 
 
473
  all_content = []
474
  for f in all_files:
475
- if f.endswith('.md'):
476
- with open(f, 'r', encoding='utf-8') as file:
477
- all_content.append(file.read())
478
- elif f.endswith('.mp3') or f.endswith('.wav'):
479
- basename = os.path.splitext(os.path.basename(f))[0]
480
- words = basename.replace('_', ' ')
481
- all_content.append(words)
482
-
483
- all_content.append(input_question)
 
484
  combined_content = " ".join(all_content)
485
  info_terms = get_high_info_terms(combined_content, top_n=10)
486
 
487
  timestamp = format_timestamp_prefix()
488
- name_text = '-'.join(term for term in info_terms[:5])
489
  short_zip_name = (timestamp + "_" + name_text)[:20] + ".zip"
490
 
491
  with zipfile.ZipFile(short_zip_name, 'w') as z:
@@ -493,99 +496,102 @@ def create_zip_of_files(md_files, mp3_files, wav_files, input_question):
493
  z.write(f)
494
  return short_zip_name
495
 
 
 
 
 
 
 
 
 
 
 
496
  # ─────────────────────────────────────────────────────────
497
  # 5. MAIN LOGIC: AI LOOKUP & VOICE INPUT
498
  # ─────────────────────────────────────────────────────────
499
 
500
- def run_claude_search(q):
501
- """Call Anthropic (Claude) for the user's query."""
 
 
 
 
502
  client = anthropic.Anthropic(api_key=anthropic_key)
 
503
  response = client.messages.create(
504
  model="claude-3-sonnet-20240229",
505
  max_tokens=1000,
506
  messages=[
507
- {"role": "user", "content": q}
508
  ])
509
- result = response.content[0].text
 
510
 
511
- st.write("### Claude's reply 🧠:")
512
- st.markdown(result)
513
- return result
 
 
 
514
 
515
- def run_arxiv_search(q):
516
- """Call the Arxiv RAG pipeline for the user's query."""
517
- st.write("### Arxiv's AI: Mixtral 8x7B RAG")
518
  client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
519
  refs = client.predict(
520
- q,
521
- 10, # topK
522
  "Semantic Search",
523
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
524
  api_name="/update_with_rag_md"
525
  )[0]
526
-
527
  r2 = client.predict(
528
  q,
529
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
530
  True,
531
  api_name="/ask_llm"
532
  )
533
-
534
- # Combine the final result
535
  result = f"### πŸ”Ž {q}\n\n{r2}\n\n{refs}"
536
- st.markdown(result)
 
 
537
 
538
- # Parse + handle papers
539
  papers = parse_arxiv_refs(refs)
540
  if papers:
541
- # Create minimal links page if autosave is on
542
- if st.session_state['autosave_output']:
543
- paper_links = create_paper_links_md(papers)
544
- create_file(q, paper_links, "md")
545
 
 
546
  create_paper_audio_files(papers, input_question=q)
547
  display_papers(papers, get_marquee_settings())
548
  display_papers_in_sidebar(papers)
549
  else:
550
  st.warning("No papers found in the response.")
551
- return result
552
 
553
- def perform_selections(q):
554
- """
555
- Checks which search(s) are enabled and runs them in sequence,
556
- returning a combined response string.
557
- """
558
- combined_response = ""
559
-
560
- if st.session_state['run_claude']:
561
- claude_response = run_claude_search(q)
562
- combined_response += "\n\nCLAUDE:\n" + claude_response
563
-
564
- if st.session_state['run_arxiv']:
565
- arxiv_response = run_arxiv_search(q)
566
- combined_response += "\n\nARXIV:\n" + arxiv_response
567
-
568
- return combined_response
569
 
570
  def process_voice_input(text):
571
- """When user sends voice query, we run whichever searches are enabled."""
572
  if not text:
573
  return
574
  st.subheader("πŸ” Search Results")
575
- # 1) Run the searches user has checked
576
- result = perform_selections(text)
577
-
578
- # 2) If autosave is turned on, store Q&A output
 
 
 
579
  md_file, audio_file = save_qa_with_audio(text, result)
580
-
581
- # 3) If we saved TTS audio, play it
582
- if audio_file:
583
- st.subheader("πŸ“ Generated Audio")
584
- play_and_download_audio(audio_file, st.session_state['audio_format'])
585
-
586
- # 4) Refresh the sidebar file listing if autosave was used
587
- if st.session_state['autosave_output']:
588
- display_file_history_in_sidebar()
589
 
590
  # ─────────────────────────────────────────────────────────
591
  # 6. FILE HISTORY SIDEBAR
@@ -593,171 +599,146 @@ def process_voice_input(text):
593
 
594
  def display_file_history_in_sidebar():
595
  """
596
- Shows a history of each local .md, .mp3, .wav file in descending
597
  order of modification time, with quick icons and optional download links.
598
  """
599
  st.sidebar.markdown("---")
600
  st.sidebar.markdown("### πŸ“‚ File History")
601
 
602
- # Add Delete All and Download All buttons in a row
603
- col1, col2 = st.sidebar.columns(2)
604
- with col1:
605
- if st.button("πŸ—‘οΈ Delete All"):
606
- # Delete all files except README.md
607
- for pattern in ["*.md", "*.mp3", "*.wav", "*.mp4"]:
608
- for f in glob.glob(pattern):
609
- if f.lower() != "readme.md":
610
- try:
611
- os.remove(f)
612
- except Exception as e:
613
- st.warning(f"Error deleting {f}: {str(e)}")
614
- st.rerun()
615
-
616
- with col2:
617
- # Get all files for potential zip
618
- md_files = [f for f in glob.glob("*.md") if f.lower() != "readme.md"]
619
- mp3_files = glob.glob("*.mp3")
620
- wav_files = glob.glob("*.wav")
621
-
622
- if md_files or mp3_files or wav_files:
623
- zip_name = "Download.zip"
624
- if 'last_query' in st.session_state and st.session_state['last_query']:
625
- # Use last_query in the zip name
626
- clean_q = clean_text_for_filename(st.session_state['last_query'])[:30]
627
- if clean_q:
628
- zip_name = f"{clean_q}.zip"
629
-
630
- if st.button("πŸ“¦ Download All"):
631
- with zipfile.ZipFile(zip_name, 'w') as z:
632
- for f in md_files + mp3_files + wav_files:
633
- z.write(f)
634
- st.sidebar.markdown(get_download_link(zip_name), unsafe_allow_html=True)
635
-
636
- # Gather all files
637
- md_files = glob.glob("*.md")
638
- mp3_files = glob.glob("*.mp3")
639
- wav_files = glob.glob("*.wav")
640
- all_files = md_files + mp3_files + wav_files
641
 
642
  if not all_files:
643
  st.sidebar.write("No files found.")
644
  return
645
 
646
- # Sort by modification time descending
647
- all_files_sorted = sorted(all_files, key=os.path.getmtime, reverse=True)
648
-
649
- for f in all_files_sorted:
650
- ext = os.path.splitext(f)[1].lower().replace('.', '')
651
- emoji = FILE_EMOJIS.get(ext, "πŸ“")
652
- mod_time = datetime.fromtimestamp(os.path.getmtime(f)).strftime("%m-%d %H:%M")
653
- # Download link
654
- dl_link = get_download_link(f, file_type=ext)
655
- with st.sidebar.expander(f"{emoji} {os.path.basename(f)} [{mod_time}]"):
656
- if ext in ["mp3", "wav"]:
657
- st.audio(f)
658
  if ext == "md":
659
- with open(f, 'r', encoding='utf-8') as file:
660
- content = file.read()
661
- st.markdown(f"```\n{content[:500]}\n...```")
662
- st.markdown(dl_link, unsafe_allow_html=True)
 
 
 
 
 
 
 
663
 
664
  # ─────────────────────────────────────────────────────────
665
  # 7. MAIN APP
666
  # ─────────────────────────────────────────────────────────
667
 
668
  def main():
669
- # 1) Setup marquee UI in the sidebar
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
670
  update_marquee_settings_ui()
671
  marquee_settings = get_marquee_settings()
672
 
673
- # 2) Place the radio for main tabs AND the row of checkboxes
674
- colA, colB, colC, colD, colE = st.columns([2,1,1,1,1])
675
- with colA:
676
- tab_main = st.radio("Action:", ["🎀 Voice", "πŸ“Έ Media", "πŸ” ArXiv", "πŸ“ Editor"], horizontal=True)
677
- with colB:
678
- st.session_state['run_claude'] = st.checkbox("Claude", value=st.session_state['run_claude'])
679
- with colC:
680
- st.session_state['run_arxiv'] = st.checkbox("Arxiv", value=st.session_state['run_arxiv'])
681
- with colD:
682
- st.session_state['autorun_searches'] = st.checkbox("Autorun", value=st.session_state['autorun_searches'])
683
- with colE:
684
- st.session_state['autosave_output'] = st.checkbox("AutoSave", value=st.session_state['autosave_output'])
685
-
686
- # 3) Display the marquee welcome
687
  display_marquee(st.session_state['marquee_content'],
688
  {**marquee_settings, "font-size": "28px", "lineHeight": "50px"},
689
  key_suffix="welcome")
690
 
691
- # Example custom component usage:
692
- mycomponent = components.declare_component("mycomponent", path="mycomponent")
693
- val = mycomponent(my_input_value="Hello")
694
-
695
- if val:
696
- val_stripped = val.replace('\\n', ' ')
697
- edited_input = st.text_area("✏️ Edit Input:", value=val_stripped, height=100)
698
- run_option = st.selectbox("Model:", ["Arxiv"])
699
- full_audio = st.checkbox("πŸ“šFullAudio", value=False)
700
- input_changed = (val != st.session_state.old_val)
701
-
702
- # We'll define: if autorun is on, run immediately after input changes
703
- if st.session_state['autorun_searches'] and input_changed:
704
- st.session_state.old_val = val
705
- st.session_state.last_query = edited_input
706
- process_voice_input(edited_input)
707
- else:
708
- if st.button("β–Ά Run"):
709
- st.session_state.old_val = val
710
- st.session_state.last_query = edited_input
711
- process_voice_input(edited_input)
712
-
713
- # ────────���────────────────────────────────────────────────
714
- # TAB: ArXiv
715
- # (kept for demonstration if user chooses to do Arxiv only)
716
- # ─────────────────────────────────────────────────────────
717
- if tab_main == "πŸ” ArXiv":
718
- st.subheader("πŸ” Query ArXiv")
719
- q = st.text_input("πŸ” Query:", key="arxiv_query")
720
-
721
- if q and st.button("πŸ”Run"):
722
- st.session_state.last_query = q
723
- # Even if the tab is "ArXiv," we can just call our standard function
724
- # that uses whichever checkboxes are selected (or you can do Arxiv only).
725
- process_voice_input(q)
726
 
727
- # ─────────────────────────────────────────────────────────
728
- # TAB: Voice
729
- # ─────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
730
  elif tab_main == "🎀 Voice":
731
  st.subheader("🎀 Voice Input")
732
-
733
- st.markdown("### 🎀 Voice Settings")
734
- selected_voice = st.selectbox(
735
- "Select TTS Voice:",
736
- options=EDGE_TTS_VOICES,
737
- index=EDGE_TTS_VOICES.index(st.session_state['tts_voice'])
738
- if st.session_state['tts_voice'] in EDGE_TTS_VOICES
739
- else 0
740
- )
741
-
742
- st.markdown("### πŸ”Š Audio Format")
743
- selected_format = st.radio(
744
- "Choose Audio Format:",
745
- options=["MP3", "WAV"],
746
- index=0 if st.session_state['audio_format'] == "mp3" else 1
747
- )
748
-
749
- # Update session state if voice/format changes
750
- if selected_voice != st.session_state['tts_voice']:
751
- st.session_state['tts_voice'] = selected_voice
752
- st.rerun()
753
- if selected_format.lower() != st.session_state['audio_format']:
754
- st.session_state['audio_format'] = selected_format.lower()
755
- st.rerun()
756
-
757
- user_text = st.text_area("πŸ’¬ Message:", height=100).strip().replace('\n', ' ')
758
  if st.button("πŸ“¨ Send"):
759
- st.session_state.last_query = user_text
760
- # If autorun is off, we explicitly run
761
  process_voice_input(user_text)
762
 
763
  st.subheader("πŸ“œ Chat History")
@@ -765,14 +746,10 @@ def main():
765
  st.write("**You:**", c["user"])
766
  st.write("**Response:**", c["claude"])
767
 
768
- # ─────────────────────────────────────────────────────────
769
- # TAB: Media
770
- # ─────────────────────────────────────────────────────────
771
  elif tab_main == "πŸ“Έ Media":
772
  st.header("πŸ“Έ Media Gallery")
773
  tabs = st.tabs(["🎡 Audio", "πŸ–Ό Images", "πŸŽ₯ Video"])
774
-
775
- # AUDIO sub-tab
776
  with tabs[0]:
777
  st.subheader("🎡 Audio Files")
778
  audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
@@ -785,8 +762,6 @@ def main():
785
  st.markdown(dl_link, unsafe_allow_html=True)
786
  else:
787
  st.write("No audio files found.")
788
-
789
- # IMAGES sub-tab
790
  with tabs[1]:
791
  st.subheader("πŸ–Ό Image Files")
792
  imgs = glob.glob("*.png") + glob.glob("*.jpg") + glob.glob("*.jpeg")
@@ -798,8 +773,6 @@ def main():
798
  st.image(Image.open(f), use_container_width=True)
799
  else:
800
  st.write("No images found.")
801
-
802
- # VIDEO sub-tab
803
  with tabs[2]:
804
  st.subheader("πŸŽ₯ Video Files")
805
  vids = glob.glob("*.mp4") + glob.glob("*.mov") + glob.glob("*.avi")
@@ -810,30 +783,45 @@ def main():
810
  else:
811
  st.write("No videos found.")
812
 
813
- # ─────────────────────────────────────────────────────────
814
- # TAB: Editor
815
- # ─────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
816
  elif tab_main == "πŸ“ Editor":
817
  st.write("Select or create a file to edit. (Currently minimal demo)")
818
 
819
- # ─────────────────────────────────────────────────────────
820
- # SIDEBAR: FILE HISTORY
821
- # ─────────────────────────────────────────────────────────
822
- display_file_history_in_sidebar()
823
-
824
- # Some light CSS styling
825
- st.markdown("""
826
- <style>
827
- .main { background: linear-gradient(to right, #1a1a1a, #2d2d2d); color: #fff; }
828
- .stMarkdown { font-family: 'Helvetica Neue', sans-serif; }
829
- .stButton>button { margin-right: 0.5rem; }
830
- </style>
831
- """, unsafe_allow_html=True)
832
-
833
  # Rerun if needed
834
  if st.session_state.should_rerun:
835
  st.session_state.should_rerun = False
836
- st.rerun()
837
 
838
  if __name__ == "__main__":
839
  main()
 
106
  if 'marquee_content' not in st.session_state:
107
  st.session_state['marquee_content'] = "πŸš€ Welcome to TalkingAIResearcher | πŸ€– Your Research Assistant"
108
 
109
+ # New: default AutoRun to False (off)
110
+ if 'autorun' not in st.session_state:
111
+ st.session_state['autorun'] = False
 
 
 
 
 
 
112
 
113
  # API Keys
114
  openai_api_key = os.getenv('OPENAI_API_KEY', "")
 
128
  FILE_EMOJIS = {
129
  "md": "πŸ“",
130
  "mp3": "🎡",
131
+ "wav": "πŸ”Š",
132
+ "pdf": "πŸ“•",
133
+ "mp4": "πŸŽ₯",
134
+ "csv": "πŸ“ˆ",
135
+ "xlsx": "πŸ“Š",
136
+ "html": "🌐",
137
+ "py": "🐍",
138
+ "txt": "πŸ“„"
139
  }
140
 
141
  # ─────────────────────────────────────────────────────────
 
306
  st.markdown(dl_link, unsafe_allow_html=True)
307
 
308
  def save_qa_with_audio(question, answer, voice=None):
309
+ """Save Q&A to markdown and also generate audio."""
310
  if not voice:
311
  voice = st.session_state['tts_voice']
312
 
313
  combined_text = f"# Question\n{question}\n\n# Answer\n{answer}"
314
+ md_file = create_file(question, answer, "md")
315
+ audio_text = f"{question}\n\nAnswer: {answer}"
316
+ audio_file = speak_with_edge_tts(
317
+ audio_text,
318
+ voice=voice,
319
+ file_format=st.session_state['audio_format']
320
+ )
 
 
 
 
 
321
  return md_file, audio_file
322
 
323
  # ─────────────────────────────────────────────────────────
 
388
 
389
  def create_paper_audio_files(papers, input_question):
390
  """
391
+ For each paper, generate TTS audio summary, store the path in `paper['full_audio']`,
392
+ and also store a base64 link for stable downloading.
 
393
  """
 
 
394
  for paper in papers:
395
  try:
396
  audio_text = f"{paper['title']} by {paper['authors']}. {paper['summary']}"
 
450
  st.markdown(f"**Summary:** {paper['summary'][:300]}...")
451
 
452
  # ─────────────────────────────────────────────────────────
453
+ # 4. ZIP & DELETE-ALL UTILS
454
  # ─────────────────────────────────────────────────────────
455
 
456
+ def create_zip_of_all_files():
457
  """
458
+ Zip up all recognized file types, limiting the final zip name to ~20 chars
459
  to avoid overly long base64 strings.
460
  """
461
+ # Patterns for .md, .pdf, .mp4, .mp3, .wav, .csv, .xlsx, .html, .py, .txt
462
+ file_patterns = [
463
+ "*.md", "*.pdf", "*.mp4", "*.mp3", "*.wav",
464
+ "*.csv", "*.xlsx", "*.html", "*.py", "*.txt"
465
+ ]
466
+ all_files = []
467
+ for pat in file_patterns:
468
+ all_files.extend(glob.glob(pat))
469
+ all_files = list(set(all_files)) # unique
470
+
471
  if not all_files:
472
  return None
473
 
474
+ # Combine content for naming
475
  all_content = []
476
  for f in all_files:
477
+ if f.endswith(".md"):
478
+ with open(f, "r", encoding="utf-8") as fin:
479
+ all_content.append(fin.read())
480
+ else:
481
+ all_content.append(os.path.basename(f))
482
+
483
+ # Add last query if relevant
484
+ if st.session_state['last_query']:
485
+ all_content.append(st.session_state['last_query'])
486
+
487
  combined_content = " ".join(all_content)
488
  info_terms = get_high_info_terms(combined_content, top_n=10)
489
 
490
  timestamp = format_timestamp_prefix()
491
+ name_text = '-'.join(term for term in info_terms[:5])
492
  short_zip_name = (timestamp + "_" + name_text)[:20] + ".zip"
493
 
494
  with zipfile.ZipFile(short_zip_name, 'w') as z:
 
496
  z.write(f)
497
  return short_zip_name
498
 
499
+ def delete_all_files():
500
+ """Removes all recognized file types from the directory."""
501
+ file_patterns = [
502
+ "*.md", "*.pdf", "*.mp4", "*.mp3", "*.wav",
503
+ "*.csv", "*.xlsx", "*.html", "*.py", "*.txt"
504
+ ]
505
+ for pat in file_patterns:
506
+ for f in glob.glob(pat):
507
+ os.remove(f)
508
+
509
  # ─────────────────────────────────────────────────────────
510
  # 5. MAIN LOGIC: AI LOOKUP & VOICE INPUT
511
  # ─────────────────────────────────────────────────────────
512
 
513
+ def perform_ai_lookup(q, vocal_summary=True, extended_refs=False,
514
+ titles_summary=True, full_audio=False):
515
+ """Main routine that uses Anthropic (Claude) + Gradio ArXiv RAG pipeline."""
516
+ start = time.time()
517
+
518
+ # --- 1) Claude API
519
  client = anthropic.Anthropic(api_key=anthropic_key)
520
+ user_input = q
521
  response = client.messages.create(
522
  model="claude-3-sonnet-20240229",
523
  max_tokens=1000,
524
  messages=[
525
+ {"role": "user", "content": user_input}
526
  ])
527
+ st.write("Claude's reply 🧠:")
528
+ st.markdown(response.content[0].text)
529
 
530
+ # Save & produce audio
531
+ result = response.content[0].text
532
+ create_file(q, result)
533
+ md_file, audio_file = save_qa_with_audio(q, result)
534
+ st.subheader("πŸ“ Main Response Audio")
535
+ play_and_download_audio(audio_file, st.session_state['audio_format'])
536
 
537
+ # --- 2) Arxiv RAG
538
+ st.write("Arxiv's AI this Evening is Mixtral 8x7B...")
 
539
  client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
540
  refs = client.predict(
541
+ q,
542
+ 20,
543
  "Semantic Search",
544
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
545
  api_name="/update_with_rag_md"
546
  )[0]
 
547
  r2 = client.predict(
548
  q,
549
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
550
  True,
551
  api_name="/ask_llm"
552
  )
553
+
 
554
  result = f"### πŸ”Ž {q}\n\n{r2}\n\n{refs}"
555
+ md_file, audio_file = save_qa_with_audio(q, result)
556
+ st.subheader("πŸ“ Main Response Audio")
557
+ play_and_download_audio(audio_file, st.session_state['audio_format'])
558
 
559
+ # --- 3) Parse + handle papers
560
  papers = parse_arxiv_refs(refs)
561
  if papers:
562
+ # Create minimal links page first
563
+ paper_links = create_paper_links_md(papers)
564
+ links_file = create_file(q, paper_links, "md")
565
+ st.markdown(paper_links)
566
 
567
+ # Then create audio for each paper
568
  create_paper_audio_files(papers, input_question=q)
569
  display_papers(papers, get_marquee_settings())
570
  display_papers_in_sidebar(papers)
571
  else:
572
  st.warning("No papers found in the response.")
 
573
 
574
+ elapsed = time.time() - start
575
+ st.write(f"**Total Elapsed:** {elapsed:.2f} s")
576
+ return result
 
 
 
 
 
 
 
 
 
 
 
 
 
577
 
578
  def process_voice_input(text):
579
+ """When user sends voice query, we run the AI lookup + Q&A with audio."""
580
  if not text:
581
  return
582
  st.subheader("πŸ” Search Results")
583
+ result = perform_ai_lookup(
584
+ text,
585
+ vocal_summary=True,
586
+ extended_refs=False,
587
+ titles_summary=True,
588
+ full_audio=True
589
+ )
590
  md_file, audio_file = save_qa_with_audio(text, result)
591
+ st.subheader("πŸ“ Generated Files")
592
+ st.write(f"Markdown: {md_file}")
593
+ st.write(f"Audio: {audio_file}")
594
+ play_and_download_audio(audio_file, st.session_state['audio_format'])
 
 
 
 
 
595
 
596
  # ─────────────────────────────────────────────────────────
597
  # 6. FILE HISTORY SIDEBAR
 
599
 
600
  def display_file_history_in_sidebar():
601
  """
602
+ Shows a history of each recognized file in descending
603
  order of modification time, with quick icons and optional download links.
604
  """
605
  st.sidebar.markdown("---")
606
  st.sidebar.markdown("### πŸ“‚ File History")
607
 
608
+ # Patterns for .md, .mp3, .wav, .pdf, .mp4, .csv, .xlsx, .html, .py, .txt
609
+ patterns = [
610
+ "*.md", "*.pdf", "*.mp4", "*.mp3", "*.wav",
611
+ "*.csv", "*.xlsx", "*.html", "*.py", "*.txt"
612
+ ]
613
+ all_files = []
614
+ for p in patterns:
615
+ all_files.extend(glob.glob(p))
616
+ all_files = list(set(all_files)) # unique
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
 
618
  if not all_files:
619
  st.sidebar.write("No files found.")
620
  return
621
 
622
+ # Sort newest first
623
+ all_files = sorted(all_files, key=os.path.getmtime, reverse=True)
624
+
625
+ for f in all_files:
626
+ fname = os.path.basename(f)
627
+ ext = os.path.splitext(fname)[1].lower().strip('.')
628
+ emoji = FILE_EMOJIS.get(ext, 'πŸ“¦')
629
+ time_str = datetime.fromtimestamp(os.path.getmtime(f)).strftime("%Y-%m-%d %H:%M:%S")
630
+
631
+ with st.sidebar.expander(f"{emoji} {fname}"):
632
+ st.write(f"**Modified:** {time_str}")
 
633
  if ext == "md":
634
+ with open(f, "r", encoding="utf-8") as file_in:
635
+ snippet = file_in.read(200).replace("\n", " ")
636
+ if len(snippet) == 200:
637
+ snippet += "..."
638
+ st.write(snippet)
639
+ st.markdown(get_download_link(f, file_type="md"), unsafe_allow_html=True)
640
+ elif ext in ["mp3","wav"]:
641
+ st.audio(f)
642
+ st.markdown(get_download_link(f, file_type=ext), unsafe_allow_html=True)
643
+ else:
644
+ st.markdown(get_download_link(f), unsafe_allow_html=True)
645
 
646
  # ─────────────────────────────────────────────────────────
647
  # 7. MAIN APP
648
  # ─────────────────────────────────────────────────────────
649
 
650
  def main():
651
+ """
652
+ Main Streamlit app.
653
+ Now includes:
654
+ 1) Voice & AutoRun at the top of the sidebar,
655
+ 2) File Tools (Delete All / Zip All) in the sidebar,
656
+ 3) A new 'πŸ“€ Upload' tab,
657
+ 4) Everything else from your original code snippet.
658
+ """
659
+
660
+ # -- 1) Voice & AutoRun at top of sidebar --
661
+ st.sidebar.title("Global Settings")
662
+ selected_voice = st.sidebar.selectbox(
663
+ "TTS Voice",
664
+ options=EDGE_TTS_VOICES,
665
+ index=EDGE_TTS_VOICES.index(st.session_state['tts_voice'])
666
+ )
667
+ # Autorun defaults to off (False)
668
+ st.session_state.autorun = st.sidebar.checkbox("AutoRun", value=st.session_state.autorun)
669
+
670
+ # Audio format
671
+ audio_format = st.sidebar.radio("Audio Format", ["MP3","WAV"], index=0)
672
+ if selected_voice != st.session_state['tts_voice']:
673
+ st.session_state['tts_voice'] = selected_voice
674
+ st.experimental_rerun()
675
+ if audio_format.lower() != st.session_state['audio_format']:
676
+ st.session_state['audio_format'] = audio_format.lower()
677
+ st.experimental_rerun()
678
+
679
+ # -- 2) File Tools: Delete All / Zip All
680
+ st.sidebar.markdown("---")
681
+ st.sidebar.markdown("### πŸ—ƒ File Tools")
682
+ col_del, col_zip = st.sidebar.columns(2)
683
+ with col_del:
684
+ if st.button("πŸ—‘ Delete All"):
685
+ delete_all_files()
686
+ st.sidebar.success("All recognized files removed!")
687
+ st.experimental_rerun()
688
+ with col_zip:
689
+ if st.button("πŸ“¦ Zip All"):
690
+ zip_name = create_zip_of_all_files()
691
+ if zip_name:
692
+ st.sidebar.markdown(get_download_link(zip_name, "zip"), unsafe_allow_html=True)
693
+
694
+ # -- 3) Marquee Settings
695
  update_marquee_settings_ui()
696
  marquee_settings = get_marquee_settings()
697
 
698
+ # -- 4) File History in sidebar
699
+ display_file_history_in_sidebar()
700
+
701
+ # -- 5) Display marquee
 
 
 
 
 
 
 
 
 
 
702
  display_marquee(st.session_state['marquee_content'],
703
  {**marquee_settings, "font-size": "28px", "lineHeight": "50px"},
704
  key_suffix="welcome")
705
 
706
+ # -- 6) Main action tabs
707
+ tab_main = st.radio(
708
+ "Action:",
709
+ ["πŸ“€ Upload", "🎀 Voice", "πŸ“Έ Media", "πŸ” ArXiv", "πŸ“ Editor"],
710
+ horizontal=True
711
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
712
 
713
+ # 6a) Upload Tab
714
+ if tab_main == "πŸ“€ Upload":
715
+ st.header("πŸ“€ Upload Files")
716
+ accepted_types = [
717
+ # We'll accept basically everything (None in file_uploader),
718
+ # but let's specify for clarity:
719
+ "text/plain", "text/markdown", "audio/mpeg", "audio/wav",
720
+ "image/png", "image/jpeg", "video/mp4", "application/pdf",
721
+ "application/vnd.ms-excel",
722
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
723
+ "text/html", "application/octet-stream",
724
+ ]
725
+ uploaded = st.file_uploader("Select files to upload:",
726
+ accept_multiple_files=True,
727
+ type=None)
728
+ if uploaded:
729
+ for uf in uploaded:
730
+ with open(uf.name, "wb") as outfile:
731
+ outfile.write(uf.read())
732
+ st.success("Uploaded!")
733
+ st.session_state.should_rerun = True
734
+
735
+ # 6b) Voice Tab
736
  elif tab_main == "🎀 Voice":
737
  st.subheader("🎀 Voice Input")
738
+ user_text = st.text_area("πŸ’¬ Message:", height=100)
739
+ user_text = user_text.strip().replace('\n', ' ')
740
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
741
  if st.button("πŸ“¨ Send"):
 
 
742
  process_voice_input(user_text)
743
 
744
  st.subheader("πŸ“œ Chat History")
 
746
  st.write("**You:**", c["user"])
747
  st.write("**Response:**", c["claude"])
748
 
749
+ # 6c) Media Tab
 
 
750
  elif tab_main == "πŸ“Έ Media":
751
  st.header("πŸ“Έ Media Gallery")
752
  tabs = st.tabs(["🎡 Audio", "πŸ–Ό Images", "πŸŽ₯ Video"])
 
 
753
  with tabs[0]:
754
  st.subheader("🎡 Audio Files")
755
  audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
 
762
  st.markdown(dl_link, unsafe_allow_html=True)
763
  else:
764
  st.write("No audio files found.")
 
 
765
  with tabs[1]:
766
  st.subheader("πŸ–Ό Image Files")
767
  imgs = glob.glob("*.png") + glob.glob("*.jpg") + glob.glob("*.jpeg")
 
773
  st.image(Image.open(f), use_container_width=True)
774
  else:
775
  st.write("No images found.")
 
 
776
  with tabs[2]:
777
  st.subheader("πŸŽ₯ Video Files")
778
  vids = glob.glob("*.mp4") + glob.glob("*.mov") + glob.glob("*.avi")
 
783
  else:
784
  st.write("No videos found.")
785
 
786
+ # 6d) ArXiv Tab
787
+ elif tab_main == "πŸ” ArXiv":
788
+ st.subheader("πŸ” Query ArXiv")
789
+ q = st.text_input("πŸ” Query:", key="arxiv_query")
790
+
791
+ st.markdown("### πŸŽ› Options")
792
+ st.write("(AutoRun is in the sidebar.)")
793
+ extended_refs = st.checkbox("πŸ“œLongRefs", value=False, key="option_extended_refs")
794
+ titles_summary = st.checkbox("πŸ”–TitlesOnly", value=True, key="option_titles_summary")
795
+ full_audio = st.checkbox("πŸ“šFullAudio", value=False, key="option_full_audio")
796
+ full_transcript = st.checkbox("🧾FullTranscript", value=False, key="option_full_transcript")
797
+
798
+ if q and st.button("πŸ”Run"):
799
+ st.session_state.last_query = q
800
+ result = perform_ai_lookup(q,
801
+ extended_refs=extended_refs,
802
+ titles_summary=titles_summary,
803
+ full_audio=full_audio)
804
+ if full_transcript:
805
+ create_file(q, result, "md")
806
+
807
+ # If AutoRun is ON and user typed something
808
+ if st.session_state.autorun and q:
809
+ st.session_state.last_query = q
810
+ result = perform_ai_lookup(q,
811
+ extended_refs=extended_refs,
812
+ titles_summary=titles_summary,
813
+ full_audio=full_audio)
814
+ if full_transcript:
815
+ create_file(q, result, "md")
816
+
817
+ # 6e) Editor Tab
818
  elif tab_main == "πŸ“ Editor":
819
  st.write("Select or create a file to edit. (Currently minimal demo)")
820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  # Rerun if needed
822
  if st.session_state.should_rerun:
823
  st.session_state.should_rerun = False
824
+ st.experimental_rerun()
825
 
826
  if __name__ == "__main__":
827
  main()