awacke1 commited on
Commit
f5c7e99
β€’
1 Parent(s): 4874569

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +761 -0
app.py ADDED
@@ -0,0 +1,761 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from azure.cosmos import CosmosClient, exceptions
3
+ import os
4
+ import pandas as pd
5
+ import traceback
6
+ import shutil
7
+ from github import Github
8
+ from git import Repo
9
+ from datetime import datetime
10
+ import base64
11
+ import json
12
+ import uuid # 🎲 For generating unique IDs
13
+ from urllib.parse import quote # πŸ”— For encoding URLs
14
+ from gradio_client import Client # 🌐 For connecting to Gradio apps
15
+
16
+ # πŸŽ‰ Welcome to our fun-filled Cosmos DB and GitHub Integration app!
17
+ st.set_page_config(layout="wide")
18
+
19
+ # 🌌 Cosmos DB configuration
20
+ ENDPOINT = "https://acae-afd.documents.azure.com:443/"
21
+ DATABASE_NAME = os.environ.get("COSMOS_DATABASE_NAME")
22
+ CONTAINER_NAME = os.environ.get("COSMOS_CONTAINER_NAME")
23
+ Key = os.environ.get("Key") # πŸ”‘ Don't forget your key!
24
+
25
+ # 🏠 Your local app URL (Change this to your app's URL)
26
+ LOCAL_APP_URL = "https://huggingface.co/spaces/awacke1/AzureCosmosDBUI"
27
+
28
+ # πŸ€– OpenAI configuration
29
+ # openai.api_key = os.environ.get("OPENAI_API_KEY")
30
+ # MODEL = "gpt-3.5-turbo" # Replace with your desired model
31
+
32
+ # πŸ™ GitHub configuration
33
+ def download_github_repo(url, local_path):
34
+ # 🚚 Let's download that GitHub repo!
35
+ if os.path.exists(local_path):
36
+ shutil.rmtree(local_path)
37
+ Repo.clone_from(url, local_path)
38
+
39
+ def create_zip_file(source_dir, output_filename):
40
+ # πŸ“¦ Zipping up files like a pro!
41
+ shutil.make_archive(output_filename, 'zip', source_dir)
42
+
43
+ def create_repo(g, repo_name):
44
+ # πŸ› οΈ Creating a new GitHub repo. Magic!
45
+ user = g.get_user()
46
+ return user.create_repo(repo_name)
47
+
48
+ def push_to_github(local_path, repo, github_token):
49
+ # πŸš€ Pushing code to GitHub. Hold on tight!
50
+ repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
51
+ local_repo = Repo(local_path)
52
+
53
+ if 'origin' in [remote.name for remote in local_repo.remotes]:
54
+ origin = local_repo.remote('origin')
55
+ origin.set_url(repo_url)
56
+ else:
57
+ origin = local_repo.create_remote('origin', repo_url)
58
+
59
+ if not local_repo.heads:
60
+ local_repo.git.checkout('-b', 'main')
61
+ current_branch = 'main'
62
+ else:
63
+ current_branch = local_repo.active_branch.name
64
+
65
+ local_repo.git.add(A=True)
66
+
67
+ if local_repo.is_dirty():
68
+ local_repo.git.commit('-m', 'Initial commit')
69
+
70
+ origin.push(refspec=f'{current_branch}:{current_branch}')
71
+
72
+ def get_base64_download_link(file_path, file_name):
73
+ # πŸ§™β€β™‚οΈ Generating a magical download link!
74
+ with open(file_path, "rb") as file:
75
+ contents = file.read()
76
+ base64_encoded = base64.b64encode(contents).decode()
77
+ return f'<a href="data:application/zip;base64,{base64_encoded}" download="{file_name}">⬇️ Download {file_name}</a>'
78
+
79
+
80
+ # 🧭 New functions for dynamic sidebar navigation
81
+ def get_databases(client):
82
+ # πŸ“š Fetching list of databases. So many options!
83
+ return [db['id'] for db in client.list_databases()]
84
+
85
+ def get_containers(database):
86
+ # πŸ“‚ Getting containers. Containers within containers!
87
+ return [container['id'] for container in database.list_containers()]
88
+
89
+ def get_documents(container, limit=None):
90
+ # πŸ“ Retrieving documents. Shhh, don't tell anyone!
91
+ query = "SELECT * FROM c ORDER BY c._ts DESC"
92
+ items = list(container.query_items(query=query, enable_cross_partition_query=True, max_item_count=limit))
93
+ return items
94
+
95
+
96
+ # 🌟 Cosmos DB functions
97
+ def insert_record(container, record):
98
+ # πŸ“₯ Inserting a record into the Cosmosβ€”hope we don't disturb any aliens! πŸ‘½
99
+ try:
100
+ container.create_item(body=record)
101
+ return True, "Record inserted successfully! πŸŽ‰"
102
+ except exceptions.CosmosHttpResponseError as e:
103
+ return False, f"HTTP error occurred: {str(e)} 🚨"
104
+ except Exception as e:
105
+ return False, f"An unexpected error occurred: {str(e)} 😱"
106
+
107
+ def update_record(container, updated_record):
108
+ # πŸ”„ Updating a recordβ€”giving it a cosmic makeover! ✨
109
+ try:
110
+ container.upsert_item(body=updated_record)
111
+ return True, f"Record with id {updated_record['id']} successfully updated. πŸ› οΈ"
112
+ except exceptions.CosmosHttpResponseError as e:
113
+ return False, f"HTTP error occurred: {str(e)} 🚨"
114
+ except Exception as e:
115
+ return False, f"An unexpected error occurred: {traceback.format_exc()} 😱"
116
+
117
+ def delete_record(container, name, id):
118
+ # πŸ—‘οΈ Deleting a recordβ€”sending it into the cosmic void! 🌌
119
+ try:
120
+ container.delete_item(item=id, partition_key=id)
121
+ return True, f"Successfully deleted record with name: {name} and id: {id} πŸ—‘οΈ"
122
+ except exceptions.CosmosResourceNotFoundError:
123
+ return False, f"Record with id {id} not found. It may have been already deleted. πŸ•΅οΈβ€β™‚οΈ"
124
+ except exceptions.CosmosHttpResponseError as e:
125
+ return False, f"HTTP error occurred: {str(e)} 🚨"
126
+ except Exception as e:
127
+ return False, f"An unexpected error occurred: {traceback.format_exc()} 😱"
128
+
129
+ # 🎲 Function to generate a unique UUID
130
+ def generate_unique_id():
131
+ # πŸ§™β€β™‚οΈ Generating a unique UUID!
132
+ return str(uuid.uuid4())
133
+
134
+ # πŸ“¦ Function to archive current container
135
+ def archive_current_container(database_name, container_name, client):
136
+ # πŸ“¦ Archiving the entire containerβ€”time to pack up the stars! 🌠
137
+ try:
138
+ base_dir = "./cosmos_archive_current_container"
139
+ if os.path.exists(base_dir):
140
+ shutil.rmtree(base_dir)
141
+ os.makedirs(base_dir)
142
+
143
+ db_client = client.get_database_client(database_name)
144
+ container_client = db_client.get_container_client(container_name)
145
+ items = list(container_client.read_all_items())
146
+
147
+ container_dir = os.path.join(base_dir, container_name)
148
+ os.makedirs(container_dir)
149
+
150
+ for item in items:
151
+ item_id = item.get('id', f"unknown_{datetime.now().strftime('%Y%m%d%H%M%S')}")
152
+ with open(os.path.join(container_dir, f"{item_id}.json"), 'w') as f:
153
+ json.dump(item, f, indent=2)
154
+
155
+ archive_name = f"{container_name}_archive_{datetime.now().strftime('%Y%m%d%H%M%S')}"
156
+ shutil.make_archive(archive_name, 'zip', base_dir)
157
+
158
+ return get_base64_download_link(f"{archive_name}.zip", f"{archive_name}.zip")
159
+ except Exception as e:
160
+ return f"An error occurred while archiving data: {str(e)} 😒"
161
+
162
+
163
+ # πŸ”— Helper to extract hyperlinks
164
+ def extract_hyperlinks(responses):
165
+ # πŸ”— Extracting hyperlinksβ€”connecting the dots across the universe! πŸ•ΈοΈ
166
+ hyperlinks = []
167
+ for response in responses:
168
+ parsed_response = json.loads(response)
169
+ links = [value for key, value in parsed_response.items() if isinstance(value, str) and value.startswith("http")]
170
+ hyperlinks.extend(links)
171
+ return hyperlinks
172
+
173
+ # πŸ“‹ Helper to format text with line numbers
174
+ def format_with_line_numbers(text):
175
+ # πŸ“‹ Formatting text with line numbersβ€”organizing the cosmos one line at a time! πŸ“
176
+ lines = text.splitlines()
177
+ formatted_text = '\n'.join(f"{i+1}: {line}" for i, line in enumerate(lines))
178
+ return formatted_text
179
+
180
+
181
+ def generate_unique_id():
182
+ return str(uuid.uuid4())
183
+
184
+ def get_databases(client):
185
+ return [db['id'] for db in client.list_databases()]
186
+
187
+ def get_containers(database):
188
+ return [container['id'] for container in database.list_containers()]
189
+
190
+ def get_documents(container, limit=None):
191
+ query = "SELECT * FROM c ORDER BY c._ts DESC"
192
+ items = list(container.query_items(query=query, enable_cross_partition_query=True, max_item_count=limit))
193
+ return items
194
+
195
+ def save_to_cosmos_db(container, query, response1, response2):
196
+ try:
197
+ if container:
198
+ record = {
199
+ "id": generate_unique_id(),
200
+ "query": query,
201
+ "response1": response1,
202
+ "response2": response2
203
+ }
204
+ try:
205
+ container.create_item(body=record)
206
+ st.success(f"Record saved successfully with ID: {record['id']}")
207
+ # Refresh the documents display
208
+ st.session_state.documents = get_documents(container)
209
+ except exceptions.CosmosHttpResponseError as e:
210
+ st.error(f"Error saving record to Cosmos DB: {e}")
211
+ else:
212
+ st.error("Cosmos DB container is not initialized.")
213
+ except Exception as e:
214
+ st.error(f"An unexpected error occurred: {str(e)}")
215
+
216
+ # Add dropdowns for model and database choices
217
+ def search_glossary(query):
218
+ st.markdown(f"### πŸ” Search Glossary for: `{query}`")
219
+
220
+ # Dropdown for model selection
221
+ model_options = ['mistralai/Mixtral-8x7B-Instruct-v0.1', 'mistralai/Mistral-7B-Instruct-v0.2', 'google/gemma-7b-it', 'None']
222
+ model_choice = st.selectbox('🧠 Select LLM Model', options=model_options, index=1)
223
+
224
+ # Dropdown for database selection
225
+ database_options = ['Semantic Search', 'Arxiv Search - Latest - (EXPERIMENTAL)']
226
+ database_choice = st.selectbox('πŸ“š Select Database', options=database_options, index=0)
227
+
228
+
229
+
230
+ # Run Button with Emoji
231
+ #if st.button("πŸš€ Run"):
232
+
233
+ # πŸ•΅οΈβ€β™‚οΈ Searching the glossary for: query
234
+ all_results = ""
235
+ st.markdown(f"- {query}")
236
+
237
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM
238
+ #database_choice Literal['Semantic Search', 'Arxiv Search - Latest - (EXPERIMENTAL)'] Default: "Semantic Search"
239
+ #llm_model_picked Literal['mistralai/Mixtral-8x7B-Instruct-v0.1', 'mistralai/Mistral-7B-Instruct-v0.2', 'google/gemma-7b-it', 'None'] Default: "mistralai/Mistral-7B-Instruct-v0.2"
240
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
241
+
242
+
243
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /ask_llm
244
+ result = client.predict(
245
+ prompt=query,
246
+ llm_model_picked="mistralai/Mixtral-8x7B-Instruct-v0.1",
247
+ stream_outputs=True,
248
+ api_name="/ask_llm"
249
+ )
250
+ st.markdown(result)
251
+ st.code(result, language="python", line_numbers=True)
252
+
253
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /ask_llm
254
+ result2 = client.predict(
255
+ prompt=query,
256
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
257
+ stream_outputs=True,
258
+ api_name="/ask_llm"
259
+ )
260
+ st.markdown(result2)
261
+ st.code(result2, language="python", line_numbers=True)
262
+
263
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /ask_llm
264
+ result3 = client.predict(
265
+ prompt=query,
266
+ llm_model_picked="google/gemma-7b-it",
267
+ stream_outputs=True,
268
+ api_name="/ask_llm"
269
+ )
270
+ st.markdown(result3)
271
+ st.code(result3, language="python", line_numbers=True)
272
+
273
+
274
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /update_with_rag_md
275
+ response2 = client.predict(
276
+ message=query, # str in 'parameter_13' Textbox component
277
+ llm_results_use=10,
278
+ database_choice="Semantic Search",
279
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
280
+ api_name="/update_with_rag_md"
281
+ ) # update_with_rag_md Returns tuple of 2 elements [0] str The output value that appears in the "value_14" Markdown component. [1] str
282
+
283
+ st.markdown(response2[0])
284
+ st.code(response2[0], language="python", line_numbers=True, wrap_lines=True)
285
+
286
+ st.markdown(response2[1])
287
+ st.code(response2[1], language="python", line_numbers=True, wrap_lines=True)
288
+
289
+ # When saving results, pass the container
290
+ try:
291
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result, result)
292
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result2, result2)
293
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result3, result3)
294
+ save_to_cosmos_db(st.session_state.cosmos_container, query, response2[0], response2[0])
295
+ save_to_cosmos_db(st.session_state.cosmos_container, query, response2[1], response2[1])
296
+ except exceptions.CosmosHttpResponseError as e:
297
+ return False, f"HTTP error occurred: {str(e)} 🚨"
298
+ except Exception as e:
299
+ return False, f"An unexpected error occurred: {str(e)} 😱"
300
+
301
+
302
+ try:
303
+ # Aggregate hyperlinks and show with emojis
304
+ hyperlinks = extract_hyperlinks([response1, response2])
305
+ st.markdown("### πŸ”— Aggregated Hyperlinks")
306
+ for link in hyperlinks:
307
+ st.markdown(f"πŸ”— [{link}]({link})")
308
+
309
+ # Show responses in a code format with line numbers
310
+ st.markdown("### πŸ“œ Response Outputs with Line Numbers")
311
+ st.code(f"Response 1: \n{format_with_line_numbers(response1)}\n\nResponse 2: \n{format_with_line_numbers(response2)}", language="json")
312
+ except exceptions.CosmosHttpResponseError as e:
313
+ return False, f"HTTP error occurred: {str(e)} 🚨"
314
+ except Exception as e:
315
+ return False, f"An unexpected error occurred: {str(e)} 😱"
316
+
317
+
318
+
319
+
320
+ # 🎀 Function to process text input
321
+ def process_text(text_input):
322
+ # 🎀 Processing text inputβ€”translating human words into cosmic signals! πŸ“‘
323
+ if text_input:
324
+ if 'messages' not in st.session_state:
325
+ st.session_state.messages = []
326
+
327
+ st.session_state.messages.append({"role": "user", "content": text_input})
328
+
329
+ with st.chat_message("user"):
330
+ st.markdown(text_input)
331
+
332
+ with st.chat_message("assistant"):
333
+ search_glossary(text_input)
334
+
335
+ # πŸ“ Function to generate a filename
336
+ def generate_filename(text, file_type):
337
+ # πŸ“ Generate a filename based on the text input
338
+ safe_text = "".join(c if c.isalnum() or c in (' ', '.', '_') else '_' for c in text)
339
+ safe_text = "_".join(safe_text.strip().split())
340
+ filename = f"{safe_text}.{file_type}"
341
+ return filename
342
+
343
+ # πŸ•΅οΈβ€β™€οΈ Function to extract markdown title
344
+ def extract_markdown_title(content):
345
+ # πŸ•΅οΈβ€β™€οΈ Extracting markdown titleβ€”finding the headline in the cosmic news! πŸ“°
346
+ lines = content.splitlines()
347
+ for line in lines:
348
+ if line.startswith('#'):
349
+ return line.lstrip('#').strip()
350
+ return None
351
+
352
+ # πŸ’Ύ Function to create and save a file
353
+ def create_and_save_file(content, file_type="md", prompt=None, is_image=False, should_save=True):
354
+ # πŸ’Ύ Creating and saving a fileβ€”capturing cosmic wisdom! πŸ“
355
+ if not should_save:
356
+ return None
357
+
358
+ # Step 1: Generate filename based on the prompt or content
359
+ filename = generate_filename(prompt if prompt else content, file_type)
360
+
361
+ # Step 2: If it's a markdown file, check if it has a title
362
+ if file_type == "md":
363
+ title_from_content = extract_markdown_title(content)
364
+ if title_from_content:
365
+ filename = generate_filename(title_from_content, file_type)
366
+
367
+ # Step 3: Save the file
368
+ with open(filename, "w", encoding="utf-8") as f:
369
+ if is_image:
370
+ f.write(content)
371
+ else:
372
+ f.write(prompt + "\n\n" + content)
373
+
374
+ return filename
375
+
376
+ # πŸ€– Function to insert an auto-generated record
377
+ def insert_auto_generated_record(container):
378
+ # πŸ€– Automatically generating a record and inserting it into Cosmos DB!
379
+ try:
380
+ # Generate a unique id
381
+ new_id = generate_unique_id()
382
+ # Create a sample JSON document
383
+ new_doc = {
384
+ 'id': new_id,
385
+ 'name': f'Sample Name {new_id[:8]}',
386
+ 'description': 'This is a sample auto-generated description.',
387
+ 'timestamp': datetime.utcnow().isoformat()
388
+ }
389
+ # Insert the document
390
+ container.create_item(body=new_doc)
391
+ return True, f"Record inserted successfully with id: {new_id} πŸŽ‰"
392
+ except exceptions.CosmosHttpResponseError as e:
393
+ return False, f"HTTP error occurred: {str(e)} 🚨"
394
+ except Exception as e:
395
+ return False, f"An unexpected error occurred: {str(e)} 😱"
396
+
397
+ # 🎈 Main function
398
+ def main():
399
+ # 🎈 Let's modify the main app to be more fun!
400
+ st.title("πŸ™Git🌌CosmosπŸ’« - Azure Cosmos DB and Github Agent")
401
+
402
+ # 🚦 Initialize session state
403
+ if 'logged_in' not in st.session_state:
404
+ st.session_state.logged_in = False
405
+ if 'selected_records' not in st.session_state:
406
+ st.session_state.selected_records = []
407
+ if 'client' not in st.session_state:
408
+ st.session_state.client = None
409
+ if 'selected_database' not in st.session_state:
410
+ st.session_state.selected_database = None
411
+ if 'selected_container' not in st.session_state:
412
+ st.session_state.selected_container = None
413
+ if 'selected_document_id' not in st.session_state:
414
+ st.session_state.selected_document_id = None
415
+ if 'current_index' not in st.session_state:
416
+ st.session_state.current_index = 0
417
+ if 'cloned_doc' not in st.session_state:
418
+ st.session_state.cloned_doc = None
419
+
420
+ # βš™οΈ q= Run ArXiv search from query parameters
421
+ try:
422
+ query_params = st.query_params
423
+ query = query_params.get('q') or query_params.get('query') or ''
424
+ if query:
425
+ # πŸ•΅οΈβ€β™‚οΈ We have a query! Let's process it!
426
+ process_text(query)
427
+ st.stop() # Stop further execution
428
+ except Exception as e:
429
+ st.markdown(' ')
430
+
431
+ # πŸ” Automatic Login
432
+ if Key:
433
+ st.session_state.primary_key = Key
434
+ st.session_state.logged_in = True
435
+ else:
436
+ st.error("Cosmos DB Key is not set in environment variables. πŸ”‘βŒ")
437
+ return # Can't proceed without a key
438
+
439
+ if st.session_state.logged_in:
440
+ # 🌌 Initialize Cosmos DB client
441
+ try:
442
+ if st.session_state.client is None:
443
+ st.session_state.client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
444
+
445
+ # πŸ—„οΈ Sidebar for database, container, and document selection
446
+ st.sidebar.title("πŸ™Git🌌CosmosπŸ’«πŸ—„οΈNavigator")
447
+
448
+ databases = get_databases(st.session_state.client)
449
+ selected_db = st.sidebar.selectbox("πŸ—ƒοΈ Select Database", databases)
450
+
451
+ if selected_db != st.session_state.selected_database:
452
+ st.session_state.selected_database = selected_db
453
+ st.session_state.selected_container = None
454
+ st.session_state.selected_document_id = None
455
+ st.session_state.current_index = 0
456
+ st.rerun()
457
+
458
+ if st.session_state.selected_database:
459
+ database = st.session_state.client.get_database_client(st.session_state.selected_database)
460
+ containers = get_containers(database)
461
+ selected_container = st.sidebar.selectbox("πŸ“ Select Container", containers)
462
+
463
+ if selected_container != st.session_state.selected_container:
464
+ st.session_state.selected_container = selected_container
465
+ st.session_state.selected_document_id = None
466
+ st.session_state.current_index = 0
467
+ st.rerun()
468
+
469
+ if st.session_state.selected_container:
470
+ container = database.get_container_client(st.session_state.selected_container)
471
+
472
+ # πŸ“¦ Add Export button
473
+ if st.button("πŸ“¦ Export Container Data"):
474
+ download_link = archive_current_container(st.session_state.selected_database, st.session_state.selected_container, st.session_state.client)
475
+ if download_link.startswith('<a'):
476
+ st.markdown(download_link, unsafe_allow_html=True)
477
+ else:
478
+ st.error(download_link)
479
+
480
+ # Fetch documents
481
+ documents = get_documents(container)
482
+ total_docs = len(documents)
483
+
484
+ if total_docs > 5:
485
+ documents_to_display = documents[:5]
486
+ st.info("Showing top 5 most recent documents.")
487
+ else:
488
+ documents_to_display = documents
489
+ st.info(f"Showing all {len(documents_to_display)} documents.")
490
+
491
+ if documents_to_display:
492
+ # 🎨 Add Viewer/Editor selection
493
+ view_options = ['Show as Markdown', 'Show as Code Editor', 'Show as Edit and Save', 'Clone Document', 'New Record']
494
+ selected_view = st.selectbox("Select Viewer/Editor", view_options, index=2)
495
+
496
+ if selected_view == 'Show as Markdown':
497
+ # πŸ–ŒοΈ Show each record as Markdown with navigation
498
+ total_docs = len(documents)
499
+ doc = documents[st.session_state.current_index]
500
+ st.markdown(f"#### Document ID: {doc.get('id', '')}")
501
+
502
+ # πŸ•΅οΈβ€β™‚οΈ Let's extract values from the JSON that have at least one space
503
+ values_with_space = []
504
+ def extract_values(obj):
505
+ if isinstance(obj, dict):
506
+ for k, v in obj.items():
507
+ extract_values(v)
508
+ elif isinstance(obj, list):
509
+ for item in obj:
510
+ extract_values(item)
511
+ elif isinstance(obj, str):
512
+ if ' ' in obj:
513
+ values_with_space.append(obj)
514
+
515
+ extract_values(doc)
516
+
517
+ # πŸ”— Let's create a list of links for these values
518
+ search_urls = {
519
+ "πŸš€πŸŒŒArXiv": lambda k: f"{LOCAL_APP_URL}/?q={quote(k)}",
520
+ "πŸƒAnalyst": lambda k: f"{LOCAL_APP_URL}/?q={quote(k)}-{quote('PromptPrefix')}",
521
+ "πŸ“šPyCoder": lambda k: f"{LOCAL_APP_URL}/?q={quote(k)}-{quote('PromptPrefix2')}",
522
+ "πŸ”¬JSCoder": lambda k: f"{LOCAL_APP_URL}/?q={quote(k)}-{quote('PromptPrefix3')}",
523
+ "🏠": lambda k: f"{LOCAL_APP_URL}/?q={quote(k)}",
524
+ "πŸ“–": lambda k: f"https://en.wikipedia.org/wiki/{quote(k)}",
525
+ "πŸ”": lambda k: f"https://www.google.com/search?q={quote(k)}",
526
+ "▢️": lambda k: f"https://www.youtube.com/results?search_query={quote(k)}",
527
+ "πŸ”Ž": lambda k: f"https://www.bing.com/search?q={quote(k)}",
528
+ "πŸŽ₯": lambda k: f"https://www.youtube.com/results?search_query={quote(k)}",
529
+ "🐦": lambda k: f"https://twitter.com/search?q={quote(k)}",
530
+ }
531
+
532
+ st.markdown("#### πŸ”— Links for Extracted Texts")
533
+ for term in values_with_space:
534
+ links_md = ' '.join([f"[{emoji}]({url(term)})" for emoji, url in search_urls.items()])
535
+ st.markdown(f"**{term}** <small>{links_md}</small>", unsafe_allow_html=True)
536
+
537
+ # Show the document content as markdown
538
+ content = json.dumps(doc, indent=2)
539
+ st.markdown(f"```json\n{content}\n```")
540
+
541
+ # Navigation buttons
542
+ col_prev, col_next = st.columns([1, 1])
543
+ with col_prev:
544
+ if st.button("⬅️ Previous", key='prev_markdown'):
545
+ if st.session_state.current_index > 0:
546
+ st.session_state.current_index -= 1
547
+ st.rerun()
548
+ with col_next:
549
+ if st.button("➑️ Next", key='next_markdown'):
550
+ if st.session_state.current_index < total_docs - 1:
551
+ st.session_state.current_index += 1
552
+ st.rerun()
553
+
554
+ elif selected_view == 'Show as Code Editor':
555
+ # πŸ’» Show each record in a code editor with navigation
556
+ total_docs = len(documents)
557
+ doc = documents[st.session_state.current_index]
558
+ st.markdown(f"#### Document ID: {doc.get('id', '')}")
559
+ doc_str = st.text_area("Edit Document", value=json.dumps(doc, indent=2), height=300, key=f'code_editor_{st.session_state.current_index}')
560
+ col_prev, col_next = st.columns([1, 1])
561
+ with col_prev:
562
+ if st.button("⬅️ Previous", key='prev_code'):
563
+ if st.session_state.current_index > 0:
564
+ st.session_state.current_index -= 1
565
+ st.rerun()
566
+ with col_next:
567
+ if st.button("➑️ Next", key='next_code'):
568
+ if st.session_state.current_index < total_docs - 1:
569
+ st.session_state.current_index += 1
570
+ st.rerun()
571
+ if st.button("πŸ’Ύ Save Changes", key=f'save_button_{st.session_state.current_index}'):
572
+ try:
573
+ updated_doc = json.loads(doc_str)
574
+ success, message = update_record(container, updated_doc)
575
+ if success:
576
+ st.success(f"Document {updated_doc['id']} saved successfully.")
577
+ st.session_state.selected_document_id = updated_doc['id']
578
+ st.rerun()
579
+ else:
580
+ st.error(message)
581
+ except json.JSONDecodeError as e:
582
+ st.error(f"Invalid JSON: {str(e)} 🚫")
583
+
584
+ elif selected_view == 'Show as Edit and Save':
585
+ # ✏️ Show as Edit and Save in columns
586
+ st.markdown("#### Edit the document fields below:")
587
+
588
+ # Create columns for each document
589
+ num_cols = len(documents_to_display)
590
+ cols = st.columns(num_cols)
591
+
592
+
593
+ for idx, (col, doc) in enumerate(zip(cols, documents_to_display)):
594
+ with col:
595
+ st.markdown(f"##### Document ID: {doc.get('id', '')}")
596
+ editable_id = st.text_input("ID", value=doc.get('id', ''), key=f'edit_id_{idx}')
597
+ # Remove 'id' from the document for editing other fields
598
+ editable_doc = doc.copy()
599
+ editable_doc.pop('id', None)
600
+ doc_str = st.text_area("Document Content (in JSON format)", value=json.dumps(editable_doc, indent=2), height=300, key=f'doc_str_{idx}')
601
+
602
+ # Add the "Run With AI" button next to "Save Changes"
603
+ col_save, col_ai = st.columns(2)
604
+ with col_save:
605
+ if st.button("πŸ’Ύ Save Changes", key=f'save_button_{idx}'):
606
+ try:
607
+ updated_doc = json.loads(doc_str)
608
+ updated_doc['id'] = editable_id # Include the possibly edited ID
609
+ success, message = update_record(container, updated_doc)
610
+ if success:
611
+ st.success(f"Document {updated_doc['id']} saved successfully.")
612
+ st.session_state.selected_document_id = updated_doc['id']
613
+ st.rerun()
614
+ else:
615
+ st.error(message)
616
+ except json.JSONDecodeError as e:
617
+ st.error(f"Invalid JSON: {str(e)} 🚫")
618
+ with col_ai:
619
+ if st.button("πŸ€– Run With AI", key=f'run_with_ai_button_{idx}'):
620
+ # Use the entire document as input
621
+ search_glossary(json.dumps(editable_doc, indent=2))
622
+
623
+
624
+
625
+
626
+
627
+ elif selected_view == 'Clone Document':
628
+ # 🧬 Clone Document per record
629
+ st.markdown("#### Clone a document:")
630
+ for idx, doc in enumerate(documents_to_display):
631
+ st.markdown(f"##### Document ID: {doc.get('id', '')}")
632
+ if st.button("πŸ“„ Clone Document", key=f'clone_button_{idx}'):
633
+ cloned_doc = doc.copy()
634
+ # Generate a unique ID
635
+ cloned_doc['id'] = generate_unique_id()
636
+ st.session_state.cloned_doc = cloned_doc
637
+ st.session_state.cloned_doc_str = json.dumps(cloned_doc, indent=2)
638
+ st.session_state.clone_mode = True
639
+ st.rerun()
640
+ if st.session_state.get('clone_mode', False):
641
+ st.markdown("#### Edit Cloned Document:")
642
+ cloned_doc_str = st.text_area("Cloned Document Content (in JSON format)", value=st.session_state.cloned_doc_str, height=300)
643
+ if st.button("πŸ’Ύ Save Cloned Document"):
644
+ try:
645
+ new_doc = json.loads(cloned_doc_str)
646
+ success, message = insert_record(container, new_doc)
647
+ if success:
648
+ st.success(f"Cloned document saved with id: {new_doc['id']} πŸŽ‰")
649
+ st.session_state.selected_document_id = new_doc['id']
650
+ st.session_state.clone_mode = False
651
+ st.session_state.cloned_doc = None
652
+ st.session_state.cloned_doc_str = ''
653
+ st.rerun()
654
+ else:
655
+ st.error(message)
656
+ except json.JSONDecodeError as e:
657
+ st.error(f"Invalid JSON: {str(e)} 🚫")
658
+
659
+ elif selected_view == 'New Record':
660
+ # πŸ†• New Record
661
+ st.markdown("#### Create a new document:")
662
+ if st.button("πŸ€– Insert Auto-Generated Record"):
663
+ success, message = insert_auto_generated_record(container)
664
+ if success:
665
+ st.success(message)
666
+ st.rerun()
667
+ else:
668
+ st.error(message)
669
+ else:
670
+ new_id = st.text_input("ID", value=generate_unique_id(), key='new_id')
671
+ new_doc_str = st.text_area("Document Content (in JSON format)", value='{}', height=300)
672
+ if st.button("βž• Create New Document"):
673
+ try:
674
+ new_doc = json.loads(new_doc_str)
675
+ new_doc['id'] = new_id # Use the provided ID
676
+ success, message = insert_record(container, new_doc)
677
+ if success:
678
+ st.success(f"New document created with id: {new_doc['id']} πŸŽ‰")
679
+ st.session_state.selected_document_id = new_doc['id']
680
+ # Switch to 'Show as Edit and Save' mode
681
+ st.rerun()
682
+ else:
683
+ st.error(message)
684
+ except json.JSONDecodeError as e:
685
+ st.error(f"Invalid JSON: {str(e)} 🚫")
686
+
687
+ else:
688
+ st.sidebar.info("No documents found in this container. πŸ“­")
689
+
690
+ # πŸŽ‰ Main content area
691
+ st.subheader(f"πŸ“Š Container: {st.session_state.selected_container}")
692
+ if st.session_state.selected_container:
693
+ if documents_to_display:
694
+ df = pd.DataFrame(documents_to_display)
695
+ st.dataframe(df)
696
+ else:
697
+ st.info("No documents to display. 🧐")
698
+
699
+ # πŸ™ GitHub section
700
+ st.subheader("πŸ™ GitHub Operations")
701
+ github_token = os.environ.get("GITHUB") # Read GitHub token from environment variable
702
+ source_repo = st.text_input("Source GitHub Repository URL", value="https://github.com/AaronCWacker/AIExamples-8-24-Streamlit")
703
+ new_repo_name = st.text_input("New Repository Name (for cloning)", value=f"AIExample-Clone-{datetime.now().strftime('%Y%m%d_%H%M%S')}")
704
+
705
+ col1, col2 = st.columns(2)
706
+ with col1:
707
+ if st.button("πŸ“₯ Clone Repository"):
708
+ if github_token and source_repo:
709
+ try:
710
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d%H%M%S')}"
711
+ download_github_repo(source_repo, local_path)
712
+ zip_filename = f"{new_repo_name}.zip"
713
+ create_zip_file(local_path, zip_filename[:-4])
714
+ st.markdown(get_base64_download_link(zip_filename, zip_filename), unsafe_allow_html=True)
715
+ st.success("Repository cloned successfully! πŸŽ‰")
716
+ except Exception as e:
717
+ st.error(f"An error occurred: {str(e)} 😒")
718
+ finally:
719
+ if os.path.exists(local_path):
720
+ shutil.rmtree(local_path)
721
+ if os.path.exists(zip_filename):
722
+ os.remove(zip_filename)
723
+ else:
724
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided. πŸ”‘β“")
725
+
726
+ with col2:
727
+ if st.button("πŸ“€ Push to New Repository"):
728
+ if github_token and source_repo:
729
+ try:
730
+ g = Github(github_token)
731
+ new_repo = create_repo(g, new_repo_name)
732
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d%H%M%S')}"
733
+ download_github_repo(source_repo, local_path)
734
+ push_to_github(local_path, new_repo, github_token)
735
+ st.success(f"Repository pushed successfully to {new_repo.html_url} πŸš€")
736
+ except Exception as e:
737
+ st.error(f"An error occurred: {str(e)} 😒")
738
+ finally:
739
+ if os.path.exists(local_path):
740
+ shutil.rmtree(local_path)
741
+ else:
742
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided. πŸ”‘β“")
743
+
744
+ except exceptions.CosmosHttpResponseError as e:
745
+ st.error(f"Failed to connect to Cosmos DB. HTTP error: {str(e)} 🚨")
746
+ except Exception as e:
747
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
748
+
749
+ # πŸšͺ Logout button
750
+ if st.session_state.logged_in and st.sidebar.button("πŸšͺ Logout"):
751
+ st.session_state.logged_in = False
752
+ st.session_state.selected_records.clear()
753
+ st.session_state.client = None
754
+ st.session_state.selected_database = None
755
+ st.session_state.selected_container = None
756
+ st.session_state.selected_document_id = None
757
+ st.session_state.current_index = 0
758
+ st.rerun()
759
+
760
+ if __name__ == "__main__":
761
+ main()