awacke1 commited on
Commit
c58ba1f
·
verified ·
1 Parent(s): 1d9bee0

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +489 -0
app.py ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import glob
4
+ import re
5
+ import base64
6
+ import pytz
7
+ import time
8
+ import streamlit.components.v1 as components
9
+
10
+ from urllib.parse import quote
11
+ from gradio_client import Client
12
+ from datetime import datetime
13
+
14
+ # Page configuration
15
+ Site_Name = 'AI Knowledge Tree Builder 📈🌿 Grow Smarter with Every Click'
16
+ title = "🌳✨AI Knowledge Tree Builder🛠️🤓"
17
+ helpURL = 'https://huggingface.co/spaces/awacke1/AIKnowledgeTreeBuilder/'
18
+ bugURL = 'https://huggingface.co/spaces/awacke1/AIKnowledgeTreeBuilder/'
19
+ icons = '🌳✨🛠️🤓'
20
+
21
+ SidebarOutline = """🌳🤖 Designed with the following tenets:
22
+ 1 📱 **Portability** - Universal access via any device & link sharing
23
+ 2. ⚡ **Speed of Build** - Rapid deployments < 2min to production
24
+ 3. 🔗 **Linkiness** - Programmatic access to AI knowledge sources
25
+ 4. 🎯 **Abstractive** - Core stays lean isolating high-maintenance components
26
+ 5. 🧠 **Memory** - Shareable flows deep-linked research paths
27
+ 6. 👤 **Personalized** - Rapidly adapts knowledge base to user needs
28
+ 7. 🐦 **Living Brevity** - Easily cloneable, self modify data public share results.
29
+ """
30
+
31
+ st.set_page_config(
32
+ page_title=title,
33
+ page_icon=icons,
34
+ layout="wide",
35
+ initial_sidebar_state="auto",
36
+ menu_items={
37
+ 'Get Help': helpURL,
38
+ 'Report a bug': bugURL,
39
+ 'About': title
40
+ }
41
+ )
42
+
43
+ st.sidebar.markdown(SidebarOutline)
44
+
45
+ # Initialize session state variables
46
+ if 'selected_file' not in st.session_state:
47
+ st.session_state.selected_file = None
48
+ if 'view_mode' not in st.session_state:
49
+ st.session_state.view_mode = 'view'
50
+ if 'files' not in st.session_state:
51
+ st.session_state.files = []
52
+
53
+ # --- MoE System Prompts Setup ---
54
+ moe_prompts_data = """1. Create a python streamlit app.py demonstrating the topic and show top 3 arxiv papers discussing this as reference.
55
+ 2. Create a python gradio app.py demonstrating the topic and show top 3 arxiv papers discussing this as reference.
56
+ 3. Create a mermaid model of the knowledge tree around concepts and parts of this topic. Use appropriate emojis.
57
+ 4. Create a top three list of tools and techniques for this topic with markdown and emojis.
58
+ 5. Create a specification in markdown outline with emojis for this topic.
59
+ 6. Create an image generation prompt for this with Bosch and Turner oil painting influences.
60
+ 7. Generate an image which describes this as a concept and area of study.
61
+ 8. List top ten glossary terms with emojis related to this topic as markdown outline."""
62
+ # Split the data by lines and remove the numbering/period (assume each line has "number. " at the start)
63
+ moe_prompts_list = [line.split('. ', 1)[1].strip() for line in moe_prompts_data.splitlines() if '. ' in line]
64
+ moe_options = [""] + moe_prompts_list # blank is default
65
+
66
+ # Place the selectbox at the top of the app; store selection in session_state key "selected_moe"
67
+ selected_moe = st.selectbox("Choose a MoE system prompt", options=moe_options, index=0, key="selected_moe")
68
+
69
+ # --- Utility Functions ---
70
+
71
+ def get_display_name(filename):
72
+ """Extract text from parentheses or return filename as is."""
73
+ match = re.search(r'\((.*?)\)', filename)
74
+ if match:
75
+ return match.group(1)
76
+ return filename
77
+
78
+ def get_time_display(filename):
79
+ """Extract just the time portion from the filename."""
80
+ time_match = re.match(r'(\d{2}\d{2}[AP]M)', filename)
81
+ if time_match:
82
+ return time_match.group(1)
83
+ return filename
84
+
85
+ def sanitize_filename(text):
86
+ """Create a safe filename from text while preserving spaces."""
87
+ safe_text = re.sub(r'[^\w\s-]', ' ', text)
88
+ safe_text = re.sub(r'\s+', ' ', safe_text)
89
+ safe_text = safe_text.strip()
90
+ return safe_text[:50]
91
+
92
+ def generate_timestamp_filename(query):
93
+ """Generate filename with format: 1103AM 11032024 (Query).md"""
94
+ central = pytz.timezone('US/Central')
95
+ current_time = datetime.now(central)
96
+ time_str = current_time.strftime("%I%M%p")
97
+ date_str = current_time.strftime("%m%d%Y")
98
+ safe_query = sanitize_filename(query)
99
+ filename = f"{time_str} {date_str} ({safe_query}).md"
100
+ return filename
101
+
102
+ def delete_file(file_path):
103
+ """Delete a file and return success status."""
104
+ try:
105
+ os.remove(file_path)
106
+ return True
107
+ except Exception as e:
108
+ st.error(f"Error deleting file: {e}")
109
+ return False
110
+
111
+ def save_ai_interaction(query, ai_result, is_rerun=False):
112
+ """Save AI interaction to a markdown file with new filename format."""
113
+ filename = generate_timestamp_filename(query)
114
+ if is_rerun:
115
+ content = f"""# Rerun Query
116
+ Original file content used for rerun:
117
+
118
+ {query}
119
+
120
+ # AI Response (Fun Version)
121
+ {ai_result}
122
+ """
123
+ else:
124
+ content = f"""# Query: {query}
125
+
126
+ ## AI Response
127
+ {ai_result}
128
+ """
129
+ try:
130
+ with open(filename, 'w', encoding='utf-8') as f:
131
+ f.write(content)
132
+ return filename
133
+ except Exception as e:
134
+ st.error(f"Error saving file: {e}")
135
+ return None
136
+
137
+ def get_file_download_link(file_path):
138
+ """Generate a base64 download link for a file."""
139
+ try:
140
+ with open(file_path, 'r', encoding='utf-8') as f:
141
+ content = f.read()
142
+ b64 = base64.b64encode(content.encode()).decode()
143
+ filename = os.path.basename(file_path)
144
+ return f'<a href="data:text/markdown;base64,{b64}" download="{filename}">{get_display_name(filename)}</a>'
145
+ except Exception as e:
146
+ st.error(f"Error creating download link: {e}")
147
+ return None
148
+
149
+ # --- New Functions for Markdown File Parsing and Link Tree ---
150
+
151
+ def clean_item_text(line):
152
+ """
153
+ Remove emoji and numbered prefix from a line.
154
+ E.g., "🔧 1. Low-level system integrations compilers Cplusplus" becomes
155
+ "Low-level system integrations compilers Cplusplus".
156
+ Also remove any bold markdown markers.
157
+ """
158
+ # Remove leading emoji and number+period
159
+ cleaned = re.sub(r'^[^\w]*(\d+\.\s*)', '', line)
160
+ # Remove any remaining emoji (simple unicode range) and ** markers
161
+ cleaned = re.sub(r'[\U0001F300-\U0001FAFF]', '', cleaned)
162
+ cleaned = cleaned.replace("**", "")
163
+ return cleaned.strip()
164
+
165
+ def clean_header_text(header_line):
166
+ """
167
+ Extract header text from a markdown header line.
168
+ E.g., "🔧 **Systems, Infrastructure & Low-Level Engineering**" becomes
169
+ "Systems, Infrastructure & Low-Level Engineering".
170
+ """
171
+ match = re.search(r'\*\*(.*?)\*\*', header_line)
172
+ if match:
173
+ return match.group(1).strip()
174
+ return header_line.strip()
175
+
176
+ def parse_markdown_sections(md_text):
177
+ """
178
+ Parse markdown text into sections.
179
+ Each section starts with a header line containing bold text.
180
+ Returns a list of dicts with keys: 'header' and 'items' (list of lines).
181
+ Skips any content before the first header.
182
+ """
183
+ sections = []
184
+ current_section = None
185
+ lines = md_text.splitlines()
186
+ for line in lines:
187
+ if line.strip() == "":
188
+ continue
189
+ # Check if line is a header (contains bold markdown and an emoji)
190
+ if '**' in line:
191
+ header = clean_header_text(line)
192
+ current_section = {'header': header, 'raw': line, 'items': []}
193
+ sections.append(current_section)
194
+ elif current_section is not None:
195
+ # Only add lines that appear to be list items (start with an emoji and number)
196
+ if re.match(r'^[^\w]*\d+\.\s+', line):
197
+ current_section['items'].append(line)
198
+ else:
199
+ if current_section['items']:
200
+ current_section['items'][-1] += " " + line.strip()
201
+ else:
202
+ current_section['items'].append(line)
203
+ return sections
204
+
205
+ def display_section_items(items):
206
+ """
207
+ Display list of items as links.
208
+ For each item, clean the text and generate search links using your original link set.
209
+ If a MoE system prompt is selected (non-blank), prepend it—with three spaces—before the cleaned text.
210
+ """
211
+ # Retrieve the current selected MoE prompt (if any)
212
+ moe_prefix = st.session_state.get("selected_moe", "")
213
+ search_urls = {
214
+ "📚📖ArXiv": lambda k: f"/?q={quote(k)}",
215
+ "🔮<sup>Google</sup>": lambda k: f"https://www.google.com/search?q={quote(k)}",
216
+ "📺<sup>Youtube</sup>": lambda k: f"https://www.youtube.com/results?search_query={quote(k)}",
217
+ "🔭<sup>Bing</sup>": lambda k: f"https://www.bing.com/search?q={quote(k)}",
218
+ "💡<sup>Claude</sup>": lambda k: f"https://claude.ai/new?q={quote(k)}",
219
+ "📱X": lambda k: f"https://twitter.com/search?q={quote(k)}",
220
+ "🤖<sup>GPT</sup>": lambda k: f"https://chatgpt.com/?model=o3-mini-high&q={quote(k)}",
221
+ }
222
+ for item in items:
223
+ cleaned_text = clean_item_text(item)
224
+ # If a MoE prompt is selected (non-blank), prepend it (with three spaces) to the cleaned text.
225
+ final_query = (moe_prefix + " " if moe_prefix else "") + cleaned_text
226
+ links_md = ' '.join([f"[{emoji}]({url(final_query)})" for emoji, url in search_urls.items()])
227
+ st.markdown(f"- **{cleaned_text}** {links_md}", unsafe_allow_html=True)
228
+
229
+ def display_markdown_tree():
230
+ """
231
+ Allow user to upload a .md file or load README.md.
232
+ Parse the markdown into sections and display each section in a collapsed expander
233
+ with the original markdown and a link tree of items.
234
+ """
235
+ st.markdown("## Markdown Tree Parser")
236
+ uploaded_file = st.file_uploader("Upload a Markdown file", type=["md"])
237
+ if uploaded_file is not None:
238
+ md_content = uploaded_file.read().decode("utf-8")
239
+ else:
240
+ if os.path.exists("README.md"):
241
+ with open("README.md", "r", encoding="utf-8") as f:
242
+ md_content = f.read()
243
+ else:
244
+ st.info("No Markdown file uploaded and README.md not found.")
245
+ return
246
+
247
+ sections = parse_markdown_sections(md_content)
248
+ if not sections:
249
+ st.info("No sections found in the markdown file.")
250
+ return
251
+
252
+ for sec in sections:
253
+ with st.expander(sec['header'], expanded=False):
254
+ st.markdown(f"**Original Markdown:**\n\n{sec['raw']}\n")
255
+ if sec['items']:
256
+ st.markdown("**Link Tree:**")
257
+ display_section_items(sec['items'])
258
+ else:
259
+ st.write("No items found in this section.")
260
+
261
+ # --- Existing AI and File Management Functions ---
262
+
263
+ def search_arxiv(query):
264
+ st.write("Performing AI Lookup...")
265
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
266
+ result1 = client.predict(
267
+ prompt=query,
268
+ llm_model_picked="mistralai/Mixtral-8x7B-Instruct-v0.1",
269
+ stream_outputs=True,
270
+ api_name="/ask_llm"
271
+ )
272
+ st.markdown("### Mixtral-8x7B-Instruct-v0.1 Result")
273
+ st.markdown(result1)
274
+ result2 = client.predict(
275
+ prompt=query,
276
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
277
+ stream_outputs=True,
278
+ api_name="/ask_llm"
279
+ )
280
+ st.markdown("### Mistral-7B-Instruct-v0.2 Result")
281
+ st.markdown(result2)
282
+ combined_result = f"{result1}\n\n{result2}"
283
+ return combined_result
284
+
285
+ @st.cache_resource
286
+ def SpeechSynthesis(result):
287
+ documentHTML5 = '''
288
+ <!DOCTYPE html>
289
+ <html>
290
+ <head>
291
+ <title>Read It Aloud</title>
292
+ <script type="text/javascript">
293
+ function readAloud() {
294
+ const text = document.getElementById("textArea").value;
295
+ const speech = new SpeechSynthesisUtterance(text);
296
+ window.speechSynthesis.speak(speech);
297
+ }
298
+ </script>
299
+ </head>
300
+ <body>
301
+ <h1>🔊 Read It Aloud</h1>
302
+ <textarea id="textArea" rows="10" cols="80">
303
+ '''
304
+ documentHTML5 += result
305
+ documentHTML5 += '''
306
+ </textarea>
307
+ <br>
308
+ <button onclick="readAloud()">🔊 Read Aloud</button>
309
+ </body>
310
+ </html>
311
+ '''
312
+ components.html(documentHTML5, width=1280, height=300)
313
+
314
+ def display_file_content(file_path):
315
+ """Display file content with editing capabilities."""
316
+ try:
317
+ with open(file_path, 'r', encoding='utf-8') as f:
318
+ content = f.read()
319
+ if st.session_state.view_mode == 'view':
320
+ st.markdown(content)
321
+ else:
322
+ edited_content = st.text_area(
323
+ "Edit content",
324
+ content,
325
+ height=400,
326
+ key=f"edit_{os.path.basename(file_path)}"
327
+ )
328
+ if st.button("Save Changes", key=f"save_{os.path.basename(file_path)}"):
329
+ try:
330
+ with open(file_path, 'w', encoding='utf-8') as f:
331
+ f.write(edited_content)
332
+ st.success(f"Successfully saved changes to {file_path}")
333
+ except Exception as e:
334
+ st.error(f"Error saving changes: {e}")
335
+ except Exception as e:
336
+ st.error(f"Error reading file: {e}")
337
+
338
+ def file_management_sidebar():
339
+ """Redesigned sidebar with improved layout and additional functionality."""
340
+ st.sidebar.title("📁 File Management")
341
+ md_files = [file for file in glob.glob("*.md") if file.lower() != 'readme.md']
342
+ md_files.sort()
343
+ st.session_state.files = md_files
344
+ if md_files:
345
+ st.sidebar.markdown("### Saved Files")
346
+ for idx, file in enumerate(md_files):
347
+ st.sidebar.markdown("---")
348
+ st.sidebar.text(get_time_display(file))
349
+ download_link = get_file_download_link(file)
350
+ if download_link:
351
+ st.sidebar.markdown(download_link, unsafe_allow_html=True)
352
+ col1, col2, col3, col4 = st.sidebar.columns(4)
353
+ with col1:
354
+ if st.button("📄View", key=f"view_{idx}"):
355
+ st.session_state.selected_file = file
356
+ st.session_state.view_mode = 'view'
357
+ with col2:
358
+ if st.button("✏️Edit", key=f"edit_{idx}"):
359
+ st.session_state.selected_file = file
360
+ st.session_state.view_mode = 'edit'
361
+ with col3:
362
+ if st.button("🔄Run", key=f"rerun_{idx}"):
363
+ try:
364
+ with open(file, 'r', encoding='utf-8') as f:
365
+ content = f.read()
366
+ rerun_prefix = """For the markdown below reduce the text to a humorous fun outline with emojis and markdown outline levels in outline that convey all the facts and adds wise quotes and funny statements to engage the reader:
367
+
368
+ """
369
+ full_prompt = rerun_prefix + content
370
+ ai_result = perform_ai_lookup(full_prompt)
371
+ saved_file = save_ai_interaction(content, ai_result, is_rerun=True)
372
+ if saved_file:
373
+ st.success(f"Created fun version in {saved_file}")
374
+ st.session_state.selected_file = saved_file
375
+ st.session_state.view_mode = 'view'
376
+ except Exception as e:
377
+ st.error(f"Error during rerun: {e}")
378
+ with col4:
379
+ if st.button("🗑️Delete", key=f"delete_{idx}"):
380
+ if delete_file(file):
381
+ st.success(f"Deleted {file}")
382
+ st.rerun()
383
+ else:
384
+ st.error(f"Failed to delete {file}")
385
+ st.sidebar.markdown("---")
386
+ if st.sidebar.button("📝 Create New Note"):
387
+ filename = generate_timestamp_filename("New Note")
388
+ with open(filename, 'w', encoding='utf-8') as f:
389
+ f.write("# New Markdown File\n")
390
+ st.sidebar.success(f"Created: {filename}")
391
+ st.session_state.selected_file = filename
392
+ st.session_state.view_mode = 'edit'
393
+ else:
394
+ st.sidebar.write("No markdown files found.")
395
+ if st.sidebar.button("📝 Create First Note"):
396
+ filename = generate_timestamp_filename("New Note")
397
+ with open(filename, 'w', encoding='utf-8') as f:
398
+ f.write("# New Markdown File\n")
399
+ st.sidebar.success(f"Created: {filename}")
400
+ st.session_state.selected_file = filename
401
+ st.session_state.view_mode = 'edit'
402
+
403
+ def perform_ai_lookup(query):
404
+ start_time = time.strftime("%Y-%m-%d %H:%M:%S")
405
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
406
+ response1 = client.predict(
407
+ query,
408
+ 20,
409
+ "Semantic Search",
410
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
411
+ api_name="/update_with_rag_md"
412
+ )
413
+ Question = '### 🔎 ' + query + '\r\n'
414
+ References = response1[0]
415
+ ReferenceLinks = ""
416
+ results = ""
417
+ RunSecondQuery = True
418
+ if RunSecondQuery:
419
+ response2 = client.predict(
420
+ query,
421
+ "mistralai/Mixtral-8x7B-Instruct-v0.1",
422
+ True,
423
+ api_name="/ask_llm"
424
+ )
425
+ if len(response2) > 10:
426
+ Answer = response2
427
+ SpeechSynthesis(Answer)
428
+ results = Question + '\r\n' + Answer + '\r\n' + References + '\r\n' + ReferenceLinks
429
+ st.markdown(results)
430
+ st.write('🔍Run of Multi-Agent System Paper Summary Spec is Complete')
431
+ end_time = time.strftime("%Y-%m-%d %H:%M:%S")
432
+ start_timestamp = time.mktime(time.strptime(start_time, "%Y-%m-%d %H:%M:%S"))
433
+ end_timestamp = time.mktime(time.strptime(end_time, "%Y-%m-%d %H:%M:%S"))
434
+ elapsed_seconds = end_timestamp - start_timestamp
435
+ st.write(f"Start time: {start_time}")
436
+ st.write(f"Finish time: {end_time}")
437
+ st.write(f"Elapsed time: {elapsed_seconds:.2f} seconds")
438
+ filename = generate_filename(query, "md")
439
+ create_file(filename, query, results)
440
+ return results
441
+
442
+ def generate_filename(prompt, file_type):
443
+ central = pytz.timezone('US/Central')
444
+ safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
445
+ safe_prompt = re.sub(r'\W+', '_', prompt)[:90]
446
+ return f"{safe_date_time}_{safe_prompt}.{file_type}"
447
+
448
+ def create_file(filename, prompt, response):
449
+ with open(filename, 'w', encoding='utf-8') as file:
450
+ file.write(prompt + "\n\n" + response)
451
+
452
+ # --- Main Application ---
453
+
454
+ def main():
455
+ st.markdown("### AI Knowledge Tree Builder 🧠🌱 Cultivate Your AI Mindscape!")
456
+ query_params = st.query_params
457
+ query = query_params.get('q', '')
458
+ show_initial_content = True
459
+
460
+ if query:
461
+ show_initial_content = False
462
+ st.write(f"### Search query received: {query}")
463
+ try:
464
+ ai_result = perform_ai_lookup(query)
465
+ saved_file = save_ai_interaction(query, ai_result)
466
+ if saved_file:
467
+ st.success(f"Saved interaction to {saved_file}")
468
+ st.session_state.selected_file = saved_file
469
+ st.session_state.view_mode = 'view'
470
+ except Exception as e:
471
+ st.error(f"Error during AI lookup: {e}")
472
+
473
+ file_management_sidebar()
474
+
475
+ if st.session_state.selected_file:
476
+ show_initial_content = False
477
+ if os.path.exists(st.session_state.selected_file):
478
+ st.markdown(f"### Current File: {st.session_state.selected_file}")
479
+ display_file_content(st.session_state.selected_file)
480
+ else:
481
+ st.error("Selected file no longer exists.")
482
+ st.session_state.selected_file = None
483
+ st.rerun()
484
+
485
+ if show_initial_content:
486
+ display_markdown_tree()
487
+
488
+ if __name__ == "__main__":
489
+ main()