Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -77,7 +77,7 @@ for d in ["chat_logs", "vote_logs", "audio_logs", "history_logs", "audio_cache"]
|
|
| 77 |
|
| 78 |
CHAT_DIR = "chat_logs"
|
| 79 |
VOTE_DIR = "vote_logs"
|
| 80 |
-
MEDIA_DIR = "."
|
| 81 |
AUDIO_CACHE_DIR = "audio_cache"
|
| 82 |
AUDIO_DIR = "audio_logs"
|
| 83 |
STATE_FILE = "user_state.txt"
|
|
@@ -101,11 +101,12 @@ def format_timestamp_prefix(username=""):
|
|
| 101 |
|
| 102 |
# ๐ Performance Timer
|
| 103 |
class PerformanceTimer:
|
| 104 |
-
def __init__(self, name):
|
| 105 |
-
|
|
|
|
| 106 |
self.start = time.time()
|
| 107 |
return self
|
| 108 |
-
def __exit__(self, *args):
|
| 109 |
duration = time.time() - self.start
|
| 110 |
st.session_state['operation_timings'][self.name] = duration
|
| 111 |
st.session_state['performance_metrics'][self.name].append(duration)
|
|
@@ -128,7 +129,8 @@ def init_session_state():
|
|
| 128 |
'quote_source': "famous"
|
| 129 |
}
|
| 130 |
for k, v in defaults.items():
|
| 131 |
-
if k not in st.session_state:
|
|
|
|
| 132 |
|
| 133 |
# ๐๏ธ Marquee Helpers
|
| 134 |
def update_marquee_settings_ui():
|
|
@@ -147,8 +149,12 @@ def display_marquee(text, settings, key_suffix=""):
|
|
| 147 |
st.write("")
|
| 148 |
|
| 149 |
# ๐ Text & File Helpers
|
| 150 |
-
def clean_text_for_tts(text):
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
def get_high_info_terms(text, top_n=10):
|
| 153 |
stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with'}
|
| 154 |
words = re.findall(r'\b\w+(?:-\w+)*\b', text.lower())
|
|
@@ -163,7 +169,8 @@ def generate_filename(prompt, username, file_type="md"):
|
|
| 163 |
|
| 164 |
def create_file(prompt, username, file_type="md"):
|
| 165 |
filename = generate_filename(prompt, username, file_type)
|
| 166 |
-
with open(filename, 'w', encoding='utf-8') as f:
|
|
|
|
| 167 |
return filename
|
| 168 |
|
| 169 |
def get_download_link(file, file_type="mp3"):
|
|
@@ -202,10 +209,12 @@ def concatenate_markdown_files():
|
|
| 202 |
# ๐ถ Audio Processing
|
| 203 |
async def async_edge_tts_generate(text, voice, username, rate=0, pitch=0, file_format="mp3"):
|
| 204 |
cache_key = f"{text[:100]}_{voice}_{rate}_{pitch}_{file_format}"
|
| 205 |
-
if cache_key in st.session_state['audio_cache']:
|
|
|
|
| 206 |
start_time = time.time()
|
| 207 |
text = clean_text_for_tts(text)
|
| 208 |
-
if not text:
|
|
|
|
| 209 |
filename = f"{format_timestamp_prefix(username)}-{hashlib.md5(text.encode()).hexdigest()[:8]}.{file_format}"
|
| 210 |
communicate = edge_tts.Communicate(text, voice, rate=f"{rate:+d}%", pitch=f"{pitch:+d}Hz")
|
| 211 |
await communicate.save(filename)
|
|
@@ -228,11 +237,13 @@ async def save_chat_entry(username, message, is_markdown=False):
|
|
| 228 |
central = pytz.timezone('US/Central')
|
| 229 |
timestamp = datetime.now(central).strftime("%Y-%m-%d %H:%M:%S")
|
| 230 |
entry = f"[{timestamp}] {username}: {message}" if not is_markdown else f"[{timestamp}] {username}:\n```markdown\n{message}\n```"
|
| 231 |
-
with open(CHAT_FILE, 'a') as f:
|
|
|
|
| 232 |
voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
|
| 233 |
audio_file, _ = await async_edge_tts_generate(message, voice, username)
|
| 234 |
if audio_file:
|
| 235 |
-
with open(HISTORY_FILE, 'a') as f:
|
|
|
|
| 236 |
st.session_state['mp3_files'][os.path.basename(audio_file)] = audio_file
|
| 237 |
await broadcast_message(f"{username}|{message}", "chat")
|
| 238 |
st.session_state.last_chat_update = time.time()
|
|
@@ -241,8 +252,9 @@ async def save_chat_entry(username, message, is_markdown=False):
|
|
| 241 |
|
| 242 |
async def load_chat():
|
| 243 |
if not os.path.exists(CHAT_FILE):
|
| 244 |
-
with open(CHAT_FILE, 'a') as f:
|
| 245 |
-
|
|
|
|
| 246 |
content = f.read().strip()
|
| 247 |
lines = content.split('\n')
|
| 248 |
numbered_content = "\n".join(f"{i+1}. {line}" for i, line in enumerate(lines) if line.strip())
|
|
@@ -298,7 +310,8 @@ class AudioProcessor:
|
|
| 298 |
self.metadata = json.load(open(f"{self.cache_dir}/metadata.json")) if os.path.exists(f"{self.cache_dir}/metadata.json") else {}
|
| 299 |
|
| 300 |
def _save_metadata(self):
|
| 301 |
-
with open(f"{self.cache_dir}/metadata.json", 'w') as f:
|
|
|
|
| 302 |
|
| 303 |
async def create_audio(self, text, voice='en-US-AriaNeural'):
|
| 304 |
cache_key = hashlib.md5(f"{text}:{voice}".encode()).hexdigest()
|
|
@@ -306,7 +319,8 @@ class AudioProcessor:
|
|
| 306 |
if cache_key in self.metadata and os.path.exists(cache_path):
|
| 307 |
return cache_path
|
| 308 |
text = clean_text_for_tts(text)
|
| 309 |
-
if not text:
|
|
|
|
| 310 |
communicate = edge_tts.Communicate(text, voice)
|
| 311 |
await communicate.save(cache_path)
|
| 312 |
self.metadata[cache_key] = {'timestamp': datetime.now().isoformat(), 'text_length': len(text), 'voice': voice}
|
|
@@ -317,7 +331,7 @@ def process_pdf(pdf_file, max_pages, voice, audio_processor):
|
|
| 317 |
reader = PdfReader(pdf_file)
|
| 318 |
total_pages = min(len(reader.pages), max_pages)
|
| 319 |
texts, audios = [], {}
|
| 320 |
-
async def process_page(i, text):
|
| 321 |
audio_path = await audio_processor.create_audio(text, voice)
|
| 322 |
if audio_path:
|
| 323 |
audios[i] = audio_path
|
|
@@ -329,19 +343,24 @@ def process_pdf(pdf_file, max_pages, voice, audio_processor):
|
|
| 329 |
|
| 330 |
# ๐ ArXiv & AI Lookup
|
| 331 |
def parse_arxiv_refs(ref_text):
|
| 332 |
-
if not ref_text:
|
|
|
|
| 333 |
papers = []
|
| 334 |
current = {}
|
| 335 |
for line in ref_text.split('\n'):
|
| 336 |
if line.count('|') == 2:
|
| 337 |
-
if current:
|
|
|
|
| 338 |
date, title, *_ = line.strip('* ').split('|')
|
| 339 |
url = re.search(r'(https://arxiv.org/\S+)', line).group(1) if re.search(r'(https://arxiv.org/\S+)', line) else f"paper_{len(papers)}"
|
| 340 |
current = {'date': date, 'title': title, 'url': url, 'authors': '', 'summary': '', 'full_audio': None, 'download_base64': ''}
|
| 341 |
elif current:
|
| 342 |
-
if not current['authors']:
|
| 343 |
-
|
| 344 |
-
|
|
|
|
|
|
|
|
|
|
| 345 |
return papers[:20]
|
| 346 |
|
| 347 |
def generate_5min_feature_markdown(paper):
|
|
@@ -363,13 +382,15 @@ def generate_5min_feature_markdown(paper):
|
|
| 363 |
---
|
| 364 |
"""
|
| 365 |
|
| 366 |
-
def create_detailed_paper_md(papers):
|
|
|
|
| 367 |
|
| 368 |
async def create_paper_audio_files(papers, query):
|
| 369 |
for p in papers:
|
| 370 |
audio_text = clean_text_for_tts(f"{p['title']} by {p['authors']}. {p['summary']}")
|
| 371 |
p['full_audio'], _ = await async_edge_tts_generate(audio_text, st.session_state['tts_voice'], p['authors'])
|
| 372 |
-
if p['full_audio']:
|
|
|
|
| 373 |
|
| 374 |
async def perform_ai_lookup(q, useArxiv=True, useArxivAudio=False):
|
| 375 |
client = anthropic.Anthropic(api_key=anthropic_key)
|
|
@@ -388,7 +409,8 @@ async def perform_ai_lookup(q, useArxiv=True, useArxivAudio=False):
|
|
| 388 |
md_file, audio_file = create_file(result, "System", "md"), (await async_edge_tts_generate(result, st.session_state['tts_voice'], "System"))[0]
|
| 389 |
play_and_download_audio(audio_file)
|
| 390 |
papers = parse_arxiv_refs(refs)
|
| 391 |
-
if papers and useArxivAudio:
|
|
|
|
| 392 |
return result, papers
|
| 393 |
return result, []
|
| 394 |
|
|
@@ -435,7 +457,7 @@ async def save_pasted_image(image, username):
|
|
| 435 |
return None
|
| 436 |
timestamp = format_timestamp_prefix(username)
|
| 437 |
filename = f"{timestamp}-{img_hash}.png"
|
| 438 |
-
filepath = filename
|
| 439 |
image.save(filepath, "PNG")
|
| 440 |
st.session_state.image_hashes.add(img_hash)
|
| 441 |
return filepath
|
|
@@ -443,10 +465,12 @@ async def save_pasted_image(image, username):
|
|
| 443 |
# ๐ฆ Zip Files
|
| 444 |
def create_zip_of_files(md_files, mp3_files, png_files, mp4_files, query):
|
| 445 |
all_files = md_files + mp3_files + png_files + mp4_files
|
| 446 |
-
if not all_files:
|
|
|
|
| 447 |
terms = get_high_info_terms(" ".join([open(f, 'r', encoding='utf-8').read() if f.endswith('.md') else os.path.splitext(os.path.basename(f))[0].replace('_', ' ') for f in all_files] + [query]), 5)
|
| 448 |
zip_name = f"{format_timestamp_prefix()}_{'-'.join(terms)[:20]}.zip"
|
| 449 |
-
with zipfile.ZipFile(zip_name, 'w') as z:
|
|
|
|
| 450 |
return zip_name
|
| 451 |
|
| 452 |
# ๐ฎ Main Interface
|
|
@@ -498,7 +522,7 @@ async def async_interface():
|
|
| 498 |
st.session_state.timer_start = time.time()
|
| 499 |
save_username(st.session_state.username)
|
| 500 |
st.rerun()
|
| 501 |
-
|
| 502 |
message = st.text_input(f"Message as {st.session_state.username}", key="message_input")
|
| 503 |
paste_result = paste_image_button("๐ Paste Image or Text", key="paste_button_msg")
|
| 504 |
if paste_result.image_data is not None:
|
|
@@ -524,22 +548,28 @@ async def async_interface():
|
|
| 524 |
|
| 525 |
st.subheader("๐ค Speech-to-Chat")
|
| 526 |
from mycomponent import speech_component
|
| 527 |
-
transcript_data = speech_component(default_value=st.session_state.get('last_transcript', ''))
|
| 528 |
if transcript_data and 'value' in transcript_data:
|
| 529 |
transcript = transcript_data['value'].strip()
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
st.session_state.last_transcript
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
|
| 544 |
# ๐ธ Media
|
| 545 |
elif tab_main == "๐ธ Media":
|
|
@@ -550,12 +580,10 @@ async def async_interface():
|
|
| 550 |
png_files = [f for f in all_files if f.endswith('.png')]
|
| 551 |
mp4_files = [f for f in all_files if f.endswith('.mp4')]
|
| 552 |
|
| 553 |
-
# Display concatenated Markdown
|
| 554 |
st.subheader("All Submitted Text")
|
| 555 |
all_md_content = concatenate_markdown_files()
|
| 556 |
st.markdown(all_md_content)
|
| 557 |
|
| 558 |
-
# Display Media by Type at End
|
| 559 |
st.subheader("๐ต Audio (MP3)")
|
| 560 |
for mp3 in mp3_files:
|
| 561 |
with st.expander(os.path.basename(mp3)):
|
|
@@ -577,7 +605,7 @@ async def async_interface():
|
|
| 577 |
uploaded_file = st.file_uploader("Upload Media", type=['png', 'mp4', 'mp3'])
|
| 578 |
if uploaded_file:
|
| 579 |
filename = f"{format_timestamp_prefix(st.session_state.username)}-{hashlib.md5(uploaded_file.getbuffer()).hexdigest()[:8]}.{uploaded_file.name.split('.')[-1]}"
|
| 580 |
-
with open(filename, 'wb') as f:
|
| 581 |
f.write(uploaded_file.getbuffer())
|
| 582 |
await save_chat_entry(st.session_state.username, f"Uploaded: {filename}")
|
| 583 |
st.session_state.timer_start = time.time()
|
|
@@ -595,7 +623,8 @@ async def async_interface():
|
|
| 595 |
with st.expander(f"{i}. ๐ {p['title']}"):
|
| 596 |
st.markdown(f"**{p['date']} | {p['title']}** โ [Link]({p['url']})")
|
| 597 |
st.markdown(generate_5min_feature_markdown(p))
|
| 598 |
-
if p.get('full_audio'):
|
|
|
|
| 599 |
|
| 600 |
# ๐ PDF to Audio
|
| 601 |
elif tab_main == "๐ PDF to Audio":
|
|
@@ -608,7 +637,8 @@ async def async_interface():
|
|
| 608 |
for i, text in enumerate(texts):
|
| 609 |
with st.expander(f"Page {i+1}"):
|
| 610 |
st.markdown(text)
|
| 611 |
-
while i not in audios:
|
|
|
|
| 612 |
if audios.get(i):
|
| 613 |
st.audio(audios[i])
|
| 614 |
st.markdown(get_download_link(audios[i], "mp3"), unsafe_allow_html=True)
|
|
@@ -662,7 +692,8 @@ async def async_interface():
|
|
| 662 |
st.sidebar.write(f"{FILE_EMOJIS.get(f.split('.')[-1], '๐')} {os.path.basename(f)}")
|
| 663 |
if st.sidebar.button("โฌ๏ธ Zip All"):
|
| 664 |
zip_name = create_zip_of_files(md_files, mp3_files, png_files, mp4_files, "latest_query")
|
| 665 |
-
if zip_name:
|
|
|
|
| 666 |
|
| 667 |
def main():
|
| 668 |
asyncio.run(async_interface())
|
|
|
|
| 77 |
|
| 78 |
CHAT_DIR = "chat_logs"
|
| 79 |
VOTE_DIR = "vote_logs"
|
| 80 |
+
MEDIA_DIR = "."
|
| 81 |
AUDIO_CACHE_DIR = "audio_cache"
|
| 82 |
AUDIO_DIR = "audio_logs"
|
| 83 |
STATE_FILE = "user_state.txt"
|
|
|
|
| 101 |
|
| 102 |
# ๐ Performance Timer
|
| 103 |
class PerformanceTimer:
|
| 104 |
+
def __init__(self, name):
|
| 105 |
+
self.name, self.start = name, None
|
| 106 |
+
def __enter__(self):
|
| 107 |
self.start = time.time()
|
| 108 |
return self
|
| 109 |
+
def __exit__(self, *args):
|
| 110 |
duration = time.time() - self.start
|
| 111 |
st.session_state['operation_timings'][self.name] = duration
|
| 112 |
st.session_state['performance_metrics'][self.name].append(duration)
|
|
|
|
| 129 |
'quote_source': "famous"
|
| 130 |
}
|
| 131 |
for k, v in defaults.items():
|
| 132 |
+
if k not in st.session_state:
|
| 133 |
+
st.session_state[k] = v
|
| 134 |
|
| 135 |
# ๐๏ธ Marquee Helpers
|
| 136 |
def update_marquee_settings_ui():
|
|
|
|
| 149 |
st.write("")
|
| 150 |
|
| 151 |
# ๐ Text & File Helpers
|
| 152 |
+
def clean_text_for_tts(text):
|
| 153 |
+
return re.sub(r'[#*!\[\]]+', '', ' '.join(text.split()))[:200] or "No text"
|
| 154 |
+
|
| 155 |
+
def clean_text_for_filename(text):
|
| 156 |
+
return '_'.join(re.sub(r'[^\w\s-]', '', text.lower()).split())[:200]
|
| 157 |
+
|
| 158 |
def get_high_info_terms(text, top_n=10):
|
| 159 |
stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with'}
|
| 160 |
words = re.findall(r'\b\w+(?:-\w+)*\b', text.lower())
|
|
|
|
| 169 |
|
| 170 |
def create_file(prompt, username, file_type="md"):
|
| 171 |
filename = generate_filename(prompt, username, file_type)
|
| 172 |
+
with open(filename, 'w', encoding='utf-8') as f:
|
| 173 |
+
f.write(prompt)
|
| 174 |
return filename
|
| 175 |
|
| 176 |
def get_download_link(file, file_type="mp3"):
|
|
|
|
| 209 |
# ๐ถ Audio Processing
|
| 210 |
async def async_edge_tts_generate(text, voice, username, rate=0, pitch=0, file_format="mp3"):
|
| 211 |
cache_key = f"{text[:100]}_{voice}_{rate}_{pitch}_{file_format}"
|
| 212 |
+
if cache_key in st.session_state['audio_cache']:
|
| 213 |
+
return st.session_state['audio_cache'][cache_key], 0
|
| 214 |
start_time = time.time()
|
| 215 |
text = clean_text_for_tts(text)
|
| 216 |
+
if not text:
|
| 217 |
+
return None, 0
|
| 218 |
filename = f"{format_timestamp_prefix(username)}-{hashlib.md5(text.encode()).hexdigest()[:8]}.{file_format}"
|
| 219 |
communicate = edge_tts.Communicate(text, voice, rate=f"{rate:+d}%", pitch=f"{pitch:+d}Hz")
|
| 220 |
await communicate.save(filename)
|
|
|
|
| 237 |
central = pytz.timezone('US/Central')
|
| 238 |
timestamp = datetime.now(central).strftime("%Y-%m-%d %H:%M:%S")
|
| 239 |
entry = f"[{timestamp}] {username}: {message}" if not is_markdown else f"[{timestamp}] {username}:\n```markdown\n{message}\n```"
|
| 240 |
+
with open(CHAT_FILE, 'a') as f:
|
| 241 |
+
f.write(f"{entry}\n")
|
| 242 |
voice = FUN_USERNAMES.get(username, "en-US-AriaNeural")
|
| 243 |
audio_file, _ = await async_edge_tts_generate(message, voice, username)
|
| 244 |
if audio_file:
|
| 245 |
+
with open(HISTORY_FILE, 'a') as f:
|
| 246 |
+
f.write(f"[{timestamp}] {username}: Audio - {audio_file}\n")
|
| 247 |
st.session_state['mp3_files'][os.path.basename(audio_file)] = audio_file
|
| 248 |
await broadcast_message(f"{username}|{message}", "chat")
|
| 249 |
st.session_state.last_chat_update = time.time()
|
|
|
|
| 252 |
|
| 253 |
async def load_chat():
|
| 254 |
if not os.path.exists(CHAT_FILE):
|
| 255 |
+
with open(CHAT_FILE, 'a') as f:
|
| 256 |
+
f.write(f"# {START_ROOM} Chat\n\nWelcome to the cosmic hub! ๐ค\n")
|
| 257 |
+
with open(CHAT_FILE, 'r') as f:
|
| 258 |
content = f.read().strip()
|
| 259 |
lines = content.split('\n')
|
| 260 |
numbered_content = "\n".join(f"{i+1}. {line}" for i, line in enumerate(lines) if line.strip())
|
|
|
|
| 310 |
self.metadata = json.load(open(f"{self.cache_dir}/metadata.json")) if os.path.exists(f"{self.cache_dir}/metadata.json") else {}
|
| 311 |
|
| 312 |
def _save_metadata(self):
|
| 313 |
+
with open(f"{self.cache_dir}/metadata.json", 'w') as f:
|
| 314 |
+
json.dump(self.metadata, f)
|
| 315 |
|
| 316 |
async def create_audio(self, text, voice='en-US-AriaNeural'):
|
| 317 |
cache_key = hashlib.md5(f"{text}:{voice}".encode()).hexdigest()
|
|
|
|
| 319 |
if cache_key in self.metadata and os.path.exists(cache_path):
|
| 320 |
return cache_path
|
| 321 |
text = clean_text_for_tts(text)
|
| 322 |
+
if not text:
|
| 323 |
+
return None
|
| 324 |
communicate = edge_tts.Communicate(text, voice)
|
| 325 |
await communicate.save(cache_path)
|
| 326 |
self.metadata[cache_key] = {'timestamp': datetime.now().isoformat(), 'text_length': len(text), 'voice': voice}
|
|
|
|
| 331 |
reader = PdfReader(pdf_file)
|
| 332 |
total_pages = min(len(reader.pages), max_pages)
|
| 333 |
texts, audios = [], {}
|
| 334 |
+
async def process_page(i, text):
|
| 335 |
audio_path = await audio_processor.create_audio(text, voice)
|
| 336 |
if audio_path:
|
| 337 |
audios[i] = audio_path
|
|
|
|
| 343 |
|
| 344 |
# ๐ ArXiv & AI Lookup
|
| 345 |
def parse_arxiv_refs(ref_text):
|
| 346 |
+
if not ref_text:
|
| 347 |
+
return []
|
| 348 |
papers = []
|
| 349 |
current = {}
|
| 350 |
for line in ref_text.split('\n'):
|
| 351 |
if line.count('|') == 2:
|
| 352 |
+
if current:
|
| 353 |
+
papers.append(current)
|
| 354 |
date, title, *_ = line.strip('* ').split('|')
|
| 355 |
url = re.search(r'(https://arxiv.org/\S+)', line).group(1) if re.search(r'(https://arxiv.org/\S+)', line) else f"paper_{len(papers)}"
|
| 356 |
current = {'date': date, 'title': title, 'url': url, 'authors': '', 'summary': '', 'full_audio': None, 'download_base64': ''}
|
| 357 |
elif current:
|
| 358 |
+
if not current['authors']:
|
| 359 |
+
current['authors'] = line.strip('* ')
|
| 360 |
+
else:
|
| 361 |
+
current['summary'] += ' ' + line.strip() if current['summary'] else line.strip()
|
| 362 |
+
if current:
|
| 363 |
+
papers.append(current)
|
| 364 |
return papers[:20]
|
| 365 |
|
| 366 |
def generate_5min_feature_markdown(paper):
|
|
|
|
| 382 |
---
|
| 383 |
"""
|
| 384 |
|
| 385 |
+
def create_detailed_paper_md(papers):
|
| 386 |
+
return "# Detailed Summary\n" + "\n".join(generate_5min_feature_markdown(p) for p in papers)
|
| 387 |
|
| 388 |
async def create_paper_audio_files(papers, query):
|
| 389 |
for p in papers:
|
| 390 |
audio_text = clean_text_for_tts(f"{p['title']} by {p['authors']}. {p['summary']}")
|
| 391 |
p['full_audio'], _ = await async_edge_tts_generate(audio_text, st.session_state['tts_voice'], p['authors'])
|
| 392 |
+
if p['full_audio']:
|
| 393 |
+
p['download_base64'] = get_download_link(p['full_audio'])
|
| 394 |
|
| 395 |
async def perform_ai_lookup(q, useArxiv=True, useArxivAudio=False):
|
| 396 |
client = anthropic.Anthropic(api_key=anthropic_key)
|
|
|
|
| 409 |
md_file, audio_file = create_file(result, "System", "md"), (await async_edge_tts_generate(result, st.session_state['tts_voice'], "System"))[0]
|
| 410 |
play_and_download_audio(audio_file)
|
| 411 |
papers = parse_arxiv_refs(refs)
|
| 412 |
+
if papers and useArxivAudio:
|
| 413 |
+
await create_paper_audio_files(papers, q)
|
| 414 |
return result, papers
|
| 415 |
return result, []
|
| 416 |
|
|
|
|
| 457 |
return None
|
| 458 |
timestamp = format_timestamp_prefix(username)
|
| 459 |
filename = f"{timestamp}-{img_hash}.png"
|
| 460 |
+
filepath = filename
|
| 461 |
image.save(filepath, "PNG")
|
| 462 |
st.session_state.image_hashes.add(img_hash)
|
| 463 |
return filepath
|
|
|
|
| 465 |
# ๐ฆ Zip Files
|
| 466 |
def create_zip_of_files(md_files, mp3_files, png_files, mp4_files, query):
|
| 467 |
all_files = md_files + mp3_files + png_files + mp4_files
|
| 468 |
+
if not all_files:
|
| 469 |
+
return None
|
| 470 |
terms = get_high_info_terms(" ".join([open(f, 'r', encoding='utf-8').read() if f.endswith('.md') else os.path.splitext(os.path.basename(f))[0].replace('_', ' ') for f in all_files] + [query]), 5)
|
| 471 |
zip_name = f"{format_timestamp_prefix()}_{'-'.join(terms)[:20]}.zip"
|
| 472 |
+
with zipfile.ZipFile(zip_name, 'w') as z:
|
| 473 |
+
[z.write(f) for f in all_files]
|
| 474 |
return zip_name
|
| 475 |
|
| 476 |
# ๐ฎ Main Interface
|
|
|
|
| 522 |
st.session_state.timer_start = time.time()
|
| 523 |
save_username(st.session_state.username)
|
| 524 |
st.rerun()
|
| 525 |
+
|
| 526 |
message = st.text_input(f"Message as {st.session_state.username}", key="message_input")
|
| 527 |
paste_result = paste_image_button("๐ Paste Image or Text", key="paste_button_msg")
|
| 528 |
if paste_result.image_data is not None:
|
|
|
|
| 548 |
|
| 549 |
st.subheader("๐ค Speech-to-Chat")
|
| 550 |
from mycomponent import speech_component
|
| 551 |
+
transcript_data = speech_component(default_value=st.session_state.get('last_transcript', ''), key="speech_input")
|
| 552 |
if transcript_data and 'value' in transcript_data:
|
| 553 |
transcript = transcript_data['value'].strip()
|
| 554 |
+
if transcript:
|
| 555 |
+
st.write(f"๐๏ธ You said: {transcript}")
|
| 556 |
+
if transcript != st.session_state.last_transcript:
|
| 557 |
+
st.session_state.last_transcript = transcript
|
| 558 |
+
if st.session_state.autosend:
|
| 559 |
+
await save_chat_entry(st.session_state.username, transcript, True)
|
| 560 |
+
st.session_state.timer_start = time.time()
|
| 561 |
+
save_username(st.session_state.username)
|
| 562 |
+
# Update chat display without full rerun to reduce flicker
|
| 563 |
+
with chat_container:
|
| 564 |
+
st.markdown(await load_chat())
|
| 565 |
+
else:
|
| 566 |
+
if st.button("Send to Chat", key="send_transcript"):
|
| 567 |
+
await save_chat_entry(st.session_state.username, transcript, True)
|
| 568 |
+
st.session_state.timer_start = time.time()
|
| 569 |
+
save_username(st.session_state.username)
|
| 570 |
+
st.rerun()
|
| 571 |
+
else:
|
| 572 |
+
st.write("๐๏ธ Speak to transcribe your message...")
|
| 573 |
|
| 574 |
# ๐ธ Media
|
| 575 |
elif tab_main == "๐ธ Media":
|
|
|
|
| 580 |
png_files = [f for f in all_files if f.endswith('.png')]
|
| 581 |
mp4_files = [f for f in all_files if f.endswith('.mp4')]
|
| 582 |
|
|
|
|
| 583 |
st.subheader("All Submitted Text")
|
| 584 |
all_md_content = concatenate_markdown_files()
|
| 585 |
st.markdown(all_md_content)
|
| 586 |
|
|
|
|
| 587 |
st.subheader("๐ต Audio (MP3)")
|
| 588 |
for mp3 in mp3_files:
|
| 589 |
with st.expander(os.path.basename(mp3)):
|
|
|
|
| 605 |
uploaded_file = st.file_uploader("Upload Media", type=['png', 'mp4', 'mp3'])
|
| 606 |
if uploaded_file:
|
| 607 |
filename = f"{format_timestamp_prefix(st.session_state.username)}-{hashlib.md5(uploaded_file.getbuffer()).hexdigest()[:8]}.{uploaded_file.name.split('.')[-1]}"
|
| 608 |
+
with open(filename, 'wb') as f:
|
| 609 |
f.write(uploaded_file.getbuffer())
|
| 610 |
await save_chat_entry(st.session_state.username, f"Uploaded: {filename}")
|
| 611 |
st.session_state.timer_start = time.time()
|
|
|
|
| 623 |
with st.expander(f"{i}. ๐ {p['title']}"):
|
| 624 |
st.markdown(f"**{p['date']} | {p['title']}** โ [Link]({p['url']})")
|
| 625 |
st.markdown(generate_5min_feature_markdown(p))
|
| 626 |
+
if p.get('full_audio'):
|
| 627 |
+
play_and_download_audio(p['full_audio'])
|
| 628 |
|
| 629 |
# ๐ PDF to Audio
|
| 630 |
elif tab_main == "๐ PDF to Audio":
|
|
|
|
| 637 |
for i, text in enumerate(texts):
|
| 638 |
with st.expander(f"Page {i+1}"):
|
| 639 |
st.markdown(text)
|
| 640 |
+
while i not in audios:
|
| 641 |
+
time.sleep(0.1)
|
| 642 |
if audios.get(i):
|
| 643 |
st.audio(audios[i])
|
| 644 |
st.markdown(get_download_link(audios[i], "mp3"), unsafe_allow_html=True)
|
|
|
|
| 692 |
st.sidebar.write(f"{FILE_EMOJIS.get(f.split('.')[-1], '๐')} {os.path.basename(f)}")
|
| 693 |
if st.sidebar.button("โฌ๏ธ Zip All"):
|
| 694 |
zip_name = create_zip_of_files(md_files, mp3_files, png_files, mp4_files, "latest_query")
|
| 695 |
+
if zip_name:
|
| 696 |
+
st.sidebar.markdown(get_download_link(zip_name, "zip"), unsafe_allow_html=True)
|
| 697 |
|
| 698 |
def main():
|
| 699 |
asyncio.run(async_interface())
|