awacke1 commited on
Commit
2a7e2ce
โ€ข
1 Parent(s): 8cb9f0c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +863 -348
app.py CHANGED
@@ -21,7 +21,7 @@ from audio_recorder_streamlit import audio_recorder
21
  from bs4 import BeautifulSoup
22
  from collections import deque
23
  from dotenv import load_dotenv
24
- from gradio_client import Client
25
  from huggingface_hub import InferenceClient
26
  from io import BytesIO
27
  from moviepy.editor import VideoFileClip
@@ -30,166 +30,19 @@ from PyPDF2 import PdfReader
30
  from urllib.parse import quote
31
  from xml.etree import ElementTree as ET
32
  from openai import OpenAI
33
- import extra_streamlit_components as stx
34
- from streamlit.runtime.scriptrunner import get_script_run_ctx
35
 
36
- # Configuration constants
37
- Site_Name = '๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI'
38
- title = "๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI"
39
- helpURL = 'https://huggingface.co/awacke1'
40
- bugURL = 'https://huggingface.co/spaces/awacke1'
41
- icons = '๐Ÿšฒ๐Ÿ†'
42
-
43
- # Cookie Management
44
- def get_cookie_manager():
45
- return stx.CookieManager()
46
-
47
- # State Management
48
- def update_transcript_state(new_transcript):
49
- """Update transcript in both session state and cookie"""
50
- cookie_manager = get_cookie_manager()
51
- if new_transcript is not None:
52
- st.session_state.voice_transcript = new_transcript
53
- cookie_manager.set('voice_transcript', new_transcript)
54
- return new_transcript
55
-
56
- # Speech Recognition HTML Template
57
- speech_recognition_html = """
58
- <!DOCTYPE html>
59
- <html>
60
- <head>
61
- <style>
62
- body { font-family: sans-serif; padding: 20px; }
63
- button { padding: 10px 20px; margin: 10px 5px; }
64
- #status { margin: 10px 0; padding: 10px; background: #e8f5e9; }
65
- #output {
66
- white-space: pre-wrap;
67
- padding: 15px;
68
- background: #f5f5f5;
69
- margin: 10px 0;
70
- min-height: 100px;
71
- max-height: 300px;
72
- overflow-y: auto;
73
- }
74
- </style>
75
- </head>
76
- <body>
77
- <div>
78
- <button id="startBtn">Start</button>
79
- <button id="stopBtn" disabled>Stop</button>
80
- <button id="clearBtn">Clear</button>
81
- </div>
82
- <div id="status">Ready</div>
83
- <div id="output"></div>
84
-
85
- <script>
86
- let recognition;
87
- let fullTranscript = '';
88
-
89
- // Function to save state to localStorage
90
- function saveTranscriptState(text) {
91
- localStorage.setItem('voiceTranscript', text);
92
- // Send to Streamlit
93
- window.parent.postMessage({
94
- type: 'streamlit:setComponentValue',
95
- value: JSON.stringify({ transcript: text })
96
- }, '*');
97
- }
98
-
99
- // Function to load state from localStorage
100
- function loadTranscriptState() {
101
- return localStorage.getItem('voiceTranscript') || '';
102
- }
103
-
104
- if ('webkitSpeechRecognition' in window) {
105
- recognition = new webkitSpeechRecognition();
106
- recognition.continuous = true;
107
- recognition.interimResults = true;
108
-
109
- // Load any existing transcript
110
- fullTranscript = loadTranscriptState();
111
- document.getElementById('output').textContent = fullTranscript;
112
-
113
- recognition.onstart = () => {
114
- document.getElementById('status').textContent = 'Listening...';
115
- document.getElementById('startBtn').disabled = true;
116
- document.getElementById('stopBtn').disabled = false;
117
- };
118
 
119
- recognition.onend = () => {
120
- document.getElementById('status').textContent = 'Click Start to begin';
121
- document.getElementById('startBtn').disabled = false;
122
- document.getElementById('stopBtn').disabled = true;
123
- };
124
 
125
- recognition.onresult = (event) => {
126
- let interimTranscript = '';
127
- let finalTranscript = '';
128
-
129
- for (let i = event.resultIndex; i < event.results.length; i++) {
130
- const transcript = event.results[i][0].transcript;
131
- if (event.results[i].isFinal) {
132
- finalTranscript += transcript + ' ';
133
- fullTranscript += transcript + ' ';
134
- } else {
135
- interimTranscript += transcript;
136
- }
137
- }
138
-
139
- if (finalTranscript) {
140
- saveTranscriptState(fullTranscript);
141
- }
142
-
143
- const output = document.getElementById('output');
144
- output.textContent = fullTranscript + interimTranscript;
145
- output.scrollTop = output.scrollHeight;
146
- };
147
-
148
- recognition.onerror = (event) => {
149
- document.getElementById('status').textContent = 'Error: ' + event.error;
150
- document.getElementById('startBtn').disabled = false;
151
- document.getElementById('stopBtn').disabled = true;
152
- };
153
-
154
- // Button handlers
155
- document.getElementById('startBtn').onclick = () => {
156
- try {
157
- recognition.start();
158
- } catch (e) {
159
- document.getElementById('status').textContent = 'Error starting: ' + e;
160
- }
161
- };
162
 
163
- document.getElementById('stopBtn').onclick = () => recognition.stop();
164
 
165
- document.getElementById('clearBtn').onclick = () => {
166
- fullTranscript = '';
167
- document.getElementById('output').textContent = '';
168
- saveTranscriptState('');
169
- localStorage.removeItem('voiceTranscript');
170
- };
171
 
172
- // Auto-start and load saved transcript on page load
173
- window.addEventListener('load', () => {
174
- const savedTranscript = loadTranscriptState();
175
- if (savedTranscript) {
176
- fullTranscript = savedTranscript;
177
- document.getElementById('output').textContent = savedTranscript;
178
- saveTranscriptState(savedTranscript);
179
- }
180
- setTimeout(() => document.getElementById('startBtn').click(), 1000);
181
- });
182
- } else {
183
- document.getElementById('status').textContent = 'Speech recognition not supported in this browser';
184
- document.getElementById('startBtn').disabled = true;
185
- document.getElementById('stopBtn').disabled = true;
186
- }
187
- </script>
188
- </body>
189
- </html>
190
- """
191
 
192
- # Streamlit page configuration
193
  st.set_page_config(
194
  page_title=title,
195
  page_icon=icons,
@@ -202,10 +55,7 @@ st.set_page_config(
202
  }
203
  )
204
 
205
-
206
-
207
-
208
- # Load environment variables and initialize clients
209
  load_dotenv()
210
 
211
  # OpenAI setup
@@ -218,27 +68,353 @@ openai_client = OpenAI(
218
  organization=os.getenv('OPENAI_ORG_ID')
219
  )
220
 
221
- # Claude setup
222
  anthropic_key = os.getenv("ANTHROPIC_API_KEY_3")
223
  if anthropic_key == None:
224
  anthropic_key = st.secrets["ANTHROPIC_API_KEY"]
225
  claude_client = anthropic.Anthropic(api_key=anthropic_key)
226
 
227
- # Initialize session states
228
  if 'transcript_history' not in st.session_state:
229
  st.session_state.transcript_history = []
230
  if "chat_history" not in st.session_state:
231
  st.session_state.chat_history = []
232
  if "openai_model" not in st.session_state:
233
- st.session_state["openai_model"] = "gpt-4-vision-preview"
234
  if "messages" not in st.session_state:
235
  st.session_state.messages = []
236
- if 'voice_transcript' not in st.session_state:
237
- st.session_state.voice_transcript = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
 
239
- # Processing Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  def process_with_gpt(text_input):
241
- """Process text with GPT-4."""
242
  if text_input:
243
  st.session_state.messages.append({"role": "user", "content": text_input})
244
 
@@ -255,9 +431,10 @@ def process_with_gpt(text_input):
255
  stream=False
256
  )
257
  return_text = completion.choices[0].message.content
258
- st.write("GPT-4: " + return_text)
259
 
260
- filename = generate_filename("GPT-4: " + return_text, "md")
 
261
  create_file(filename, text_input, return_text)
262
  st.session_state.messages.append({"role": "assistant", "content": return_text})
263
  return return_text
@@ -265,6 +442,7 @@ def process_with_gpt(text_input):
265
  def process_with_claude(text_input):
266
  """Process text with Claude."""
267
  if text_input:
 
268
  with st.chat_message("user"):
269
  st.markdown(text_input)
270
 
@@ -279,6 +457,7 @@ def process_with_claude(text_input):
279
  response_text = response.content[0].text
280
  st.write("Claude: " + response_text)
281
 
 
282
  filename = generate_filename("Claude: " + response_text, "md")
283
  create_file(filename, text_input, response_text)
284
 
@@ -288,55 +467,420 @@ def process_with_claude(text_input):
288
  })
289
  return response_text
290
 
291
- def perform_ai_lookup(query):
292
- """Perform ArXiv search and analysis."""
293
- client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
294
- start_time = time.strftime("%Y-%m-%d %H:%M:%S")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
 
296
- response1 = client.predict(
297
- query,
298
- 20,
299
- "Semantic Search",
300
- "mistralai/Mixtral-8x7B-Instruct-v0.1",
301
- api_name="/update_with_rag_md"
302
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
- Question = '### ๐Ÿ”Ž ' + query + '\r\n'
305
- References = response1[0]
306
- ReferenceLinks = extract_urls(References)
307
 
308
- results = ''
309
- response2 = client.predict(
310
- query,
311
- "mistralai/Mixtral-8x7B-Instruct-v0.1",
312
- True,
313
- api_name="/ask_llm"
314
- )
315
- if len(response2) > 10:
316
- Answer = response2
317
- results = Question + '\r\n' + Answer + '\r\n' + References + '\r\n' + ReferenceLinks
318
- st.markdown(results)
319
 
320
- end_time = time.strftime("%Y-%m-%d %H:%M:%S")
321
- start_timestamp = time.mktime(time.strptime(start_time, "%Y-%m-%d %H:%M:%S"))
322
- end_timestamp = time.mktime(time.strptime(end_time, "%Y-%m-%d %H:%M:%S"))
323
- elapsed_seconds = end_timestamp - start_timestamp
324
 
325
- st.write('๐Ÿ”Run Complete')
326
- st.write(f"Start time: {start_time}")
327
- st.write(f"Finish time: {end_time}")
328
- st.write(f"Elapsed time: {elapsed_seconds:.2f} seconds")
329
 
330
- filename = generate_filename(query, "md")
331
- create_file(filename, query, results)
332
- return results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  def main():
335
  st.sidebar.markdown("### ๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI")
336
 
337
- # Initialize cookie manager
338
- cookie_manager = get_cookie_manager()
339
-
340
  tab_main = st.radio("Choose Action:",
341
  ["๐ŸŽค Voice Input", "๐Ÿ’ฌ Chat", "๐Ÿ“ธ Media Gallery", "๐Ÿ” Search ArXiv", "๐Ÿ“ File Editor"],
342
  horizontal=True)
@@ -344,78 +888,112 @@ def main():
344
  if tab_main == "๐ŸŽค Voice Input":
345
  st.subheader("Voice Recognition")
346
 
347
- # Initialize/restore state from cookie
348
- saved_transcript = cookie_manager.get('voice_transcript')
349
- if saved_transcript and not st.session_state.voice_transcript:
350
- st.session_state.voice_transcript = saved_transcript
351
-
352
  # Display speech recognition component
353
- st.components.v1.html(speech_recognition_html, height=400)
354
-
355
- # Handle transcript updates with JSON parsing
356
- transcript_receiver = st.components.v1.html("""
357
- <script>
358
- window.addEventListener('message', function(e) {
359
- if (e.data && e.data.type === 'streamlit:setComponentValue') {
360
- try {
361
- const data = JSON.parse(e.data.value);
362
- if (data.transcript !== undefined) {
363
- window.Streamlit.setComponentValue(data);
364
- }
365
- } catch (err) {
366
- console.error('Error parsing transcript data:', err);
367
- }
368
- }
369
- });
370
- </script>
371
  """, height=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
372
 
373
- # Update state if we received new transcript
374
- if transcript_receiver and isinstance(transcript_receiver, dict):
375
- new_transcript = transcript_receiver.get('transcript', '')
376
- update_transcript_state(new_transcript)
377
 
378
- # Display transcript
379
- st.markdown("### Processed Voice Input:")
380
- transcript_text = st.text_area(
381
- "Voice Transcript",
382
- value=st.session_state.voice_transcript if isinstance(st.session_state.voice_transcript, str) else "",
383
- height=100,
384
- key=f"voice_transcript_display_{int(time.time())}" # Unique key to force refresh
385
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
 
387
- # Process buttons
388
- col1, col2, col3 = st.columns(3)
389
- with col1:
390
- if st.button("Process with GPT"):
391
- if st.session_state.voice_transcript:
392
- st.markdown("### GPT Response:")
393
- gpt_response = process_with_gpt(st.session_state.voice_transcript)
394
- st.markdown(gpt_response)
395
 
396
- with col2:
397
- if st.button("Process with Claude"):
398
- if st.session_state.voice_transcript:
399
- st.markdown("### Claude Response:")
400
- claude_response = process_with_claude(st.session_state.voice_transcript)
401
- st.markdown(claude_response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
 
403
- with col3:
404
- if st.button("Clear Transcript"):
405
- update_transcript_state("")
406
- st.experimental_rerun()
407
-
408
- if st.session_state.voice_transcriptif st.session_state.voice_transcript:
409
- if st.button("Search ArXiv"):
410
- st.markdown("### ArXiv Search Results:")
411
- arxiv_results = perform_ai_lookup(st.session_state.voice_transcript)
412
- st.markdown(arxiv_results)
413
 
414
- elif tab_main == "๐Ÿ’ฌ Chat":
415
  # Model Selection
416
  model_choice = st.sidebar.radio(
417
  "Choose AI Model:",
418
- ["GPT-4", "Claude-3", "GPT+Claude+Arxiv"]
419
  )
420
 
421
  # Chat Interface
@@ -423,33 +1001,35 @@ def main():
423
 
424
  if st.button("Send ๐Ÿ“จ"):
425
  if user_input:
426
- if model_choice == "GPT-4":
427
  gpt_response = process_with_gpt(user_input)
428
  elif model_choice == "Claude-3":
429
  claude_response = process_with_claude(user_input)
430
- else: # Both + Arxiv
431
  col1, col2, col3 = st.columns(3)
432
- with col1:
433
- st.subheader("GPT-4:")
434
- try:
435
- gpt_response = process_with_gpt(user_input)
436
- except:
437
- st.write('GPT-4 out of tokens')
438
  with col2:
439
- st.subheader("Claude-3:")
440
  try:
441
  claude_response = process_with_claude(user_input)
442
  except:
443
- st.write('Claude-3 out of tokens')
 
 
 
 
 
 
444
  with col3:
445
- st.subheader("Arxiv Search:")
446
  with st.spinner("Searching ArXiv..."):
 
447
  results = perform_ai_lookup(user_input)
 
448
  st.markdown(results)
449
-
450
  # Display Chat History
451
  st.subheader("Chat History ๐Ÿ“œ")
452
- tab1, tab2 = st.tabs(["Claude History", "GPT-4 History"])
453
 
454
  with tab1:
455
  for chat in st.session_state.chat_history:
@@ -469,7 +1049,7 @@ def main():
469
  query = st.text_input("Enter your research query:")
470
  if query:
471
  with st.spinner("Searching ArXiv..."):
472
- results = perform_ai_lookup(query)
473
  st.markdown(results)
474
 
475
  elif tab_main == "๐Ÿ“ File Editor":
@@ -480,75 +1060,10 @@ def main():
480
  with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
481
  file.write(new_content)
482
  st.success("File updated successfully!")
 
483
 
484
  # Always show file manager in sidebar
485
  display_file_manager()
486
 
487
- # Utility functions for file management
488
- def generate_filename(prompt, file_type):
489
- """Generate a filename based on prompt and time."""
490
- central = pytz.timezone('US/Central')
491
- safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
492
- replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
493
- safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
494
- return f"{safe_date_time}_{safe_prompt}.{file_type}"
495
-
496
- def create_file(filename, prompt, response):
497
- """Create and save a file."""
498
- with open(filename, 'w', encoding='utf-8') as file:
499
- file.write(prompt + "\n\n" + response)
500
-
501
- def load_file(file_name):
502
- """Load file content."""
503
- with open(file_name, "r", encoding='utf-8') as file:
504
- return file.read()
505
-
506
- def create_zip_of_files(files):
507
- """Create zip archive of files."""
508
- zip_name = "all_files.zip"
509
- with zipfile.ZipFile(zip_name, 'w') as zipf:
510
- for file in files:
511
- zipf.write(file)
512
- return zip_name
513
-
514
- def get_download_link(file):
515
- """Create download link for file."""
516
- with open(file, "rb") as f:
517
- contents = f.read()
518
- b64 = base64.b64encode(contents).decode()
519
- return f'<a href="data:file/txt;base64,{b64}" download="{os.path.basename(file)}">Download {os.path.basename(file)}๐Ÿ“‚</a>'
520
-
521
- def extract_urls(text):
522
- """Extract URLs from text."""
523
- try:
524
- date_pattern = re.compile(r'### (\d{2} \w{3} \d{4})')
525
- abs_link_pattern = re.compile(r'\[(.*?)\]\((https://arxiv\.org/abs/\d+\.\d+)\)')
526
- pdf_link_pattern = re.compile(r'\[โฌ‡๏ธ\]\((https://arxiv\.org/pdf/\d+\.\d+)\)')
527
- title_pattern = re.compile(r'### \d{2} \w{3} \d{4} \| \[(.*?)\]')
528
-
529
- date_matches = date_pattern.findall(text)
530
- abs_link_matches = abs_link_pattern.findall(text)
531
- pdf_link_matches = pdf_link_pattern.findall(text)
532
- title_matches = title_pattern.findall(text)
533
-
534
- markdown_text = ""
535
- for i in range(len(date_matches)):
536
- date = date_matches[i]
537
- title = title_matches[i]
538
- abs_link = abs_link_matches[i][1]
539
- pdf_link = pdf_link_matches[i]
540
- markdown_text += f"**Date:** {date}\n\n"
541
- markdown_text += f"**Title:** {title}\n\n"
542
- markdown_text += f"**Abstract Link:** [{abs_link}]({abs_link})\n\n"
543
- markdown_text += f"**PDF Link:** [{pdf_link}]({pdf_link})\n\n"
544
- markdown_text += "---\n\n"
545
- return markdown_text
546
- except:
547
- return ''
548
-
549
- # Run the application
550
  if __name__ == "__main__":
551
- main()
552
-
553
-
554
-
 
21
  from bs4 import BeautifulSoup
22
  from collections import deque
23
  from dotenv import load_dotenv
24
+ from gradio_client import Client, handle_file
25
  from huggingface_hub import InferenceClient
26
  from io import BytesIO
27
  from moviepy.editor import VideoFileClip
 
30
  from urllib.parse import quote
31
  from xml.etree import ElementTree as ET
32
  from openai import OpenAI
 
 
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
 
 
 
 
 
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
 
37
 
 
 
 
 
 
 
38
 
39
+ # 1. ๐ŸšฒBikeAI๐Ÿ† Configuration and Setup
40
+ Site_Name = '๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI'
41
+ title = "๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI"
42
+ helpURL = 'https://huggingface.co/awacke1'
43
+ bugURL = 'https://huggingface.co/spaces/awacke1'
44
+ icons = '๐Ÿšฒ๐Ÿ†'
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
 
46
  st.set_page_config(
47
  page_title=title,
48
  page_icon=icons,
 
55
  }
56
  )
57
 
58
+ # 2. ๐ŸšฒBikeAI๐Ÿ† Load environment variables and initialize clients
 
 
 
59
  load_dotenv()
60
 
61
  # OpenAI setup
 
68
  organization=os.getenv('OPENAI_ORG_ID')
69
  )
70
 
71
+ # 3.๐ŸšฒBikeAI๐Ÿ† Claude setup
72
  anthropic_key = os.getenv("ANTHROPIC_API_KEY_3")
73
  if anthropic_key == None:
74
  anthropic_key = st.secrets["ANTHROPIC_API_KEY"]
75
  claude_client = anthropic.Anthropic(api_key=anthropic_key)
76
 
77
+ # 4.๐ŸšฒBikeAI๐Ÿ† Initialize session states
78
  if 'transcript_history' not in st.session_state:
79
  st.session_state.transcript_history = []
80
  if "chat_history" not in st.session_state:
81
  st.session_state.chat_history = []
82
  if "openai_model" not in st.session_state:
83
+ st.session_state["openai_model"] = "gpt-4o-2024-05-13"
84
  if "messages" not in st.session_state:
85
  st.session_state.messages = []
86
+ if 'last_voice_input' not in st.session_state:
87
+ st.session_state.last_voice_input = ""
88
+
89
+ # 5. ๐ŸšฒBikeAI๐Ÿ† HuggingFace AI setup
90
+ API_URL = os.getenv('API_URL')
91
+ HF_KEY = os.getenv('HF_KEY')
92
+ MODEL1 = "meta-llama/Llama-2-7b-chat-hf"
93
+ MODEL2 = "openai/whisper-small.en"
94
+ headers = {
95
+ "Authorization": f"Bearer {HF_KEY}",
96
+ "Content-Type": "application/json"
97
+ }
98
+
99
+ # 6. ๐ŸšฒBikeAI๐Ÿ† Custom CSS
100
+ st.markdown("""
101
+ <style>
102
+ .main {
103
+ background: linear-gradient(to right, #1a1a1a, #2d2d2d);
104
+ color: #ffffff;
105
+ }
106
+ .stMarkdown {
107
+ font-family: 'Helvetica Neue', sans-serif;
108
+ }
109
+ .category-header {
110
+ background: linear-gradient(45deg, #2b5876, #4e4376);
111
+ padding: 20px;
112
+ border-radius: 10px;
113
+ margin: 10px 0;
114
+ }
115
+ .scene-card {
116
+ background: rgba(0,0,0,0.3);
117
+ padding: 15px;
118
+ border-radius: 8px;
119
+ margin: 10px 0;
120
+ border: 1px solid rgba(255,255,255,0.1);
121
+ }
122
+ .media-gallery {
123
+ display: grid;
124
+ gap: 1rem;
125
+ padding: 1rem;
126
+ }
127
+ .bike-card {
128
+ background: rgba(255,255,255,0.05);
129
+ border-radius: 10px;
130
+ padding: 15px;
131
+ transition: transform 0.3s;
132
+ }
133
+ .bike-card:hover {
134
+ transform: scale(1.02);
135
+ }
136
+ </style>
137
+ """, unsafe_allow_html=True)
138
+
139
+
140
+ # 7. Helper Functions
141
+ def generate_filename(prompt, file_type):
142
+ """Generate a safe filename using the prompt and file type."""
143
+ central = pytz.timezone('US/Central')
144
+ safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
145
+ replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
146
+ safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
147
+ return f"{safe_date_time}_{safe_prompt}.{file_type}"
148
+
149
+
150
+
151
+
152
+ # 8. Function to create and save a file (and avoid the black hole of lost data ๐Ÿ•ณ)
153
+ def create_file(filename, prompt, response, should_save=True):
154
+ if not should_save:
155
+ return
156
+ with open(filename, 'w', encoding='utf-8') as file:
157
+ file.write(prompt + "\n\n" + response)
158
+ def create_and_save_file(content, file_type="md", prompt=None, is_image=False, should_save=True):
159
+ """Create and save file with proper handling of different types."""
160
+ if not should_save:
161
+ return None
162
+ filename = generate_filename(prompt if prompt else content, file_type)
163
+ with open(filename, "w", encoding="utf-8") as f:
164
+ if is_image:
165
+ f.write(content)
166
+ else:
167
+ f.write(prompt + "\n\n" + content if prompt else content)
168
+ return filename
169
 
170
+
171
+ def get_download_link(file_path):
172
+ """Create download link for file."""
173
+ with open(file_path, "rb") as file:
174
+ contents = file.read()
175
+ b64 = base64.b64encode(contents).decode()
176
+ return f'<a href="data:file/txt;base64,{b64}" download="{os.path.basename(file_path)}">Download {os.path.basename(file_path)}๐Ÿ“‚</a>'
177
+
178
+ @st.cache_resource
179
+ def SpeechSynthesis(result):
180
+ """HTML5 Speech Synthesis."""
181
+ documentHTML5 = f'''
182
+ <!DOCTYPE html>
183
+ <html>
184
+ <head>
185
+ <title>Read It Aloud</title>
186
+ <script type="text/javascript">
187
+ function readAloud() {{
188
+ const text = document.getElementById("textArea").value;
189
+ const speech = new SpeechSynthesisUtterance(text);
190
+ window.speechSynthesis.speak(speech);
191
+ }}
192
+ </script>
193
+ </head>
194
+ <body>
195
+ <h1>๐Ÿ”Š Read It Aloud</h1>
196
+ <textarea id="textArea" rows="10" cols="80">{result}</textarea>
197
+ <br>
198
+ <button onclick="readAloud()">๐Ÿ”Š Read Aloud</button>
199
+ </body>
200
+ </html>
201
+ '''
202
+ components.html(documentHTML5, width=1280, height=300)
203
+
204
+ # Media Processing Functions
205
+ def process_image(image_input, user_prompt):
206
+ """Process image with GPT-4o vision."""
207
+ if isinstance(image_input, str):
208
+ with open(image_input, "rb") as image_file:
209
+ image_input = image_file.read()
210
+
211
+ base64_image = base64.b64encode(image_input).decode("utf-8")
212
+
213
+ response = openai_client.chat.completions.create(
214
+ model=st.session_state["openai_model"],
215
+ messages=[
216
+ {"role": "system", "content": "You are a helpful assistant that responds in Markdown."},
217
+ {"role": "user", "content": [
218
+ {"type": "text", "text": user_prompt},
219
+ {"type": "image_url", "image_url": {
220
+ "url": f"data:image/png;base64,{base64_image}"
221
+ }}
222
+ ]}
223
+ ],
224
+ temperature=0.0,
225
+ )
226
+
227
+ return response.choices[0].message.content
228
+
229
+ def process_audio(audio_input, text_input=''):
230
+ """Process audio with Whisper and GPT."""
231
+ if isinstance(audio_input, str):
232
+ with open(audio_input, "rb") as file:
233
+ audio_input = file.read()
234
+
235
+ transcription = openai_client.audio.transcriptions.create(
236
+ model="whisper-1",
237
+ file=audio_input,
238
+ )
239
+
240
+ st.session_state.messages.append({"role": "user", "content": transcription.text})
241
+
242
+ with st.chat_message("assistant"):
243
+ st.markdown(transcription.text)
244
+ SpeechSynthesis(transcription.text)
245
+
246
+ filename = generate_filename(transcription.text, "wav")
247
+ create_and_save_file(audio_input, "wav", transcription.text, True)
248
+
249
+ def process_video(video_path, seconds_per_frame=1):
250
+ """Process video files for frame extraction and audio."""
251
+ base64Frames = []
252
+ video = cv2.VideoCapture(video_path)
253
+ total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
254
+ fps = video.get(cv2.CAP_PROP_FPS)
255
+ frames_to_skip = int(fps * seconds_per_frame)
256
+
257
+ for frame_idx in range(0, total_frames, frames_to_skip):
258
+ video.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
259
+ success, frame = video.read()
260
+ if not success:
261
+ break
262
+ _, buffer = cv2.imencode(".jpg", frame)
263
+ base64Frames.append(base64.b64encode(buffer).decode("utf-8"))
264
+
265
+ video.release()
266
+
267
+ # Extract audio
268
+ base_video_path = os.path.splitext(video_path)[0]
269
+ audio_path = f"{base_video_path}.mp3"
270
+ try:
271
+ video_clip = VideoFileClip(video_path)
272
+ video_clip.audio.write_audiofile(audio_path)
273
+ video_clip.close()
274
+ except:
275
+ st.warning("No audio track found in video")
276
+ audio_path = None
277
+
278
+ return base64Frames, audio_path
279
+
280
+ def process_video_with_gpt(video_input, user_prompt):
281
+ """Process video with GPT-4o vision."""
282
+ base64Frames, audio_path = process_video(video_input)
283
+
284
+ response = openai_client.chat.completions.create(
285
+ model=st.session_state["openai_model"],
286
+ messages=[
287
+ {"role": "system", "content": "Analyze the video frames and provide a detailed description."},
288
+ {"role": "user", "content": [
289
+ {"type": "text", "text": user_prompt},
290
+ *[{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{frame}"}}
291
+ for frame in base64Frames]
292
+ ]}
293
+ ]
294
+ )
295
+
296
+ return response.choices[0].message.content
297
+
298
+
299
+ def extract_urls(text):
300
+ try:
301
+ date_pattern = re.compile(r'### (\d{2} \w{3} \d{4})')
302
+ abs_link_pattern = re.compile(r'\[(.*?)\]\((https://arxiv\.org/abs/\d+\.\d+)\)')
303
+ pdf_link_pattern = re.compile(r'\[โฌ‡๏ธ\]\((https://arxiv\.org/pdf/\d+\.\d+)\)')
304
+ title_pattern = re.compile(r'### \d{2} \w{3} \d{4} \| \[(.*?)\]')
305
+ date_matches = date_pattern.findall(text)
306
+ abs_link_matches = abs_link_pattern.findall(text)
307
+ pdf_link_matches = pdf_link_pattern.findall(text)
308
+ title_matches = title_pattern.findall(text)
309
+
310
+ # markdown with the extracted fields
311
+ markdown_text = ""
312
+ for i in range(len(date_matches)):
313
+ date = date_matches[i]
314
+ title = title_matches[i]
315
+ abs_link = abs_link_matches[i][1]
316
+ pdf_link = pdf_link_matches[i]
317
+ markdown_text += f"**Date:** {date}\n\n"
318
+ markdown_text += f"**Title:** {title}\n\n"
319
+ markdown_text += f"**Abstract Link:** [{abs_link}]({abs_link})\n\n"
320
+ markdown_text += f"**PDF Link:** [{pdf_link}]({pdf_link})\n\n"
321
+ markdown_text += "---\n\n"
322
+ return markdown_text
323
+
324
+ except:
325
+ st.write('.')
326
+ return ''
327
+
328
+
329
+ def search_arxiv(query):
330
+
331
+ st.write("Performing AI Lookup...")
332
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
333
+
334
+ result1 = client.predict(
335
+ prompt=query,
336
+ llm_model_picked="mistralai/Mixtral-8x7B-Instruct-v0.1",
337
+ stream_outputs=True,
338
+ api_name="/ask_llm"
339
+ )
340
+ st.markdown("### Mixtral-8x7B-Instruct-v0.1 Result")
341
+ st.markdown(result1)
342
+
343
+ result2 = client.predict(
344
+ prompt=query,
345
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
346
+ stream_outputs=True,
347
+ api_name="/ask_llm"
348
+ )
349
+ st.markdown("### Mistral-7B-Instruct-v0.2 Result")
350
+ st.markdown(result2)
351
+ combined_result = f"{result1}\n\n{result2}"
352
+ return combined_result
353
+
354
+ #return responseall
355
+
356
+
357
+ # Function to generate a filename based on prompt and time (because names matter ๐Ÿ•’)
358
+ def generate_filename(prompt, file_type):
359
+ central = pytz.timezone('US/Central')
360
+ safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
361
+ safe_prompt = re.sub(r'\W+', '_', prompt)[:90]
362
+ return f"{safe_date_time}_{safe_prompt}.{file_type}"
363
+
364
+ # Function to create and save a file (and avoid the black hole of lost data ๐Ÿ•ณ)
365
+ def create_file(filename, prompt, response):
366
+ with open(filename, 'w', encoding='utf-8') as file:
367
+ file.write(prompt + "\n\n" + response)
368
+
369
+
370
+ def perform_ai_lookup(query):
371
+ start_time = time.strftime("%Y-%m-%d %H:%M:%S")
372
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
373
+ response1 = client.predict(
374
+ query,
375
+ 20,
376
+ "Semantic Search",
377
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
378
+ api_name="/update_with_rag_md"
379
+ )
380
+ Question = '### ๐Ÿ”Ž ' + query + '\r\n' # Format for markdown display with links
381
+ References = response1[0]
382
+ ReferenceLinks = extract_urls(References)
383
+
384
+ RunSecondQuery = True
385
+ results=''
386
+ if RunSecondQuery:
387
+ # Search 2 - Retrieve the Summary with Papers Context and Original Query
388
+ response2 = client.predict(
389
+ query,
390
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
391
+ True,
392
+ api_name="/ask_llm"
393
+ )
394
+ if len(response2) > 10:
395
+ Answer = response2
396
+ SpeechSynthesis(Answer)
397
+ # Restructure results to follow format of Question, Answer, References, ReferenceLinks
398
+ results = Question + '\r\n' + Answer + '\r\n' + References + '\r\n' + ReferenceLinks
399
+ st.markdown(results)
400
+
401
+ st.write('๐Ÿ”Run of Multi-Agent System Paper Summary Spec is Complete')
402
+ end_time = time.strftime("%Y-%m-%d %H:%M:%S")
403
+ start_timestamp = time.mktime(time.strptime(start_time, "%Y-%m-%d %H:%M:%S"))
404
+ end_timestamp = time.mktime(time.strptime(end_time, "%Y-%m-%d %H:%M:%S"))
405
+ elapsed_seconds = end_timestamp - start_timestamp
406
+ st.write(f"Start time: {start_time}")
407
+ st.write(f"Finish time: {end_time}")
408
+ st.write(f"Elapsed time: {elapsed_seconds:.2f} seconds")
409
+
410
+
411
+ filename = generate_filename(query, "md")
412
+ create_file(filename, query, results)
413
+ return results
414
+
415
+ # Chat Processing Functions
416
  def process_with_gpt(text_input):
417
+ """Process text with GPT-4o."""
418
  if text_input:
419
  st.session_state.messages.append({"role": "user", "content": text_input})
420
 
 
431
  stream=False
432
  )
433
  return_text = completion.choices[0].message.content
434
+ st.write("GPT-4o: " + return_text)
435
 
436
+ #filename = generate_filename(text_input, "md")
437
+ filename = generate_filename("GPT-4o: " + return_text, "md")
438
  create_file(filename, text_input, return_text)
439
  st.session_state.messages.append({"role": "assistant", "content": return_text})
440
  return return_text
 
442
  def process_with_claude(text_input):
443
  """Process text with Claude."""
444
  if text_input:
445
+
446
  with st.chat_message("user"):
447
  st.markdown(text_input)
448
 
 
457
  response_text = response.content[0].text
458
  st.write("Claude: " + response_text)
459
 
460
+ #filename = generate_filename(text_input, "md")
461
  filename = generate_filename("Claude: " + response_text, "md")
462
  create_file(filename, text_input, response_text)
463
 
 
467
  })
468
  return response_text
469
 
470
+ # File Management Functions
471
+ def load_file(file_name):
472
+ """Load file content."""
473
+ with open(file_name, "r", encoding='utf-8') as file:
474
+ content = file.read()
475
+ return content
476
+
477
+ def create_zip_of_files(files):
478
+ """Create zip archive of files."""
479
+ zip_name = "all_files.zip"
480
+ with zipfile.ZipFile(zip_name, 'w') as zipf:
481
+ for file in files:
482
+ zipf.write(file)
483
+ return zip_name
484
+
485
+
486
+
487
+ def get_media_html(media_path, media_type="video", width="100%"):
488
+ """Generate HTML for media player."""
489
+ media_data = base64.b64encode(open(media_path, 'rb').read()).decode()
490
+ if media_type == "video":
491
+ return f'''
492
+ <video width="{width}" controls autoplay muted loop>
493
+ <source src="data:video/mp4;base64,{media_data}" type="video/mp4">
494
+ Your browser does not support the video tag.
495
+ </video>
496
+ '''
497
+ else: # audio
498
+ return f'''
499
+ <audio controls style="width: {width};">
500
+ <source src="data:audio/mpeg;base64,{media_data}" type="audio/mpeg">
501
+ Your browser does not support the audio element.
502
+ </audio>
503
+ '''
504
+
505
+ def create_media_gallery():
506
+ """Create the media gallery interface."""
507
+ st.header("๐ŸŽฌ Media Gallery")
508
 
509
+ tabs = st.tabs(["๐Ÿ–ผ๏ธ Images", "๐ŸŽต Audio", "๐ŸŽฅ Video"])
510
+
511
+ with tabs[0]:
512
+ image_files = glob.glob("*.png") + glob.glob("*.jpg")
513
+ if image_files:
514
+ num_cols = st.slider("Number of columns", 1, 5, 3)
515
+ cols = st.columns(num_cols)
516
+ for idx, image_file in enumerate(image_files):
517
+ with cols[idx % num_cols]:
518
+ img = Image.open(image_file)
519
+ st.image(img, use_container_width=True)
520
+
521
+ # Add GPT vision analysis option
522
+ if st.button(f"Analyze {os.path.basename(image_file)}"):
523
+ analysis = process_image(image_file,
524
+ "Describe this image in detail and identify key elements.")
525
+ st.markdown(analysis)
526
+
527
+ with tabs[1]:
528
+ audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
529
+ for audio_file in audio_files:
530
+ with st.expander(f"๐ŸŽต {os.path.basename(audio_file)}"):
531
+ st.markdown(get_media_html(audio_file, "audio"), unsafe_allow_html=True)
532
+ if st.button(f"Transcribe {os.path.basename(audio_file)}"):
533
+ with open(audio_file, "rb") as f:
534
+ transcription = process_audio(f)
535
+ st.write(transcription)
536
+
537
+ with tabs[2]:
538
+ video_files = glob.glob("*.mp4")
539
+ for video_file in video_files:
540
+ with st.expander(f"๐ŸŽฅ {os.path.basename(video_file)}"):
541
+ st.markdown(get_media_html(video_file, "video"), unsafe_allow_html=True)
542
+ if st.button(f"Analyze {os.path.basename(video_file)}"):
543
+ analysis = process_video_with_gpt(video_file,
544
+ "Describe what's happening in this video.")
545
+ st.markdown(analysis)
546
 
 
 
 
547
 
 
 
 
 
 
 
 
 
 
 
 
548
 
549
+ def display_file_manager():
550
+ """Display file management sidebar with guaranteed unique button keys."""
551
+ st.sidebar.title("๐Ÿ“ File Management")
 
552
 
553
+ all_files = glob.glob("*.md")
554
+ all_files.sort(reverse=True)
 
 
555
 
556
+ if st.sidebar.button("๐Ÿ—‘ Delete All", key="delete_all_files_button"):
557
+ for file in all_files:
558
+ os.remove(file)
559
+ st.rerun()
560
+
561
+ if st.sidebar.button("โฌ‡๏ธ Download All", key="download_all_files_button"):
562
+ zip_file = create_zip_of_files(all_files)
563
+ st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
564
+
565
+ # Create unique keys using file attributes
566
+ for idx, file in enumerate(all_files):
567
+ # Get file stats for unique identification
568
+ file_stat = os.stat(file)
569
+ unique_id = f"{idx}_{file_stat.st_size}_{file_stat.st_mtime}"
570
+
571
+ col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
572
+ with col1:
573
+ if st.button("๐ŸŒ", key=f"view_{unique_id}"):
574
+ st.session_state.current_file = file
575
+ st.session_state.file_content = load_file(file)
576
+ with col2:
577
+ st.markdown(get_download_link(file), unsafe_allow_html=True)
578
+ with col3:
579
+ if st.button("๐Ÿ“‚", key=f"edit_{unique_id}"):
580
+ st.session_state.current_file = file
581
+ st.session_state.file_content = load_file(file)
582
+ with col4:
583
+ if st.button("๐Ÿ—‘", key=f"delete_{unique_id}"):
584
+ os.remove(file)
585
+ st.rerun()
586
+
587
+
588
+
589
+
590
+ # Speech Recognition HTML Component
591
+ speech_recognition_html = """
592
+ <!DOCTYPE html>
593
+ <html>
594
+ <head>
595
+ <title>Continuous Speech Demo</title>
596
+ <style>
597
+ body {
598
+ font-family: sans-serif;
599
+ padding: 20px;
600
+ max-width: 800px;
601
+ margin: 0 auto;
602
+ }
603
+ button {
604
+ padding: 10px 20px;
605
+ margin: 10px 5px;
606
+ font-size: 16px;
607
+ }
608
+ #status {
609
+ margin: 10px 0;
610
+ padding: 10px;
611
+ background: #e8f5e9;
612
+ border-radius: 4px;
613
+ }
614
+ #output {
615
+ white-space: pre-wrap;
616
+ padding: 15px;
617
+ background: #f5f5f5;
618
+ border-radius: 4px;
619
+ margin: 10px 0;
620
+ min-height: 100px;
621
+ max-height: 400px;
622
+ overflow-y: auto;
623
+ }
624
+ .controls {
625
+ margin: 10px 0;
626
+ }
627
+ </style>
628
+ </head>
629
+ <body>
630
+ <div class="controls">
631
+ <button id="start">Start Listening</button>
632
+ <button id="stop" disabled>Stop Listening</button>
633
+ <button id="clear">Clear Text</button>
634
+ </div>
635
+ <div id="status">Ready</div>
636
+ <div id="output"></div>
637
+
638
+ <script>
639
+ if (!('webkitSpeechRecognition' in window)) {
640
+ alert('Speech recognition not supported');
641
+ } else {
642
+ const recognition = new webkitSpeechRecognition();
643
+ const startButton = document.getElementById('start');
644
+ const stopButton = document.getElementById('stop');
645
+ const clearButton = document.getElementById('clear');
646
+ const status = document.getElementById('status');
647
+ const output = document.getElementById('output');
648
+ let fullTranscript = '';
649
+ let lastUpdateTime = Date.now();
650
+
651
+ // Configure recognition
652
+ recognition.continuous = true;
653
+ recognition.interimResults = true;
654
+
655
+ // Function to start recognition
656
+ const startRecognition = () => {
657
+ try {
658
+ recognition.start();
659
+ status.textContent = 'Listening...';
660
+ startButton.disabled = true;
661
+ stopButton.disabled = false;
662
+ } catch (e) {
663
+ console.error(e);
664
+ status.textContent = 'Error: ' + e.message;
665
+ }
666
+ };
667
 
668
+ // Auto-start on load
669
+ window.addEventListener('load', () => {
670
+ setTimeout(startRecognition, 1000);
671
+ });
672
+
673
+ startButton.onclick = startRecognition;
674
+
675
+ stopButton.onclick = () => {
676
+ recognition.stop();
677
+ status.textContent = 'Stopped';
678
+ startButton.disabled = false;
679
+ stopButton.disabled = true;
680
+ };
681
+
682
+ clearButton.onclick = () => {
683
+ fullTranscript = '';
684
+ output.textContent = '';
685
+ window.parent.postMessage({
686
+ type: 'clear_transcript',
687
+ }, '*');
688
+ };
689
+
690
+ recognition.onresult = (event) => {
691
+ let interimTranscript = '';
692
+ let finalTranscript = '';
693
+
694
+ for (let i = event.resultIndex; i < event.results.length; i++) {
695
+ const transcript = event.results[i][0].transcript;
696
+ if (event.results[i].isFinal) {
697
+ finalTranscript += transcript + '\\n';
698
+ } else {
699
+ interimTranscript += transcript;
700
+ }
701
+ }
702
+
703
+ if (finalTranscript || (Date.now() - lastUpdateTime > 5000)) {
704
+ if (finalTranscript) {
705
+ fullTranscript += finalTranscript;
706
+ // Send to Streamlit
707
+ window.parent.postMessage({
708
+ type: 'final_transcript',
709
+ text: finalTranscript
710
+ }, '*');
711
+ }
712
+ lastUpdateTime = Date.now();
713
+ }
714
+
715
+
716
+ output.textContent = fullTranscript + (interimTranscript ? '... ' + interimTranscript : '');
717
+ output.scrollTop = output.scrollHeight;
718
+ };
719
+
720
+ recognition.onend = () => {
721
+ if (!stopButton.disabled) {
722
+ try {
723
+ recognition.start();
724
+ console.log('Restarted recognition');
725
+ } catch (e) {
726
+ console.error('Failed to restart recognition:', e);
727
+ status.textContent = 'Error restarting: ' + e.message;
728
+ startButton.disabled = false;
729
+ stopButton.disabled = true;
730
+ }
731
+ }
732
+ };
733
+
734
+ recognition.onerror = (event) => {
735
+ console.error('Recognition error:', event.error);
736
+ status.textContent = 'Error: ' + event.error;
737
+
738
+ if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {
739
+ startButton.disabled = false;
740
+ stopButton.disabled = true;
741
+ }
742
+ };
743
+ }
744
+ </script>
745
+ </body>
746
+ </html>
747
+ """
748
+
749
+ # Helper Functions
750
+ def generate_filename(prompt, file_type):
751
+ central = pytz.timezone('US/Central')
752
+ safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
753
+ replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
754
+ safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
755
+ return f"{safe_date_time}_{safe_prompt}.{file_type}"
756
+
757
+ # File Management Functions
758
+ def load_file(file_name):
759
+ """Load file content."""
760
+ with open(file_name, "r", encoding='utf-8') as file:
761
+ content = file.read()
762
+ return content
763
+
764
+ def create_zip_of_files(files):
765
+ """Create zip archive of files."""
766
+ zip_name = "all_files.zip"
767
+ with zipfile.ZipFile(zip_name, 'w') as zipf:
768
+ for file in files:
769
+ zipf.write(file)
770
+ return zip_name
771
+
772
+ def get_download_link(file):
773
+ """Create download link for file."""
774
+ with open(file, "rb") as f:
775
+ contents = f.read()
776
+ b64 = base64.b64encode(contents).decode()
777
+ return f'<a href="data:file/txt;base64,{b64}" download="{os.path.basename(file)}">Download {os.path.basename(file)}๐Ÿ“‚</a>'
778
+
779
+ def display_file_manager():
780
+ """Display file management sidebar."""
781
+ st.sidebar.title("๐Ÿ“ File Management")
782
+
783
+ all_files = glob.glob("*.md")
784
+ all_files.sort(reverse=True)
785
+
786
+ if st.sidebar.button("๐Ÿ—‘ Delete All"):
787
+ for file in all_files:
788
+ os.remove(file)
789
+ st.rerun()
790
+
791
+ if st.sidebar.button("โฌ‡๏ธ Download All"):
792
+ zip_file = create_zip_of_files(all_files)
793
+ st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
794
+
795
+ for file in all_files:
796
+ col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
797
+ with col1:
798
+ if st.button("๐ŸŒ", key="view_"+file):
799
+ st.session_state.current_file = file
800
+ st.session_state.file_content = load_file(file)
801
+ with col2:
802
+ st.markdown(get_download_link(file), unsafe_allow_html=True)
803
+ with col3:
804
+ if st.button("๐Ÿ“‚", key="edit_"+file):
805
+ st.session_state.current_file = file
806
+ st.session_state.file_content = load_file(file)
807
+ with col4:
808
+ if st.button("๐Ÿ—‘", key="delete_"+file):
809
+ os.remove(file)
810
+ st.rerun()
811
+
812
+ def create_media_gallery():
813
+ """Create the media gallery interface."""
814
+ st.header("๐ŸŽฌ Media Gallery")
815
+
816
+ tabs = st.tabs(["๐Ÿ–ผ๏ธ Images", "๐ŸŽต Audio", "๐ŸŽฅ Video"])
817
+
818
+ with tabs[0]:
819
+ image_files = glob.glob("*.png") + glob.glob("*.jpg")
820
+ if image_files:
821
+ num_cols = st.slider("Number of columns", 1, 5, 3)
822
+ cols = st.columns(num_cols)
823
+ for idx, image_file in enumerate(image_files):
824
+ with cols[idx % num_cols]:
825
+ img = Image.open(image_file)
826
+ st.image(img, use_container_width=True)
827
+
828
+ # Add GPT vision analysis option
829
+ if st.button(f"Analyze {os.path.basename(image_file)}"):
830
+ analysis = process_image(image_file,
831
+ "Describe this image in detail and identify key elements.")
832
+ st.markdown(analysis)
833
+
834
+ with tabs[1]:
835
+ audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
836
+ for audio_file in audio_files:
837
+ with st.expander(f"๐ŸŽต {os.path.basename(audio_file)}"):
838
+ st.markdown(get_media_html(audio_file, "audio"), unsafe_allow_html=True)
839
+ if st.button(f"Transcribe {os.path.basename(audio_file)}"):
840
+ with open(audio_file, "rb") as f:
841
+ transcription = process_audio(f)
842
+ st.write(transcription)
843
+
844
+ with tabs[2]:
845
+ video_files = glob.glob("*.mp4")
846
+ for video_file in video_files:
847
+ with st.expander(f"๐ŸŽฅ {os.path.basename(video_file)}"):
848
+ st.markdown(get_media_html(video_file, "video"), unsafe_allow_html=True)
849
+ if st.button(f"Analyze {os.path.basename(video_file)}"):
850
+ analysis = process_video_with_gpt(video_file,
851
+ "Describe what's happening in this video.")
852
+ st.markdown(analysis)
853
+
854
+
855
+
856
+ def get_media_html(media_path, media_type="video", width="100%"):
857
+ """Generate HTML for media player."""
858
+ media_data = base64.b64encode(open(media_path, 'rb').read()).decode()
859
+ if media_type == "video":
860
+ return f'''
861
+ <video width="{width}" controls autoplay muted loop>
862
+ <source src="data:video/mp4;base64,{media_data}" type="video/mp4">
863
+ Your browser does not support the video tag.
864
+ </video>
865
+ '''
866
+ else: # audio
867
+ return f'''
868
+ <audio controls style="width: {width};">
869
+ <source src="data:audio/mpeg;base64,{media_data}" type="audio/mpeg">
870
+ Your browser does not support the audio element.
871
+ </audio>
872
+ '''
873
+
874
+ @st.cache_resource
875
+ def set_transcript(text):
876
+ """Set transcript in session state."""
877
+ st.session_state.voice_transcript = text
878
+
879
+
880
  def main():
881
  st.sidebar.markdown("### ๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI")
882
 
883
+ # Main navigation
 
 
884
  tab_main = st.radio("Choose Action:",
885
  ["๐ŸŽค Voice Input", "๐Ÿ’ฌ Chat", "๐Ÿ“ธ Media Gallery", "๐Ÿ” Search ArXiv", "๐Ÿ“ File Editor"],
886
  horizontal=True)
 
888
  if tab_main == "๐ŸŽค Voice Input":
889
  st.subheader("Voice Recognition")
890
 
 
 
 
 
 
891
  # Display speech recognition component
892
+ speech_component = st.components.v1.html(speech_recognition_html, height=400)
893
+ #Experiment: Use `st.session_state` to store the transcript
894
+ if 'voice_transcript' not in st.session_state:
895
+ st.session_state.voice_transcript = ""
896
+
897
+ # JavaScript and Streamlit integration to capture transcript
898
+ st.components.v1.html("""
899
+ <script>
900
+ window.addEventListener('message', (event) => {
901
+ if (event.data.type === 'final_transcript') {
902
+ const transcript = event.data.text;
903
+ // Update Streamlit session state with the transcript
904
+ Streamlit.setComponentValue(transcript);
905
+ }
906
+ });
907
+ </script>
 
 
908
  """, height=0)
909
+ # Display the transcript in a Streamlit text area
910
+ st.markdown("### Processed Voice Input:")
911
+ st.text_area("Voice Transcript", st.session_state.voice_transcript, height=100)
912
+
913
+ # Add functionality to process the transcript
914
+ if st.button("Process Transcript"):
915
+ st.subheader("AI Response to Transcript")
916
+ gpt_response = process_with_gpt(st.session_state.voice_transcript)
917
+ st.markdown(gpt_response)
918
+
919
+ # Option to clear the transcript
920
+ if st.button("Clear Transcript"):
921
+ st.session_state.voice_transcript = ""
922
 
 
 
 
 
923
 
924
+ #st.markdown("### Processed Voice Input:")
925
+ #st.text_area("Voice Transcript", st.session_state.voice_transcript, height=100)
926
+
927
+ # Buttons to process the transcript
928
+ if st.button("Search with GPT"):
929
+ st.subheader("GPT-4o Response")
930
+ gpt_response = process_with_gpt(st.session_state.voice_transcript)
931
+ st.markdown(gpt_response)
932
+
933
+ if st.button("Search with Claude"):
934
+ st.subheader("Claude Response")
935
+ claude_response = process_with_claude(st.session_state.voice_transcript)
936
+ st.markdown(claude_response)
937
+
938
+ if st.button("Search ArXiv"):
939
+ st.subheader("ArXiv Search Results")
940
+ arxiv_results = perform_ai_lookup(st.session_state.voice_transcript)
941
+ st.markdown(arxiv_results)
942
+
943
+ # Clear transcript button
944
+ #if st.button("Clear Transcript"):
945
+ # st.session_state.voice_transcript = ""
946
 
 
 
 
 
 
 
 
 
947
 
948
+ # Handle speech recognition output
949
+ if speech_component:
950
+ try:
951
+ data = speech_component
952
+ if isinstance(data, dict):
953
+ if data.get('type') == 'final_transcript':
954
+ text = data.get('text', '').strip()
955
+ if text:
956
+ st.session_state.last_voice_input = text
957
+
958
+ # Process voice input with AI
959
+ st.subheader("AI Response to Voice Input:")
960
+
961
+ col1, col2, col3 = st.columns(3)
962
+ with col2:
963
+ st.write("Claude-3.5 Sonnet:")
964
+ try:
965
+ claude_response = process_with_claude(text)
966
+ except:
967
+ st.write('Claude 3.5 Sonnet out of tokens.')
968
+ with col1:
969
+ st.write("GPT-4o Omni:")
970
+ try:
971
+ gpt_response = process_with_gpt(text)
972
+ except:
973
+ st.write('GPT 4o out of tokens')
974
+ with col3:
975
+ st.write("Arxiv and Mistral Research:")
976
+ with st.spinner("Searching ArXiv..."):
977
+ results = perform_ai_lookup(text)
978
+ st.markdown(results)
979
+
980
+ elif data.get('type') == 'clear_transcript':
981
+ st.session_state.last_voice_input = ""
982
+ st.experimental_rerun()
983
+
984
+ except Exception as e:
985
+ st.error(f"Error processing voice input: {e}")
986
 
987
+ # Display last voice input
988
+ if st.session_state.last_voice_input:
989
+ st.text_area("Last Voice Input:", st.session_state.last_voice_input, height=100)
990
+
 
 
 
 
 
 
991
 
992
+ if tab_main == "๐Ÿ’ฌ Chat":
993
  # Model Selection
994
  model_choice = st.sidebar.radio(
995
  "Choose AI Model:",
996
+ ["GPT-4o", "Claude-3", "GPT+Claude+Arxiv"]
997
  )
998
 
999
  # Chat Interface
 
1001
 
1002
  if st.button("Send ๐Ÿ“จ"):
1003
  if user_input:
1004
+ if model_choice == "GPT-4o":
1005
  gpt_response = process_with_gpt(user_input)
1006
  elif model_choice == "Claude-3":
1007
  claude_response = process_with_claude(user_input)
1008
+ else: # Both
1009
  col1, col2, col3 = st.columns(3)
 
 
 
 
 
 
1010
  with col2:
1011
+ st.subheader("Claude-3.5 Sonnet:")
1012
  try:
1013
  claude_response = process_with_claude(user_input)
1014
  except:
1015
+ st.write('Claude 3.5 Sonnet out of tokens.')
1016
+ with col1:
1017
+ st.subheader("GPT-4o Omni:")
1018
+ try:
1019
+ gpt_response = process_with_gpt(user_input)
1020
+ except:
1021
+ st.write('GPT 4o out of tokens')
1022
  with col3:
1023
+ st.subheader("Arxiv and Mistral Research:")
1024
  with st.spinner("Searching ArXiv..."):
1025
+ #results = search_arxiv(user_input)
1026
  results = perform_ai_lookup(user_input)
1027
+
1028
  st.markdown(results)
1029
+
1030
  # Display Chat History
1031
  st.subheader("Chat History ๐Ÿ“œ")
1032
+ tab1, tab2 = st.tabs(["Claude History", "GPT-4o History"])
1033
 
1034
  with tab1:
1035
  for chat in st.session_state.chat_history:
 
1049
  query = st.text_input("Enter your research query:")
1050
  if query:
1051
  with st.spinner("Searching ArXiv..."):
1052
+ results = search_arxiv(query)
1053
  st.markdown(results)
1054
 
1055
  elif tab_main == "๐Ÿ“ File Editor":
 
1060
  with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
1061
  file.write(new_content)
1062
  st.success("File updated successfully!")
1063
+
1064
 
1065
  # Always show file manager in sidebar
1066
  display_file_manager()
1067
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1068
  if __name__ == "__main__":
1069
+ main()