awacke1 commited on
Commit
909930b
โ€ข
1 Parent(s): 58498fb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +167 -1027
app.py CHANGED
@@ -1,41 +1,20 @@
1
  import streamlit as st
2
  import anthropic
3
- import openai
 
4
  import base64
5
  from datetime import datetime
6
- import plotly.graph_objects as go
7
- import cv2
8
- import glob
9
- import json
10
- import math
11
- import os
12
  import pytz
13
- import random
14
  import re
15
- import requests
16
  import streamlit.components.v1 as components
17
- import textract
18
- import time
19
- import zipfile
20
- 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, handle_file
25
- from huggingface_hub import InferenceClient
26
- from io import BytesIO
27
- from moviepy.editor import VideoFileClip
28
- from PIL import Image
29
- from PyPDF2 import PdfReader
30
- from urllib.parse import quote
31
- from xml.etree import ElementTree as ET
32
- from openai import OpenAI
33
 
34
- # 1. Configuration and Setup
35
- Site_Name = '๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI'
36
- title = "๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI"
37
  helpURL = 'https://huggingface.co/awacke1'
38
- bugURL = 'https://huggingface.co/spaces/awacke1'
39
  icons = '๐Ÿšฒ๐Ÿ†'
40
 
41
  st.set_page_config(
@@ -50,710 +29,33 @@ st.set_page_config(
50
  }
51
  )
52
 
53
- # 2. Load environment variables and initialize clients
54
  load_dotenv()
55
 
56
- # OpenAI setup
57
- openai.api_key = os.getenv('OPENAI_API_KEY')
58
- if openai.api_key == None:
59
- openai.api_key = st.secrets['OPENAI_API_KEY']
60
-
61
  openai_client = OpenAI(
62
- api_key=os.getenv('OPENAI_API_KEY'),
63
  organization=os.getenv('OPENAI_ORG_ID')
64
  )
65
 
66
- # 3. Claude setup
67
- anthropic_key = os.getenv("ANTHROPIC_API_KEY_3")
68
- if anthropic_key == None:
69
- anthropic_key = st.secrets["ANTHROPIC_API_KEY"]
70
  claude_client = anthropic.Anthropic(api_key=anthropic_key)
71
 
72
- # 4. Initialize session states
73
- if 'transcript_history' not in st.session_state:
74
- st.session_state.transcript_history = []
75
- if "chat_history" not in st.session_state:
76
- st.session_state.chat_history = []
77
- if "openai_model" not in st.session_state:
78
- st.session_state["openai_model"] = "gpt-4o-2024-05-13"
79
- if "messages" not in st.session_state:
80
- st.session_state.messages = []
81
- if 'last_voice_input' not in st.session_state:
82
- st.session_state.last_voice_input = ""
83
-
84
- # 5. # HuggingFace setup
85
- API_URL = os.getenv('API_URL')
86
- HF_KEY = os.getenv('HF_KEY')
87
- MODEL1 = "meta-llama/Llama-2-7b-chat-hf"
88
- MODEL2 = "openai/whisper-small.en"
89
 
90
- headers = {
91
- "Authorization": f"Bearer {HF_KEY}",
92
- "Content-Type": "application/json"
93
- }
94
-
95
- # Initialize session states
96
- if "chat_history" not in st.session_state:
97
- st.session_state.chat_history = []
98
  if "openai_model" not in st.session_state:
99
  st.session_state["openai_model"] = "gpt-4o-2024-05-13"
100
- if "messages" not in st.session_state:
101
- st.session_state.messages = []
102
-
103
- # Custom CSS
104
- st.markdown("""
105
- <style>
106
- .main {
107
- background: linear-gradient(to right, #1a1a1a, #2d2d2d);
108
- color: #ffffff;
109
- }
110
- .stMarkdown {
111
- font-family: 'Helvetica Neue', sans-serif;
112
- }
113
- .category-header {
114
- background: linear-gradient(45deg, #2b5876, #4e4376);
115
- padding: 20px;
116
- border-radius: 10px;
117
- margin: 10px 0;
118
- }
119
- .scene-card {
120
- background: rgba(0,0,0,0.3);
121
- padding: 15px;
122
- border-radius: 8px;
123
- margin: 10px 0;
124
- border: 1px solid rgba(255,255,255,0.1);
125
- }
126
- .media-gallery {
127
- display: grid;
128
- gap: 1rem;
129
- padding: 1rem;
130
- }
131
- .bike-card {
132
- background: rgba(255,255,255,0.05);
133
- border-radius: 10px;
134
- padding: 15px;
135
- transition: transform 0.3s;
136
- }
137
- .bike-card:hover {
138
- transform: scale(1.02);
139
- }
140
- </style>
141
- """, unsafe_allow_html=True)
142
-
143
-
144
- # Bike Collections
145
- bike_collections = {
146
- "Celestial Collection ๐ŸŒŒ": {
147
- "Eclipse Vaulter": {
148
- "prompt": """Cinematic shot of a sleek black mountain bike silhouetted against a total solar eclipse.
149
- The corona creates an ethereal halo effect, with lens flares accentuating key points of the frame.
150
- Dynamic composition shows the bike mid-leap, with stardust particles trailing behind.
151
- Camera angle: Low angle, wide shot
152
- Lighting: Dramatic rim lighting from eclipse
153
- Color palette: Deep purples, cosmic blues, corona gold""",
154
- "emoji": "๐ŸŒ‘"
155
- },
156
- "Starlight Leaper": {
157
- "prompt": """A black bike performing an epic leap under a vast Milky Way galaxy.
158
- Shimmering stars blanket the sky while the bike's wheels leave a trail of stardust.
159
- Camera angle: Wide-angle upward shot
160
- Lighting: Natural starlight with subtle rim lighting
161
- Color palette: Deep blues, silver highlights, cosmic purples""",
162
- "emoji": "โœจ"
163
- },
164
- "Moonlit Hopper": {
165
- "prompt": """A sleek black bike mid-hop over a moonlit meadow,
166
- the full moon illuminating the misty surroundings. Fireflies dance around the bike,
167
- and soft shadows create a serene yet dynamic atmosphere.
168
- Camera angle: Side profile with slight low angle
169
- Lighting: Soft moonlight with atmospheric fog
170
- Color palette: Silver blues, soft whites, deep shadows""",
171
- "emoji": "๐ŸŒ™"
172
- }
173
- },
174
- "Nature-Inspired Collection ๐ŸŒฒ": {
175
- "Shadow Grasshopper": {
176
- "prompt": """A black bike jumping between forest paths,
177
- with dappled sunlight streaming through the canopy. Shadows dance on the bike's frame
178
- as it soars above mossy logs.
179
- Camera angle: Through-the-trees tracking shot
180
- Lighting: Natural forest lighting with sun rays
181
- Color palette: Forest greens, golden sunlight, deep shadows""",
182
- "emoji": "๐Ÿฆ—"
183
- },
184
- "Onyx Leapfrog": {
185
- "prompt": """A bike with obsidian-black finish jumping over a sparkling creek,
186
- the reflection on the water broken into ripples by the leap. The surrounding forest
187
- is vibrant with greens and browns.
188
- Camera angle: Low angle from water level
189
- Lighting: Golden hour side lighting
190
- Color palette: Deep blacks, water blues, forest greens""",
191
- "emoji": "๐Ÿธ"
192
- }
193
- }
194
- }
195
-
196
-
197
- # Helper Functions
198
- def generate_filename(prompt, file_type):
199
- """Generate a safe filename using the prompt and file type."""
200
- central = pytz.timezone('US/Central')
201
- safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
202
- replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
203
- safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
204
- return f"{safe_date_time}_{safe_prompt}.{file_type}"
205
-
206
-
207
-
208
-
209
- # Function to create and save a file (and avoid the black hole of lost data ๐Ÿ•ณ)
210
- def create_file(filename, prompt, response, should_save=True):
211
- if not should_save:
212
- return
213
- with open(filename, 'w', encoding='utf-8') as file:
214
- file.write(prompt + "\n\n" + response)
215
-
216
-
217
-
218
- def create_and_save_file(content, file_type="md", prompt=None, is_image=False, should_save=True):
219
- """Create and save file with proper handling of different types."""
220
- if not should_save:
221
- return None
222
- filename = generate_filename(prompt if prompt else content, file_type)
223
- with open(filename, "w", encoding="utf-8") as f:
224
- if is_image:
225
- f.write(content)
226
- else:
227
- f.write(prompt + "\n\n" + content if prompt else content)
228
- return filename
229
-
230
- def get_download_link(file_path):
231
- """Create download link for file."""
232
- with open(file_path, "rb") as file:
233
- contents = file.read()
234
- b64 = base64.b64encode(contents).decode()
235
- return f'<a href="data:file/txt;base64,{b64}" download="{os.path.basename(file_path)}">Download {os.path.basename(file_path)}๐Ÿ“‚</a>'
236
-
237
- @st.cache_resource
238
- def SpeechSynthesis(result):
239
- """HTML5 Speech Synthesis."""
240
- documentHTML5 = f'''
241
- <!DOCTYPE html>
242
- <html>
243
- <head>
244
- <title>Read It Aloud</title>
245
- <script type="text/javascript">
246
- function readAloud() {{
247
- const text = document.getElementById("textArea").value;
248
- const speech = new SpeechSynthesisUtterance(text);
249
- window.speechSynthesis.speak(speech);
250
- }}
251
- </script>
252
- </head>
253
- <body>
254
- <h1>๐Ÿ”Š Read It Aloud</h1>
255
- <textarea id="textArea" rows="10" cols="80">{result}</textarea>
256
- <br>
257
- <button onclick="readAloud()">๐Ÿ”Š Read Aloud</button>
258
- </body>
259
- </html>
260
- '''
261
- components.html(documentHTML5, width=1280, height=300)
262
-
263
- # Media Processing Functions
264
- def process_image(image_input, user_prompt):
265
- """Process image with GPT-4o vision."""
266
- if isinstance(image_input, str):
267
- with open(image_input, "rb") as image_file:
268
- image_input = image_file.read()
269
-
270
- base64_image = base64.b64encode(image_input).decode("utf-8")
271
-
272
- response = openai_client.chat.completions.create(
273
- model=st.session_state["openai_model"],
274
- messages=[
275
- {"role": "system", "content": "You are a helpful assistant that responds in Markdown."},
276
- {"role": "user", "content": [
277
- {"type": "text", "text": user_prompt},
278
- {"type": "image_url", "image_url": {
279
- "url": f"data:image/png;base64,{base64_image}"
280
- }}
281
- ]}
282
- ],
283
- temperature=0.0,
284
- )
285
-
286
- return response.choices[0].message.content
287
-
288
- def process_audio(audio_input, text_input=''):
289
- """Process audio with Whisper and GPT."""
290
- if isinstance(audio_input, str):
291
- with open(audio_input, "rb") as file:
292
- audio_input = file.read()
293
-
294
- transcription = openai_client.audio.transcriptions.create(
295
- model="whisper-1",
296
- file=audio_input,
297
- )
298
-
299
- st.session_state.messages.append({"role": "user", "content": transcription.text})
300
-
301
- with st.chat_message("assistant"):
302
- st.markdown(transcription.text)
303
- SpeechSynthesis(transcription.text)
304
-
305
- filename = generate_filename(transcription.text, "wav")
306
- create_and_save_file(audio_input, "wav", transcription.text, True)
307
-
308
- def process_video(video_path, seconds_per_frame=1):
309
- """Process video files for frame extraction and audio."""
310
- base64Frames = []
311
- video = cv2.VideoCapture(video_path)
312
- total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
313
- fps = video.get(cv2.CAP_PROP_FPS)
314
- frames_to_skip = int(fps * seconds_per_frame)
315
-
316
- for frame_idx in range(0, total_frames, frames_to_skip):
317
- video.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
318
- success, frame = video.read()
319
- if not success:
320
- break
321
- _, buffer = cv2.imencode(".jpg", frame)
322
- base64Frames.append(base64.b64encode(buffer).decode("utf-8"))
323
-
324
- video.release()
325
-
326
- # Extract audio
327
- base_video_path = os.path.splitext(video_path)[0]
328
- audio_path = f"{base_video_path}.mp3"
329
- try:
330
- video_clip = VideoFileClip(video_path)
331
- video_clip.audio.write_audiofile(audio_path)
332
- video_clip.close()
333
- except:
334
- st.warning("No audio track found in video")
335
- audio_path = None
336
-
337
- return base64Frames, audio_path
338
-
339
- def process_video_with_gpt(video_input, user_prompt):
340
- """Process video with GPT-4o vision."""
341
- base64Frames, audio_path = process_video(video_input)
342
-
343
- response = openai_client.chat.completions.create(
344
- model=st.session_state["openai_model"],
345
- messages=[
346
- {"role": "system", "content": "Analyze the video frames and provide a detailed description."},
347
- {"role": "user", "content": [
348
- {"type": "text", "text": user_prompt},
349
- *[{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{frame}"}}
350
- for frame in base64Frames]
351
- ]}
352
- ]
353
- )
354
-
355
- return response.choices[0].message.content
356
-
357
-
358
- def extract_urls(text):
359
- try:
360
- date_pattern = re.compile(r'### (\d{2} \w{3} \d{4})')
361
- abs_link_pattern = re.compile(r'\[(.*?)\]\((https://arxiv\.org/abs/\d+\.\d+)\)')
362
- pdf_link_pattern = re.compile(r'\[โฌ‡๏ธ\]\((https://arxiv\.org/pdf/\d+\.\d+)\)')
363
- title_pattern = re.compile(r'### \d{2} \w{3} \d{4} \| \[(.*?)\]')
364
- date_matches = date_pattern.findall(text)
365
- abs_link_matches = abs_link_pattern.findall(text)
366
- pdf_link_matches = pdf_link_pattern.findall(text)
367
- title_matches = title_pattern.findall(text)
368
-
369
- # markdown with the extracted fields
370
- markdown_text = ""
371
- for i in range(len(date_matches)):
372
- date = date_matches[i]
373
- title = title_matches[i]
374
- abs_link = abs_link_matches[i][1]
375
- pdf_link = pdf_link_matches[i]
376
- markdown_text += f"**Date:** {date}\n\n"
377
- markdown_text += f"**Title:** {title}\n\n"
378
- markdown_text += f"**Abstract Link:** [{abs_link}]({abs_link})\n\n"
379
- markdown_text += f"**PDF Link:** [{pdf_link}]({pdf_link})\n\n"
380
- markdown_text += "---\n\n"
381
- return markdown_text
382
-
383
- except:
384
- st.write('.')
385
- return ''
386
-
387
-
388
- def search_arxiv(query):
389
-
390
- st.write("Performing AI Lookup...")
391
- client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
392
-
393
- result1 = client.predict(
394
- prompt=query,
395
- llm_model_picked="mistralai/Mixtral-8x7B-Instruct-v0.1",
396
- stream_outputs=True,
397
- api_name="/ask_llm"
398
- )
399
- st.markdown("### Mixtral-8x7B-Instruct-v0.1 Result")
400
- st.markdown(result1)
401
-
402
- result2 = client.predict(
403
- prompt=query,
404
- llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
405
- stream_outputs=True,
406
- api_name="/ask_llm"
407
- )
408
- st.markdown("### Mistral-7B-Instruct-v0.2 Result")
409
- st.markdown(result2)
410
- combined_result = f"{result1}\n\n{result2}"
411
- return combined_result
412
-
413
- #return responseall
414
-
415
-
416
- # Function to generate a filename based on prompt and time (because names matter ๐Ÿ•’)
417
- def generate_filename(prompt, file_type):
418
- central = pytz.timezone('US/Central')
419
- safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
420
- safe_prompt = re.sub(r'\W+', '_', prompt)[:90]
421
- return f"{safe_date_time}_{safe_prompt}.{file_type}"
422
-
423
- # Function to create and save a file (and avoid the black hole of lost data ๐Ÿ•ณ)
424
- def create_file(filename, prompt, response):
425
- with open(filename, 'w', encoding='utf-8') as file:
426
- file.write(prompt + "\n\n" + response)
427
-
428
-
429
- def perform_ai_lookup(query):
430
- start_time = time.strftime("%Y-%m-%d %H:%M:%S")
431
- client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
432
- response1 = client.predict(
433
- query,
434
- 20,
435
- "Semantic Search",
436
- "mistralai/Mixtral-8x7B-Instruct-v0.1",
437
- api_name="/update_with_rag_md"
438
- )
439
- Question = '### ๐Ÿ”Ž ' + query + '\r\n' # Format for markdown display with links
440
- References = response1[0]
441
- ReferenceLinks = extract_urls(References)
442
-
443
- RunSecondQuery = True
444
- results=''
445
- if RunSecondQuery:
446
- # Search 2 - Retrieve the Summary with Papers Context and Original Query
447
- response2 = client.predict(
448
- query,
449
- "mistralai/Mixtral-8x7B-Instruct-v0.1",
450
- True,
451
- api_name="/ask_llm"
452
- )
453
- if len(response2) > 10:
454
- Answer = response2
455
- SpeechSynthesis(Answer)
456
- # Restructure results to follow format of Question, Answer, References, ReferenceLinks
457
- results = Question + '\r\n' + Answer + '\r\n' + References + '\r\n' + ReferenceLinks
458
- st.markdown(results)
459
-
460
- st.write('๐Ÿ”Run of Multi-Agent System Paper Summary Spec is Complete')
461
- end_time = time.strftime("%Y-%m-%d %H:%M:%S")
462
- start_timestamp = time.mktime(time.strptime(start_time, "%Y-%m-%d %H:%M:%S"))
463
- end_timestamp = time.mktime(time.strptime(end_time, "%Y-%m-%d %H:%M:%S"))
464
- elapsed_seconds = end_timestamp - start_timestamp
465
- st.write(f"Start time: {start_time}")
466
- st.write(f"Finish time: {end_time}")
467
- st.write(f"Elapsed time: {elapsed_seconds:.2f} seconds")
468
-
469
-
470
- filename = generate_filename(query, "md")
471
- create_file(filename, query, results)
472
- return results
473
-
474
- # Chat Processing Functions
475
- def process_with_gpt(text_input):
476
- """Process text with GPT-4o."""
477
- if text_input:
478
- st.session_state.messages.append({"role": "user", "content": text_input})
479
-
480
- with st.chat_message("user"):
481
- st.markdown(text_input)
482
-
483
- with st.chat_message("assistant"):
484
- completion = openai_client.chat.completions.create(
485
- model=st.session_state["openai_model"],
486
- messages=[
487
- {"role": m["role"], "content": m["content"]}
488
- for m in st.session_state.messages
489
- ],
490
- stream=False
491
- )
492
- return_text = completion.choices[0].message.content
493
- st.write("GPT-4o: " + return_text)
494
-
495
- #filename = generate_filename(text_input, "md")
496
- filename = generate_filename("GPT-4o: " + return_text, "md")
497
- create_file(filename, text_input, return_text)
498
- st.session_state.messages.append({"role": "assistant", "content": return_text})
499
- return return_text
500
-
501
- def process_with_claude(text_input):
502
- """Process text with Claude."""
503
- if text_input:
504
-
505
- with st.chat_message("user"):
506
- st.markdown(text_input)
507
-
508
- with st.chat_message("assistant"):
509
- response = claude_client.messages.create(
510
- model="claude-3-sonnet-20240229",
511
- max_tokens=1000,
512
- messages=[
513
- {"role": "user", "content": text_input}
514
- ]
515
- )
516
- response_text = response.content[0].text
517
- st.write("Claude: " + response_text)
518
-
519
- #filename = generate_filename(text_input, "md")
520
- filename = generate_filename("Claude: " + response_text, "md")
521
- create_file(filename, text_input, response_text)
522
-
523
- st.session_state.chat_history.append({
524
- "user": text_input,
525
- "claude": response_text
526
- })
527
- return response_text
528
-
529
- # File Management Functions
530
- def load_file(file_name):
531
- """Load file content."""
532
- with open(file_name, "r", encoding='utf-8') as file:
533
- content = file.read()
534
- return content
535
-
536
- def create_zip_of_files(files):
537
- """Create zip archive of files."""
538
- zip_name = "all_files.zip"
539
- with zipfile.ZipFile(zip_name, 'w') as zipf:
540
- for file in files:
541
- zipf.write(file)
542
- return zip_name
543
-
544
-
545
-
546
- def get_media_html(media_path, media_type="video", width="100%"):
547
- """Generate HTML for media player."""
548
- media_data = base64.b64encode(open(media_path, 'rb').read()).decode()
549
- if media_type == "video":
550
- return f'''
551
- <video width="{width}" controls autoplay muted loop>
552
- <source src="data:video/mp4;base64,{media_data}" type="video/mp4">
553
- Your browser does not support the video tag.
554
- </video>
555
- '''
556
- else: # audio
557
- return f'''
558
- <audio controls style="width: {width};">
559
- <source src="data:audio/mpeg;base64,{media_data}" type="audio/mpeg">
560
- Your browser does not support the audio element.
561
- </audio>
562
- '''
563
-
564
- def create_media_gallery():
565
- """Create the media gallery interface."""
566
- st.header("๐ŸŽฌ Media Gallery")
567
-
568
- tabs = st.tabs(["๐Ÿ–ผ๏ธ Images", "๐ŸŽต Audio", "๐ŸŽฅ Video", "๐ŸŽจ Scene Generator"])
569
-
570
- with tabs[0]:
571
- image_files = glob.glob("*.png") + glob.glob("*.jpg")
572
- if image_files:
573
- num_cols = st.slider("Number of columns", 1, 5, 3)
574
- cols = st.columns(num_cols)
575
- for idx, image_file in enumerate(image_files):
576
- with cols[idx % num_cols]:
577
- img = Image.open(image_file)
578
- st.image(img, use_container_width=True)
579
-
580
- # Add GPT vision analysis option
581
- if st.button(f"Analyze {os.path.basename(image_file)}"):
582
- analysis = process_image(image_file,
583
- "Describe this image in detail and identify key elements.")
584
- st.markdown(analysis)
585
-
586
- with tabs[1]:
587
- audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
588
- for audio_file in audio_files:
589
- with st.expander(f"๐ŸŽต {os.path.basename(audio_file)}"):
590
- st.markdown(get_media_html(audio_file, "audio"), unsafe_allow_html=True)
591
- if st.button(f"Transcribe {os.path.basename(audio_file)}"):
592
- with open(audio_file, "rb") as f:
593
- transcription = process_audio(f)
594
- st.write(transcription)
595
-
596
- with tabs[2]:
597
- video_files = glob.glob("*.mp4")
598
- for video_file in video_files:
599
- with st.expander(f"๐ŸŽฅ {os.path.basename(video_file)}"):
600
- st.markdown(get_media_html(video_file, "video"), unsafe_allow_html=True)
601
- if st.button(f"Analyze {os.path.basename(video_file)}"):
602
- analysis = process_video_with_gpt(video_file,
603
- "Describe what's happening in this video.")
604
- st.markdown(analysis)
605
-
606
- with tabs[3]:
607
- for collection_name, bikes in bike_collections.items():
608
- st.subheader(collection_name)
609
- cols = st.columns(len(bikes))
610
-
611
- for idx, (bike_name, details) in enumerate(bikes.items()):
612
- with cols[idx]:
613
- st.markdown(f"""
614
- <div class='bike-card'>
615
- <h3>{details['emoji']} {bike_name}</h3>
616
- <p>{details['prompt']}</p>
617
- </div>
618
- """, unsafe_allow_html=True)
619
-
620
- if st.button(f"Generate {bike_name} Scene"):
621
- prompt = details['prompt']
622
- # Here you could integrate with image generation API
623
- st.write(f"Generated scene description for {bike_name}:")
624
- st.write(prompt)
625
-
626
- def display_file_manager():
627
- """Display file management sidebar with guaranteed unique button keys."""
628
- st.sidebar.title("๐Ÿ“ File Management")
629
-
630
- all_files = glob.glob("*.md")
631
- all_files.sort(reverse=True)
632
-
633
- if st.sidebar.button("๐Ÿ—‘ Delete All", key="delete_all_files_button"):
634
- for file in all_files:
635
- os.remove(file)
636
- st.rerun()
637
 
638
- if st.sidebar.button("โฌ‡๏ธ Download All", key="download_all_files_button"):
639
- zip_file = create_zip_of_files(all_files)
640
- st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
641
-
642
- # Create unique keys using file attributes
643
- for idx, file in enumerate(all_files):
644
- # Get file stats for unique identification
645
- file_stat = os.stat(file)
646
- unique_id = f"{idx}_{file_stat.st_size}_{file_stat.st_mtime}"
647
-
648
- col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
649
- with col1:
650
- if st.button("๐ŸŒ", key=f"view_{unique_id}"):
651
- st.session_state.current_file = file
652
- st.session_state.file_content = load_file(file)
653
- with col2:
654
- st.markdown(get_download_link(file), unsafe_allow_html=True)
655
- with col3:
656
- if st.button("๐Ÿ“‚", key=f"edit_{unique_id}"):
657
- st.session_state.current_file = file
658
- st.session_state.file_content = load_file(file)
659
- with col4:
660
- if st.button("๐Ÿ—‘", key=f"delete_{unique_id}"):
661
- os.remove(file)
662
- st.rerun()
663
-
664
-
665
- def main():
666
- st.sidebar.markdown("### ๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI")
667
-
668
- # Main navigation
669
- tab_main = st.radio("Choose Action:",
670
- ["๐Ÿ’ฌ Chat", "๐Ÿ“ธ Media Gallery", "๐Ÿ” Search ArXiv", "๐Ÿ“ File Editor"],
671
- horizontal=True)
672
-
673
- if tab_main == "๐Ÿ’ฌ Chat":
674
- # Model Selection
675
- model_choice = st.sidebar.radio(
676
- "Choose AI Model:",
677
- ["GPT-4o", "Claude-3", "GPT+Claude+Arxiv"]
678
- )
679
-
680
- # Chat Interface
681
- user_input = st.text_area("Message:", height=100)
682
-
683
- if st.button("Send ๐Ÿ“จ"):
684
- if user_input:
685
- if model_choice == "GPT-4o":
686
- gpt_response = process_with_gpt(user_input)
687
- elif model_choice == "Claude-3":
688
- claude_response = process_with_claude(user_input)
689
- else: # Both
690
- col1, col2, col3 = st.columns(3)
691
- with col2:
692
- st.subheader("Claude-3.5 Sonnet:")
693
- try:
694
- claude_response = process_with_claude(user_input)
695
- except:
696
- st.write('Claude 3.5 Sonnet out of tokens.')
697
- with col1:
698
- st.subheader("GPT-4o Omni:")
699
- try:
700
- gpt_response = process_with_gpt(user_input)
701
- except:
702
- st.write('GPT 4o out of tokens')
703
- with col3:
704
- st.subheader("Arxiv and Mistral Research:")
705
- with st.spinner("Searching ArXiv..."):
706
- #results = search_arxiv(user_input)
707
- results = perform_ai_lookup(user_input)
708
-
709
- st.markdown(results)
710
-
711
- # Display Chat History
712
- st.subheader("Chat History ๐Ÿ“œ")
713
- tab1, tab2 = st.tabs(["Claude History", "GPT-4o History"])
714
-
715
- with tab1:
716
- for chat in st.session_state.chat_history:
717
- st.text_area("You:", chat["user"], height=100)
718
- st.text_area("Claude:", chat["claude"], height=200)
719
- st.markdown(chat["claude"])
720
-
721
- with tab2:
722
- for message in st.session_state.messages:
723
- with st.chat_message(message["role"]):
724
- st.markdown(message["content"])
725
-
726
- elif tab_main == "๐Ÿ“ธ Media Gallery":
727
- create_media_gallery()
728
-
729
- elif tab_main == "๐Ÿ” Search ArXiv":
730
- query = st.text_input("Enter your research query:")
731
- if query:
732
- with st.spinner("Searching ArXiv..."):
733
- results = search_arxiv(query)
734
- st.markdown(results)
735
-
736
- elif tab_main == "๐Ÿ“ File Editor":
737
- if hasattr(st.session_state, 'current_file'):
738
- st.subheader(f"Editing: {st.session_state.current_file}")
739
- new_content = st.text_area("Content:", st.session_state.file_content, height=300)
740
- if st.button("Save Changes"):
741
- with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
742
- file.write(new_content)
743
- st.success("File updated successfully!")
744
-
745
- # Always show file manager in sidebar
746
- display_file_manager()
747
-
748
- if __name__ == "__main__":
749
- main()
750
-
751
- # Speech Recognition HTML Component
752
  speech_recognition_html = """
753
  <!DOCTYPE html>
754
  <html>
755
  <head>
756
- <title>Continuous Speech Demo</title>
757
  <style>
758
  body {
759
  font-family: sans-serif;
@@ -782,13 +84,10 @@ speech_recognition_html = """
782
  max-height: 400px;
783
  overflow-y: auto;
784
  }
785
- .controls {
786
- margin: 10px 0;
787
- }
788
  </style>
789
  </head>
790
  <body>
791
- <div class="controls">
792
  <button id="start">Start Listening</button>
793
  <button id="stop" disabled>Stop Listening</button>
794
  <button id="clear">Clear Text</button>
@@ -809,24 +108,16 @@ speech_recognition_html = """
809
  let fullTranscript = '';
810
  let lastUpdateTime = Date.now();
811
 
812
- // Configure recognition
813
  recognition.continuous = true;
814
  recognition.interimResults = true;
815
 
816
- // Function to start recognition
817
- const startRecognition = () => {
818
- try {
819
- recognition.start();
820
- status.textContent = 'Listening...';
821
- startButton.disabled = true;
822
- stopButton.disabled = false;
823
- } catch (e) {
824
- console.error(e);
825
- status.textContent = 'Error: ' + e.message;
826
- }
827
- };
828
 
829
- // Auto-start on load
830
  window.addEventListener('load', () => {
831
  setTimeout(startRecognition, 1000);
832
  });
@@ -844,7 +135,7 @@ speech_recognition_html = """
844
  fullTranscript = '';
845
  output.textContent = '';
846
  window.parent.postMessage({
847
- type: 'clear_transcript',
848
  }, '*');
849
  };
850
 
@@ -856,20 +147,17 @@ speech_recognition_html = """
856
  const transcript = event.results[i][0].transcript;
857
  if (event.results[i].isFinal) {
858
  finalTranscript += transcript + '\\n';
 
 
 
 
859
  } else {
860
  interimTranscript += transcript;
861
  }
862
  }
863
 
864
- if (finalTranscript || (Date.now() - lastUpdateTime > 5000)) {
865
- if (finalTranscript) {
866
- fullTranscript += finalTranscript;
867
- // Send to Streamlit
868
- window.parent.postMessage({
869
- type: 'final_transcript',
870
- text: finalTranscript
871
- }, '*');
872
- }
873
  lastUpdateTime = Date.now();
874
  }
875
 
@@ -879,23 +167,13 @@ speech_recognition_html = """
879
 
880
  recognition.onend = () => {
881
  if (!stopButton.disabled) {
882
- try {
883
- recognition.start();
884
- console.log('Restarted recognition');
885
- } catch (e) {
886
- console.error('Failed to restart recognition:', e);
887
- status.textContent = 'Error restarting: ' + e.message;
888
- startButton.disabled = false;
889
- stopButton.disabled = true;
890
- }
891
  }
892
  };
893
 
894
  recognition.onerror = (event) => {
895
- console.error('Recognition error:', event.error);
896
  status.textContent = 'Error: ' + event.error;
897
-
898
- if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {
899
  startButton.disabled = false;
900
  stopButton.disabled = true;
901
  }
@@ -906,303 +184,165 @@ speech_recognition_html = """
906
  </html>
907
  """
908
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
909
  # Helper Functions
910
  def generate_filename(prompt, file_type):
 
911
  central = pytz.timezone('US/Central')
912
  safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
913
  replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
914
  safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
915
  return f"{safe_date_time}_{safe_prompt}.{file_type}"
916
 
917
- # File Management Functions
918
- def load_file(file_name):
919
- """Load file content."""
920
- with open(file_name, "r", encoding='utf-8') as file:
921
- content = file.read()
922
- return content
923
-
924
- def create_zip_of_files(files):
925
- """Create zip archive of files."""
926
- zip_name = "all_files.zip"
927
- with zipfile.ZipFile(zip_name, 'w') as zipf:
928
- for file in files:
929
- zipf.write(file)
930
- return zip_name
931
-
932
- def get_download_link(file):
933
- """Create download link for file."""
934
- with open(file, "rb") as f:
935
- contents = f.read()
936
- b64 = base64.b64encode(contents).decode()
937
- return f'<a href="data:file/txt;base64,{b64}" download="{os.path.basename(file)}">Download {os.path.basename(file)}๐Ÿ“‚</a>'
938
-
939
- def display_file_manager():
940
- """Display file management sidebar."""
941
- st.sidebar.title("๐Ÿ“ File Management")
942
-
943
- all_files = glob.glob("*.md")
944
- all_files.sort(reverse=True)
945
-
946
- if st.sidebar.button("๐Ÿ—‘ Delete All"):
947
- for file in all_files:
948
- os.remove(file)
949
- st.rerun()
950
-
951
- if st.sidebar.button("โฌ‡๏ธ Download All"):
952
- zip_file = create_zip_of_files(all_files)
953
- st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
954
-
955
- for file in all_files:
956
- col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
957
- with col1:
958
- if st.button("๐ŸŒ", key="view_"+file):
959
- st.session_state.current_file = file
960
- st.session_state.file_content = load_file(file)
961
- with col2:
962
- st.markdown(get_download_link(file), unsafe_allow_html=True)
963
- with col3:
964
- if st.button("๐Ÿ“‚", key="edit_"+file):
965
- st.session_state.current_file = file
966
- st.session_state.file_content = load_file(file)
967
- with col4:
968
- if st.button("๐Ÿ—‘", key="delete_"+file):
969
- os.remove(file)
970
- st.rerun()
971
 
972
- def create_media_gallery():
973
- """Create the media gallery interface."""
974
- st.header("๐ŸŽฌ Media Gallery")
975
-
976
- tabs = st.tabs(["๐Ÿ–ผ๏ธ Images", "๐ŸŽต Audio", "๐ŸŽฅ Video", "๐ŸŽจ Scene Generator"])
977
-
978
- with tabs[0]:
979
- image_files = glob.glob("*.png") + glob.glob("*.jpg")
980
- if image_files:
981
- num_cols = st.slider("Number of columns", 1, 5, 3)
982
- cols = st.columns(num_cols)
983
- for idx, image_file in enumerate(image_files):
984
- with cols[idx % num_cols]:
985
- img = Image.open(image_file)
986
- st.image(img, use_container_width=True)
987
-
988
- # Add GPT vision analysis option
989
- if st.button(f"Analyze {os.path.basename(image_file)}"):
990
- analysis = process_image(image_file,
991
- "Describe this image in detail and identify key elements.")
992
- st.markdown(analysis)
993
-
994
- with tabs[1]:
995
- audio_files = glob.glob("*.mp3") + glob.glob("*.wav")
996
- for audio_file in audio_files:
997
- with st.expander(f"๐ŸŽต {os.path.basename(audio_file)}"):
998
- st.markdown(get_media_html(audio_file, "audio"), unsafe_allow_html=True)
999
- if st.button(f"Transcribe {os.path.basename(audio_file)}"):
1000
- with open(audio_file, "rb") as f:
1001
- transcription = process_audio(f)
1002
- st.write(transcription)
1003
 
1004
- with tabs[2]:
1005
- video_files = glob.glob("*.mp4")
1006
- for video_file in video_files:
1007
- with st.expander(f"๐ŸŽฅ {os.path.basename(video_file)}"):
1008
- st.markdown(get_media_html(video_file, "video"), unsafe_allow_html=True)
1009
- if st.button(f"Analyze {os.path.basename(video_file)}"):
1010
- analysis = process_video_with_gpt(video_file,
1011
- "Describe what's happening in this video.")
1012
- st.markdown(analysis)
1013
 
1014
- with tabs[3]:
1015
- for collection_name, bikes in bike_collections.items():
1016
- st.subheader(collection_name)
1017
- cols = st.columns(len(bikes))
1018
-
1019
- for idx, (bike_name, details) in enumerate(bikes.items()):
1020
- with cols[idx]:
1021
- st.markdown(f"""
1022
- <div class='bike-card'>
1023
- <h3>{details['emoji']} {bike_name}</h3>
1024
- <p>{details['prompt']}</p>
1025
- </div>
1026
- """, unsafe_allow_html=True)
1027
-
1028
- if st.button(f"Generate {bike_name} Scene"):
1029
- prompt = details['prompt']
1030
- # Here you could integrate with image generation API
1031
- st.write(f"Generated scene description for {bike_name}:")
1032
- st.write(prompt)
1033
 
1034
- def get_media_html(media_path, media_type="video", width="100%"):
1035
- """Generate HTML for media player."""
1036
- media_data = base64.b64encode(open(media_path, 'rb').read()).decode()
1037
- if media_type == "video":
1038
- return f'''
1039
- <video width="{width}" controls autoplay muted loop>
1040
- <source src="data:video/mp4;base64,{media_data}" type="video/mp4">
1041
- Your browser does not support the video tag.
1042
- </video>
1043
- '''
1044
- else: # audio
1045
- return f'''
1046
- <audio controls style="width: {width};">
1047
- <source src="data:audio/mpeg;base64,{media_data}" type="audio/mpeg">
1048
- Your browser does not support the audio element.
1049
- </audio>
1050
- '''
1051
 
 
 
1052
 
1053
- def process_transcription_with_ai(text):
1054
- """Process transcribed text with all three AI models."""
1055
- results = {
1056
- "claude": None,
1057
- "gpt": None,
1058
- "arxiv": None
1059
- }
1060
-
1061
- try:
1062
- results["claude"] = process_with_claude(text)
1063
- except Exception as e:
1064
- st.error(f"Claude processing error: {e}")
1065
 
1066
- try:
1067
- results["gpt"] = process_with_gpt(text)
1068
- except Exception as e:
1069
- st.error(f"GPT processing error: {e}")
1070
 
1071
- try:
1072
- results["arxiv"] = perform_ai_lookup(text)
1073
- except Exception as e:
1074
- st.error(f"Arxiv processing error: {e}")
 
 
 
 
 
 
 
 
 
1075
 
1076
- return results
1077
-
1078
- def handle_speech_recognition_component():
1079
- """Handle the speech recognition component and AI processing."""
1080
- st.subheader("Voice Recognition with Multi-Modal Output")
1081
-
1082
- # Initialize state for transcribed text
1083
- if "transcribed_text" not in st.session_state:
1084
- st.session_state.transcribed_text = ""
1085
-
1086
- # Render the React component
1087
- component = components.declare_component(
1088
- "speech_recognition",
1089
- path="frontend/build" # Update this path to match your React component location
1090
- )
1091
-
1092
- # Handle component events
1093
- component_result = component()
1094
- if component_result:
1095
- if component_result.get("type") == "process_ai":
1096
- text = component_result.get("text", "").strip()
1097
- if text:
1098
- with st.spinner("Processing with AI models..."):
1099
- results = process_transcription_with_ai(text)
1100
-
1101
- # Display results in columns
1102
- col1, col2, col3 = st.columns(3)
1103
- with col1:
1104
- st.subheader("GPT-4o Results")
1105
- if results["gpt"]:
1106
- st.markdown(results["gpt"])
1107
-
1108
- with col2:
1109
- st.subheader("Claude Results")
1110
- if results["claude"]:
1111
- st.markdown(results["claude"])
1112
-
1113
- with col3:
1114
- st.subheader("Arxiv Results")
1115
- if results["arxiv"]:
1116
- st.markdown(results["arxiv"])
1117
-
1118
 
 
 
 
1119
 
1120
- def main():
1121
- st.sidebar.markdown("### ๐ŸšฒBikeAI๐Ÿ† Claude and GPT Multi-Agent Research AI")
1122
 
1123
- # Main navigation
1124
- tab_main = st.radio("Choose Action:",
1125
- ["๐ŸŽค Voice Input", "๐Ÿ’ฌ Chat", "๐Ÿ“ธ Media Gallery", "๐Ÿ” Search ArXiv", "๐Ÿ“ File Editor"],
1126
- horizontal=True)
1127
 
1128
- if tab_main == "๐ŸŽค Voice Input":
1129
- handle_speech_recognition_component()
1130
-
1131
- if tab_main == "๐ŸŽค Voice Input":
1132
- st.subheader("Voice Recognition")
1133
-
1134
- # Display speech recognition component
1135
- speech_component = st.components.v1.html(speech_recognition_html, height=400)
1136
-
1137
- # Handle speech recognition output
1138
- if speech_component:
1139
- try:
1140
- data = speech_component
1141
- if isinstance(data, dict):
1142
- if data.get('type') == 'final_transcript':
1143
- text = data.get('text', '').strip()
1144
- if text:
1145
- st.session_state.last_voice_input = text
1146
-
1147
- # Process voice input with AI
1148
- st.subheader("AI Response to Voice Input:")
1149
-
1150
- col1, col2, col3 = st.columns(3)
1151
- with col2:
1152
- st.write("Claude-3.5 Sonnet:")
1153
- try:
1154
- claude_response = process_with_claude(text)
1155
- except:
1156
- st.write('Claude 3.5 Sonnet out of tokens.')
1157
- with col1:
1158
- st.write("GPT-4o Omni:")
1159
- try:
1160
- gpt_response = process_with_gpt(text)
1161
- except:
1162
- st.write('GPT 4o out of tokens')
1163
- with col3:
1164
- st.write("Arxiv and Mistral Research:")
1165
- with st.spinner("Searching ArXiv..."):
1166
- results = perform_ai_lookup(text)
1167
- st.markdown(results)
1168
-
1169
- elif data.get('type') == 'clear_transcript':
1170
- st.session_state.last_voice_input = ""
1171
- st.experimental_rerun()
1172
-
1173
- except Exception as e:
1174
- st.error(f"Error processing voice input: {e}")
1175
-
1176
- # Display last voice input
1177
  if st.session_state.last_voice_input:
1178
- st.text_area("Last Voice Input:", st.session_state.last_voice_input, height=100)
 
 
 
 
 
 
 
 
 
 
 
 
 
1179
 
1180
- # [Rest of the main function remains the same]
1181
- elif tab_main == "๐Ÿ’ฌ Chat":
1182
- # [Previous chat interface code]
1183
- pass
1184
 
1185
- elif tab_main == "๐Ÿ“ธ Media Gallery":
1186
- create_media_gallery()
 
 
 
 
 
 
 
 
 
1187
 
1188
- elif tab_main == "๐Ÿ” Search ArXiv":
1189
- query = st.text_input("Enter your research query:")
1190
- if query:
1191
- with st.spinner("Searching ArXiv..."):
1192
- results = search_arxiv(query)
1193
- st.markdown(results)
1194
 
1195
- elif tab_main == "๐Ÿ“ File Editor":
1196
- if hasattr(st.session_state, 'current_file'):
1197
- st.subheader(f"Editing: {st.session_state.current_file}")
1198
- new_content = st.text_area("Content:", st.session_state.file_content, height=300)
1199
- if st.button("Save Changes"):
1200
- with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
1201
- file.write(new_content)
1202
- st.success("File updated successfully!")
1203
-
1204
- # Always show file manager in sidebar
1205
- display_file_manager()
1206
 
1207
  if __name__ == "__main__":
1208
  main()
 
1
  import streamlit as st
2
  import anthropic
3
+ import openai
4
+ from openai import OpenAI
5
  import base64
6
  from datetime import datetime
 
 
 
 
 
 
7
  import pytz
8
+ import os
9
  import re
 
10
  import streamlit.components.v1 as components
 
 
 
 
 
 
11
  from dotenv import load_dotenv
 
 
 
 
 
 
 
 
 
12
 
13
+ # Site Configuration
14
+ Site_Name = '๐ŸšฒBikeAI๐Ÿ† Multi-Agent Research AI'
15
+ title = "๐ŸšฒBikeAI๐Ÿ† Multi-Agent Research AI"
16
  helpURL = 'https://huggingface.co/awacke1'
17
+ bugURL = 'https://huggingface.co/spaces/awacke1'
18
  icons = '๐Ÿšฒ๐Ÿ†'
19
 
20
  st.set_page_config(
 
29
  }
30
  )
31
 
32
+ # Load environment variables
33
  load_dotenv()
34
 
35
+ # API Setup
36
+ openai.api_key = os.getenv('OPENAI_API_KEY') or st.secrets['OPENAI_API_KEY']
 
 
 
37
  openai_client = OpenAI(
38
+ api_key=openai.api_key,
39
  organization=os.getenv('OPENAI_ORG_ID')
40
  )
41
 
42
+ anthropic_key = os.getenv("ANTHROPIC_API_KEY_3") or st.secrets["ANTHROPIC_API_KEY"]
 
 
 
43
  claude_client = anthropic.Anthropic(api_key=anthropic_key)
44
 
45
+ # Session State
46
+ for key in ['transcript_history', 'chat_history', 'messages', 'last_voice_input']:
47
+ if key not in st.session_state:
48
+ st.session_state[key] = [] if key != 'last_voice_input' else ""
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
 
 
 
 
 
 
 
 
50
  if "openai_model" not in st.session_state:
51
  st.session_state["openai_model"] = "gpt-4o-2024-05-13"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ # HTML/CSS Components
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  speech_recognition_html = """
55
  <!DOCTYPE html>
56
  <html>
57
  <head>
58
+ <title>Voice Recognition</title>
59
  <style>
60
  body {
61
  font-family: sans-serif;
 
84
  max-height: 400px;
85
  overflow-y: auto;
86
  }
 
 
 
87
  </style>
88
  </head>
89
  <body>
90
+ <div>
91
  <button id="start">Start Listening</button>
92
  <button id="stop" disabled>Stop Listening</button>
93
  <button id="clear">Clear Text</button>
 
108
  let fullTranscript = '';
109
  let lastUpdateTime = Date.now();
110
 
 
111
  recognition.continuous = true;
112
  recognition.interimResults = true;
113
 
114
+ function startRecognition() {
115
+ recognition.start();
116
+ status.textContent = 'Listening...';
117
+ startButton.disabled = true;
118
+ stopButton.disabled = false;
119
+ }
 
 
 
 
 
 
120
 
 
121
  window.addEventListener('load', () => {
122
  setTimeout(startRecognition, 1000);
123
  });
 
135
  fullTranscript = '';
136
  output.textContent = '';
137
  window.parent.postMessage({
138
+ type: 'clear_transcript'
139
  }, '*');
140
  };
141
 
 
147
  const transcript = event.results[i][0].transcript;
148
  if (event.results[i].isFinal) {
149
  finalTranscript += transcript + '\\n';
150
+ window.parent.postMessage({
151
+ type: 'final_transcript',
152
+ text: transcript
153
+ }, '*');
154
  } else {
155
  interimTranscript += transcript;
156
  }
157
  }
158
 
159
+ if (finalTranscript) {
160
+ fullTranscript += finalTranscript;
 
 
 
 
 
 
 
161
  lastUpdateTime = Date.now();
162
  }
163
 
 
167
 
168
  recognition.onend = () => {
169
  if (!stopButton.disabled) {
170
+ recognition.start();
 
 
 
 
 
 
 
 
171
  }
172
  };
173
 
174
  recognition.onerror = (event) => {
 
175
  status.textContent = 'Error: ' + event.error;
176
+ if (event.error === 'not-allowed') {
 
177
  startButton.disabled = false;
178
  stopButton.disabled = true;
179
  }
 
184
  </html>
185
  """
186
 
187
+ def SpeechSynthesis(result):
188
+ """HTML5 Speech Synthesis."""
189
+ documentHTML5 = f'''
190
+ <!DOCTYPE html>
191
+ <html>
192
+ <head>
193
+ <title>Read Text</title>
194
+ </head>
195
+ <body>
196
+ <h3>๐Ÿ”Š Text to Speech</h3>
197
+ <textarea id="textArea" rows="8" style="width: 100%">{result}</textarea>
198
+ <br>
199
+ <button onclick="readAloud()">๐Ÿ”Š Read Aloud</button>
200
+ <script>
201
+ function readAloud() {{
202
+ const text = document.getElementById("textArea").value;
203
+ const speech = new SpeechSynthesisUtterance(text);
204
+ window.speechSynthesis.speak(speech);
205
+ }}
206
+ </script>
207
+ </body>
208
+ </html>
209
+ '''
210
+ components.html(documentHTML5, height=250)
211
+
212
  # Helper Functions
213
  def generate_filename(prompt, file_type):
214
+ """Generate timestamped filename."""
215
  central = pytz.timezone('US/Central')
216
  safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
217
  replaced_prompt = re.sub(r'[<>:"/\\|?*\n]', ' ', prompt)
218
  safe_prompt = re.sub(r'\s+', ' ', replaced_prompt).strip()[:230]
219
  return f"{safe_date_time}_{safe_prompt}.{file_type}"
220
 
221
+ def create_file(filename, prompt, response):
222
+ """Save content to file."""
223
+ with open(filename, 'w', encoding='utf-8') as file:
224
+ file.write(f"{prompt}\n\n{response}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
+ # AI Processing Functions
227
+ def process_with_gpt(text_input):
228
+ """Process text with GPT-4."""
229
+ if not text_input:
230
+ return None
231
+
232
+ st.session_state.messages.append({"role": "user", "content": text_input})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
+ with st.chat_message("user"):
235
+ st.markdown(text_input)
 
 
 
 
 
 
 
236
 
237
+ with st.chat_message("assistant"):
238
+ completion = openai_client.chat.completions.create(
239
+ model=st.session_state["openai_model"],
240
+ messages=[
241
+ {"role": m["role"], "content": m["content"]}
242
+ for m in st.session_state.messages
243
+ ],
244
+ stream=False
245
+ )
246
+ response_text = completion.choices[0].message.content
247
+ st.write(f"GPT-4: {response_text}")
248
+
249
+ filename = generate_filename(f"GPT-4: {response_text}", "md")
250
+ create_file(filename, text_input, response_text)
251
+ st.session_state.messages.append({"role": "assistant", "content": response_text})
252
+ return response_text
 
 
 
253
 
254
+ def process_with_claude(text_input):
255
+ """Process text with Claude."""
256
+ if not text_input:
257
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
+ with st.chat_message("user"):
260
+ st.markdown(text_input)
261
 
262
+ with st.chat_message("assistant"):
263
+ response = claude_client.messages.create(
264
+ model="claude-3-sonnet-20240229",
265
+ max_tokens=1000,
266
+ messages=[{"role": "user", "content": text_input}]
267
+ )
268
+ response_text = response.content[0].text
269
+ st.write(f"Claude: {response_text}")
 
 
 
 
270
 
271
+ filename = generate_filename(f"Claude: {response_text}", "md")
272
+ create_file(filename, text_input, response_text)
 
 
273
 
274
+ st.session_state.chat_history.append({
275
+ "user": text_input,
276
+ "claude": response_text
277
+ })
278
+ return response_text
279
+
280
+ def process_with_both(text_input):
281
+ """Process text with both GPT and Claude."""
282
+ col1, col2 = st.columns(2)
283
+
284
+ with col1:
285
+ st.subheader("GPT-4 Results")
286
+ gpt_response = process_with_gpt(text_input)
287
 
288
+ with col2:
289
+ st.subheader("Claude Results")
290
+ claude_response = process_with_claude(text_input)
291
+
292
+ return gpt_response, claude_response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
+ def handle_speech_recognition():
295
+ """Handle speech recognition with line numbers and AI processing."""
296
+ st.subheader("Voice Recognition")
297
 
298
+ col1, col2 = st.columns(2)
 
299
 
300
+ with col1:
301
+ components.html(speech_recognition_html, height=400)
302
+ if st.session_state.last_voice_input:
303
+ SpeechSynthesis(st.session_state.last_voice_input)
304
 
305
+ with col2:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  if st.session_state.last_voice_input:
307
+ st.markdown("### Transcribed Text")
308
+ lines = st.session_state.last_voice_input.split('\n')
309
+ numbered_text = '\n'.join(f"{i+1:03d} โ”‚ {line}" for i, line in enumerate(lines))
310
+ st.code(numbered_text, language=None)
311
+
312
+ if st.button("Process with AI Models ๐Ÿค–"):
313
+ process_with_both(st.session_state.last_voice_input)
314
+
315
+ def handle_chat():
316
+ """Handle chat interface."""
317
+ model_choice = st.sidebar.radio(
318
+ "Choose AI Model:",
319
+ ["GPT-4", "Claude", "Both"]
320
+ )
321
 
322
+ user_input = st.text_area("Message:", height=100)
 
 
 
323
 
324
+ if st.button("Send ๐Ÿ“จ") and user_input:
325
+ if model_choice == "GPT-4":
326
+ process_with_gpt(user_input)
327
+ elif model_choice == "Claude":
328
+ process_with_claude(user_input)
329
+ else:
330
+ process_with_both(user_input)
331
+
332
+ def main():
333
+ """Main application."""
334
+ st.sidebar.title("๐Ÿšฒ Multi-Agent Research AI")
335
 
336
+ tab = st.radio(
337
+ "Choose Action:",
338
+ ["๐ŸŽค Voice Input", "๐Ÿ’ฌ Chat"],
339
+ horizontal=True
340
+ )
 
341
 
342
+ if tab == "๐ŸŽค Voice Input":
343
+ handle_speech_recognition()
344
+ else:
345
+ handle_chat()
 
 
 
 
 
 
 
346
 
347
  if __name__ == "__main__":
348
  main()