awacke1 commited on
Commit
035d4dc
β€’
1 Parent(s): 5984e6e

Create backup13.app.py

Browse files
Files changed (1) hide show
  1. backup13.app.py +1417 -0
backup13.app.py ADDED
@@ -0,0 +1,1417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Import libraries and references:
2
+ import anthropic
3
+ import base64
4
+ import glob
5
+ import hashlib
6
+ import json
7
+ import os
8
+ import pandas as pd
9
+ import pytz
10
+ import random
11
+ import re
12
+ import shutil
13
+ import streamlit as st
14
+ import time
15
+ import traceback
16
+ import uuid
17
+ import zipfile
18
+ from PIL import Image
19
+ from azure.cosmos import CosmosClient, exceptions
20
+ from datetime import datetime
21
+ from git import Repo
22
+ from github import Github
23
+ from gradio_client import Client
24
+ from urllib.parse import quote
25
+
26
+
27
+ # 🎭 App Configuration - Because every app needs a good costume!
28
+ Site_Name = 'πŸ™GitCosmos🌌 - AI Azure Cosmos DB and Github Agent'
29
+ title = "πŸ™GitCosmos🌌 - AI Azure Cosmos DB and Github Agent"
30
+ helpURL = 'https://huggingface.co/awacke1'
31
+ bugURL = 'https://huggingface.co/spaces/awacke1/AzureCosmosDBUI/'
32
+ icons = 'πŸ™πŸŒŒπŸ’«'
33
+ st.set_page_config(
34
+ page_title=title,
35
+ page_icon=icons,
36
+ layout="wide",
37
+ initial_sidebar_state="auto",
38
+ menu_items={
39
+ 'Get Help': helpURL,
40
+ 'Report a bug': bugURL,
41
+ 'About': title
42
+ }
43
+ )
44
+
45
+
46
+ # 🌌 Cosmos DB configuration - Where data goes to party!
47
+ ENDPOINT = "https://acae-afd.documents.azure.com:443/"
48
+ DATABASE_NAME = os.environ.get("COSMOS_DATABASE_NAME")
49
+ CONTAINER_NAME = os.environ.get("COSMOS_CONTAINER_NAME")
50
+ Key = os.environ.get("Key")
51
+
52
+ # 🌐 Your local app URL - Home sweet home
53
+ LOCAL_APP_URL = "https://huggingface.co/spaces/awacke1/AzureCosmosDBUI"
54
+ CosmosDBUrl = 'https://portal.azure.com/#@AaronCWackergmail.onmicrosoft.com/resource/subscriptions/003fba60-5b3f-48f4-ab36-3ed11bc40816/resourceGroups/datasets/providers/Microsoft.DocumentDB/databaseAccounts/acae-afd/dataExplorer'
55
+
56
+ # πŸ€– Anthropic configuration - Teaching machines to be more human (and funnier)
57
+ anthropicclient = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
58
+
59
+ # 🧠 Initialize session state - Because even apps need a good memory
60
+ if "chat_history" not in st.session_state:
61
+ st.session_state.chat_history = []
62
+
63
+
64
+
65
+ # πŸ› οΈ Helper Functions - The unsung heroes of our code
66
+
67
+ # πŸ“Ž Get a file download link - Making file sharing as easy as stealing candy from a baby
68
+ def get_download_link(file_path):
69
+ with open(file_path, "rb") as file:
70
+ contents = file.read()
71
+ b64 = base64.b64encode(contents).decode()
72
+ file_name = os.path.basename(file_path)
73
+ return f'<a href="data:file/txt;base64,{b64}" download="{file_name}">Download {file_name}πŸ“‚</a>'
74
+
75
+ # 🎲 Generate a unique ID - Because being unique is important (just ask your mother)
76
+ def generate_unique_id():
77
+ timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
78
+ unique_uuid = str(uuid.uuid4())
79
+ returnValue = f"{timestamp}-{unique_uuid}"
80
+ st.write('New Unique ID:' + returnValue)
81
+ return
82
+
83
+ # πŸ“ Generate a filename - Naming files like a pro (or a very confused librarian)
84
+ def generate_filename(prompt, file_type):
85
+ central = pytz.timezone('US/Central')
86
+ safe_date_time = datetime.now(central).strftime("%m%d_%H%M")
87
+ safe_prompt = re.sub(r'\W+', '', prompt)[:90]
88
+ return f"{safe_date_time}{safe_prompt}.{file_type}"
89
+
90
+ # πŸ’Ύ Create and save a file - Because data hoarding is a legitimate hobby
91
+ def create_file(filename, prompt, response, should_save=True):
92
+ if not should_save:
93
+ return
94
+ with open(filename, 'w', encoding='utf-8') as file:
95
+ file.write(prompt + "\n\n" + response)
96
+
97
+ # πŸ“– Load file content - Bringing words back from the digital grave
98
+ def load_file(file_name):
99
+ with open(file_name, "r", encoding='utf-8') as file:
100
+ content = file.read()
101
+ return content
102
+
103
+ # πŸ” Display glossary entity - Making search fun again (as if it ever was)
104
+ def display_glossary_entity(k):
105
+ search_urls = {
106
+ "πŸš€πŸŒŒArXiv": lambda k: f"/?q={quote(k)}",
107
+ "πŸ“–": lambda k: f"https://en.wikipedia.org/wiki/{quote(k)}",
108
+ "πŸ”": lambda k: f"https://www.google.com/search?q={quote(k)}",
109
+ "πŸŽ₯": lambda k: f"https://www.youtube.com/results?search_query={quote(k)}",
110
+ }
111
+ links_md = ' '.join([f"<a href='{url(k)}' target='_blank'>{emoji}</a>" for emoji, url in search_urls.items()])
112
+ st.markdown(f"{k} {links_md}", unsafe_allow_html=True)
113
+
114
+ # πŸ—œοΈ Create zip of files - Squeezing files together like sardines in a can
115
+ def create_zip_of_files(files):
116
+ zip_name = "all_files.zip"
117
+ with zipfile.ZipFile(zip_name, 'w') as zipf:
118
+ for file in files:
119
+ zipf.write(file)
120
+ return zip_name
121
+
122
+ # 🎬 Get video HTML - Making videos play nice (or at least trying to)
123
+ def get_video_html(video_path, width="100%"):
124
+ video_url = f"data:video/mp4;base64,{base64.b64encode(open(video_path, 'rb').read()).decode()}"
125
+ return f'''
126
+ <video width="{width}" controls autoplay loop>
127
+ <source src="{video_url}" type="video/mp4">
128
+ Your browser does not support the video tag.
129
+ </video>
130
+ '''
131
+
132
+ # 🎡 Get audio HTML - Let the music play (and hope it's not Baby Shark)
133
+ def get_audio_html(audio_path, width="100%"):
134
+ audio_url = f"data:audio/mpeg;base64,{base64.b64encode(open(audio_path, 'rb').read()).decode()}"
135
+ return f'''
136
+ <audio controls style="width:{width}">
137
+ <source src="{audio_url}" type="audio/mpeg">
138
+ Your browser does not support the audio element.
139
+ </audio>
140
+ '''
141
+
142
+ # 🌌 Cosmos DB functions - Where data goes to live its best life
143
+
144
+ # πŸ“š Get databases - Collecting databases like Pokemon cards
145
+ def get_databases(client):
146
+ return [db['id'] for db in client.list_databases()]
147
+
148
+ # πŸ“¦ Get containers - Finding where all the good stuff is hidden
149
+ def get_containers(database):
150
+ return [container['id'] for container in database.list_containers()]
151
+
152
+ # πŸ“„ Get documents - Retrieving the sacred texts (or just some JSON)
153
+ def get_documents(container, limit=None):
154
+ query = "SELECT * FROM c ORDER BY c._ts DESC"
155
+ items = list(container.query_items(query=query, enable_cross_partition_query=True, max_item_count=limit))
156
+ return items
157
+
158
+ # πŸ“₯ Insert record - Adding new data (and crossing fingers it doesn't break anything)
159
+ def insert_record(container, record):
160
+ try:
161
+ container.create_item(body=record)
162
+ return True, "Record inserted successfully! πŸŽ‰"
163
+ except exceptions.CosmosHttpResponseError as e:
164
+ return False, f"HTTP error occurred: {str(e)} 🚨"
165
+ except Exception as e:
166
+ return False, f"An unexpected error occurred: {str(e)} 😱"
167
+
168
+ # πŸ”„ Update record - Giving data a makeover
169
+ def update_record(container, updated_record):
170
+ try:
171
+ container.upsert_item(body=updated_record)
172
+ return True, f"Record with id {updated_record['id']} successfully updated. πŸ› οΈ"
173
+ except exceptions.CosmosHttpResponseError as e:
174
+ return False, f"HTTP error occurred: {str(e)} 🚨"
175
+ except Exception as e:
176
+ return False, f"An unexpected error occurred: {traceback.format_exc()} 😱"
177
+
178
+ # πŸ—‘οΈ Delete record - Saying goodbye to data (it's not you, it's me)
179
+ def delete_record(container, record):
180
+ try:
181
+ container.delete_item(item=record['id'], partition_key=record['id'])
182
+ return True, f"Record with id {record['id']} successfully deleted. πŸ—‘οΈ"
183
+ except exceptions.CosmosHttpResponseError as e:
184
+ return False, f"HTTP error occurred: {str(e)} 🚨"
185
+ except Exception as e:
186
+ return False, f"An unexpected error occurred: {traceback.format_exc()} 😱"
187
+
188
+
189
+ # πŸ’Ύ Save to Cosmos DB - Preserving data for future generations (or just until the next update)
190
+ def save_to_cosmos_db(container, query, response1, response2):
191
+ try:
192
+ if container:
193
+ # Generate a unique ID that includes a timestamp
194
+ timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
195
+ unique_uuid = str(uuid.uuid4())
196
+ new_id = f"{timestamp}-{unique_uuid}"
197
+
198
+ # Create new document with proper name field
199
+ record = {
200
+ "id": new_id,
201
+ "name": new_id, # Set name equal to ID to avoid null name error
202
+ "query": query,
203
+ "response1": response1,
204
+ "response2": response2,
205
+ "timestamp": datetime.utcnow().isoformat(),
206
+ "type": "ai_response", # Add document type for better organization
207
+ "version": "1.0"
208
+ }
209
+
210
+ try:
211
+ # Create the new document
212
+ container.create_item(body=record)
213
+ st.success(f"Record saved successfully with ID: {record['id']}")
214
+ # Refresh the documents display
215
+ st.session_state.documents = get_documents(container)
216
+ except exceptions.CosmosHttpResponseError as e:
217
+ st.error(f"Error saving record to Cosmos DB: {e}")
218
+ else:
219
+ st.error("Cosmos DB container is not initialized.")
220
+ except Exception as e:
221
+ st.error(f"An unexpected error occurred: {str(e)}")
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+ def save_to_cosmos_db_old(container, query, response1, response2):
231
+ try:
232
+ if container:
233
+ record = {
234
+ "id": generate_unique_id(),
235
+ "query": query,
236
+ "response1": response1,
237
+ "response2": response2,
238
+ "timestamp": datetime.utcnow().isoformat()
239
+ }
240
+ try:
241
+ container.create_item(body=record)
242
+ st.success(f"Record saved successfully with ID: {record['id']}")
243
+ # Refresh the documents display
244
+ st.session_state.documents = get_documents(container)
245
+ except exceptions.CosmosHttpResponseError as e:
246
+ st.error(f"Error saving record to Cosmos DB: {e}")
247
+ else:
248
+ st.error("Cosmos DB container is not initialized.")
249
+ except Exception as e:
250
+ st.error(f"An unexpected error occurred: {str(e)}")
251
+
252
+
253
+
254
+ # πŸ™ GitHub functions - Where code goes to socialize
255
+
256
+ # πŸ“₯ Download GitHub repo - Cloning repos like it's going out of style
257
+ def download_github_repo(url, local_path):
258
+ if os.path.exists(local_path):
259
+ shutil.rmtree(local_path)
260
+ Repo.clone_from(url, local_path)
261
+
262
+ # πŸ—œοΈ Create zip file - Squeezing files tighter than your budget
263
+ def create_zip_file(source_dir, output_filename):
264
+ shutil.make_archive(output_filename, 'zip', source_dir)
265
+
266
+ # πŸ—οΈ Create repo - Building digital homes for lonely code
267
+ def create_repo(g, repo_name):
268
+ user = g.get_user()
269
+ return user.create_repo(repo_name)
270
+
271
+ # πŸš€ Push to GitHub - Sending code to the cloud (hopefully not the rainy kind)
272
+ def push_to_github(local_path, repo, github_token):
273
+ repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
274
+ local_repo = Repo(local_path)
275
+ if 'origin' in [remote.name for remote in local_repo.remotes]:
276
+ origin = local_repo.remote('origin')
277
+ origin.set_url(repo_url)
278
+ else:
279
+ origin = local_repo.create_remote('origin', repo_url)
280
+ if not local_repo.heads:
281
+ local_repo.git.checkout('-b', 'main')
282
+ current_branch = 'main'
283
+ else:
284
+ current_branch = local_repo.active_branch.name
285
+ local_repo.git.add(A=True)
286
+ if local_repo.is_dirty():
287
+ local_repo.git.commit('-m', 'Initial commit')
288
+ origin.push(refspec=f'{current_branch}:{current_branch}')
289
+
290
+
291
+ def save_or_clone_to_cosmos_db(container, document=None, clone_id=None):
292
+ def generate_complex_unique_id():
293
+ timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
294
+ random_component = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=8))
295
+ return f"{timestamp}-{random_component}-{str(uuid.uuid4())}"
296
+ max_retries = 10
297
+ base_delay = 0.1
298
+ for attempt in range(max_retries):
299
+ try:
300
+ new_id = generate_complex_unique_id()
301
+ if clone_id:
302
+ try:
303
+ existing_doc = container.read_item(item=clone_id, partition_key=clone_id)
304
+ new_doc = {
305
+ 'id': new_id,
306
+ 'originalText': existing_doc.get('originalText', ''),
307
+ 'qtPrompts': existing_doc.get('qtPrompts', []),
308
+ 'cloned_from': clone_id,
309
+ 'cloned_at': datetime.utcnow().isoformat()
310
+ }
311
+ except exceptions.CosmosResourceNotFoundError:
312
+ return False, f"Document with ID {clone_id} not found for cloning."
313
+ else:
314
+ if document is None:
315
+ return False, "No document provided for saving"
316
+ document['id'] = new_id
317
+ document['created_at'] = datetime.utcnow().isoformat()
318
+ new_doc = document
319
+ response = container.create_item(body=new_doc)
320
+ return True, f"{'Cloned' if clone_id else 'New'} document saved successfully with ID: {response['id']}"
321
+ except exceptions.CosmosHttpResponseError as e:
322
+ if e.status_code == 409:
323
+ delay = base_delay * (2 ** attempt) + random.uniform(0, 0.1)
324
+ time.sleep(delay)
325
+ continue
326
+ return False, f"Error saving to Cosmos DB: {str(e)}"
327
+ except Exception as e:
328
+ return False, f"An unexpected error occurred: {str(e)}"
329
+ return False, "Failed to save document after maximum retries."
330
+
331
+
332
+ # πŸ“¦ Archive current container - Packing up data like you're moving to a new digital house
333
+ def archive_current_container(database_name, container_name, client):
334
+ try:
335
+ base_dir = "./cosmos_archive_current_container"
336
+ if os.path.exists(base_dir):
337
+ shutil.rmtree(base_dir)
338
+ os.makedirs(base_dir)
339
+ db_client = client.get_database_client(database_name)
340
+ container_client = db_client.get_container_client(container_name)
341
+ items = list(container_client.read_all_items())
342
+ container_dir = os.path.join(base_dir, container_name)
343
+ os.makedirs(container_dir)
344
+ for item in items:
345
+ item_id = item.get('id', f"unknown_{datetime.now().strftime('%Y%m%d%H%M%S')}")
346
+ with open(os.path.join(container_dir, f"{item_id}.json"), 'w') as f:
347
+ json.dump(item, f, indent=2)
348
+ archive_name = f"{container_name}_archive_{datetime.now().strftime('%Y%m%d%H%M%S')}"
349
+ shutil.make_archive(archive_name, 'zip', base_dir)
350
+ return get_download_link(f"{archive_name}.zip")
351
+ except Exception as e:
352
+ return f"An error occurred while archiving data: {str(e)} 😒"
353
+
354
+ def gen_AI_IO_filename(display_query, output):
355
+ # Get current time in Central Time Zone with milliseconds
356
+ now_central = datetime.now(pytz.timezone("America/Chicago"))
357
+ timestamp = now_central.strftime("%Y-%m-%d-%I-%M-%S-%f-%p")
358
+
359
+ # Limit components to prevent excessive filename length
360
+ display_query = display_query[:50] # Truncate display_query to 50 chars
361
+ output_snippet = re.sub(r'[^A-Za-z0-9]+', '_', output[:100]) # Truncate output_snippet to 100 chars
362
+
363
+ filename = f"{timestamp} - {display_query} - {output_snippet}.md"
364
+ return filename
365
+
366
+ # πŸ” Search glossary - Finding needles in digital haystacks
367
+ def search_glossary(query):
368
+ st.markdown(f"### πŸ” SearchGlossary for: {query}")
369
+ model_options = ['mistralai/Mixtral-8x7B-Instruct-v0.1', 'mistralai/Mistral-7B-Instruct-v0.2']
370
+ model_choice = st.selectbox('🧠 Select LLM Model', options=model_options, index=1, key=f"model_choice_{id(query)}")
371
+ database_options = ['Semantic Search', 'Arxiv Search - Latest - (EXPERIMENTAL)']
372
+ database_choice = st.selectbox('πŸ“š Select Database', options=database_options, index=0, key=f"database_choice_{id(query)}")
373
+
374
+ # πŸ•΅οΈβ€β™‚οΈ Searching the glossary for: query
375
+ all_results = ""
376
+ # Limit the query display to 80 characters
377
+ display_query = query[:80] + "..." if len(query) > 80 else query
378
+ st.markdown(f"πŸ•΅οΈβ€β™‚οΈ Running ArXiV AI Analysis with Query: {display_query} - ML model: {model_choice} and Option: {database_options}")
379
+
380
+ # πŸ” ArXiV RAG researcher expert ~-<>-~ Paper Summary & Ask LLM
381
+ client = Client("awacke1/Arxiv-Paper-Search-And-QA-RAG-Pattern")
382
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /ask_llm
383
+ result = client.predict(
384
+ prompt=query,
385
+ llm_model_picked="mistralai/Mixtral-8x7B-Instruct-v0.1",
386
+ stream_outputs=True,
387
+ api_name="/ask_llm"
388
+ )
389
+ st.markdown("# Mixtral-8x7B-Instruct-v0.1")
390
+ st.markdown(result)
391
+ #st.code(result, language="python", line_numbers=True)
392
+
393
+
394
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /ask_llm
395
+ result2 = client.predict(
396
+ prompt=query,
397
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
398
+ stream_outputs=True,
399
+ api_name="/ask_llm"
400
+ )
401
+ st.markdown("# Mistral-7B-Instruct-v0.2")
402
+ st.markdown(result2)
403
+ #st.code(result2, language="python", line_numbers=True)
404
+
405
+ # πŸ” ArXiv RAG researcher expert ~-<>-~ Paper Summary & Ask LLM - api_name: /update_with_rag_md
406
+ response2 = client.predict(
407
+ message=query, # str in 'parameter_13' Textbox component
408
+ llm_results_use=10,
409
+ database_choice="Semantic Search",
410
+ llm_model_picked="mistralai/Mistral-7B-Instruct-v0.2",
411
+ api_name="/update_with_rag_md"
412
+ )
413
+ st.markdown("# Mistral-7B-Instruct-v0.2 update_with_rag_md 0")
414
+ st.markdown(response2[0])
415
+ #st.code(response2[0], language="python", line_numbers=True, wrap_lines=True)
416
+
417
+ st.markdown("# Mistral-7B-Instruct-v0.2 update_with_rag_md 1")
418
+ st.markdown(response2[1])
419
+ #st.code(response2[1], language="python", line_numbers=True, wrap_lines=True)
420
+
421
+
422
+ # βœ… Persist AI Results to Markdown Files
423
+ filename = gen_AI_IO_filename(display_query, result)
424
+ create_file(filename, query, result)
425
+ st.markdown(f"βœ… File saved as: `{filename}`")
426
+
427
+ filename = gen_AI_IO_filename(display_query, result2)
428
+ create_file(filename, query, result2)
429
+ st.markdown(f"βœ… File saved as: `{filename}`")
430
+
431
+ filename = gen_AI_IO_filename(display_query, response2[0])
432
+ create_file(filename, query, response2[0])
433
+ st.markdown(f"βœ… File saved as: `{filename}`")
434
+
435
+ filename = gen_AI_IO_filename(display_query, response2[1])
436
+ create_file(filename, query, response2[1])
437
+ st.markdown(f"βœ… File saved as: `{filename}`")
438
+
439
+ return result, result2, response2
440
+
441
+
442
+ # πŸ“ Generate a safe filename from the first few lines of content
443
+ def generate_filename_from_content(content, file_type="md"):
444
+ # Extract the first few lines or sentences
445
+ first_sentence = content.split('\n', 1)[0][:90] # Limit the length to 90 characters
446
+ # Remove special characters to make it a valid filename
447
+ safe_name = re.sub(r'[^\w\s-]', '', first_sentence)
448
+ # Limit length to be compatible with Windows and Linux
449
+ safe_name = safe_name[:50].strip() # Adjust length limit
450
+ return f"{safe_name}.{file_type}"
451
+
452
+
453
+ # πŸ’Ύ Create and save a file
454
+ def create_file_from_content(content, should_save=True):
455
+ if not should_save:
456
+ return
457
+ filename = generate_filename_from_content(content)
458
+ with open(filename, 'w', encoding='utf-8') as file:
459
+ file.write(content)
460
+ return filename
461
+
462
+
463
+ # πŸ“‚ Display list of saved .md files in the sidebar
464
+ def display_saved_files_in_sidebar():
465
+ all_files = glob.glob("*.md")
466
+ all_files.sort(reverse=True)
467
+ all_files = [file for file in all_files if not file.lower().startswith('readme')] # Exclude README.md
468
+ st.sidebar.markdown("## πŸ“ Saved Markdown Files")
469
+ for file in all_files:
470
+ col1, col2, col3 = st.sidebar.columns([6, 2, 1])
471
+ with col1:
472
+ st.markdown(f"πŸ“„ {file}")
473
+ with col2:
474
+ st.sidebar.download_button(
475
+ label="⬇️ Download",
476
+ data=open(file, 'rb').read(),
477
+ file_name=file
478
+ )
479
+ with col3:
480
+ if st.sidebar.button("πŸ—‘", key=f"delete_{file}"):
481
+ os.remove(file)
482
+ st.rerun()
483
+
484
+ def clone_record(container, clone_id):
485
+ try:
486
+ existing_doc = container.read_item(item=clone_id, partition_key=clone_id)
487
+ new_doc = existing_doc.copy()
488
+ new_doc['id'] = generate_unique_id() # Generate new unique ID with timestamp
489
+ new_doc['name'] = new_doc['id'] # Generate new unique ID with timestamp
490
+ new_doc['createdAt'] = datetime.utcnow().isoformat() # Update the creation time
491
+ new_doc['_rid'] = None # Reset _rid or any system-managed fields
492
+ new_doc['_self'] = None
493
+ new_doc['_etag'] = None
494
+ new_doc['_attachments'] = None
495
+ new_doc['_ts'] = None # Reset timestamp to be updated by Cosmos DB automatically
496
+ # Insert the cloned document
497
+ response = container.create_item(body=new_doc)
498
+ st.success(f"Cloned document saved successfully with ID: {new_doc['id']} πŸŽ‰")
499
+ # Refresh the documents in session state
500
+ st.session_state.documents = list(container.query_items(
501
+ query="SELECT * FROM c ORDER BY c._ts DESC",
502
+ enable_cross_partition_query=True
503
+ ))
504
+ except exceptions.CosmosResourceNotFoundError:
505
+ st.error(f"Document with ID {clone_id} not found for cloning.")
506
+ except exceptions.CosmosHttpResponseError as e:
507
+ st.error(f"HTTP error occurred: {str(e)} 🚨")
508
+ except Exception as e:
509
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
510
+
511
+
512
+ def create_new_blank_record(container):
513
+ try:
514
+ # Get the structure of the latest document (to preserve schema)
515
+ latest_doc = container.query_items(query="SELECT * FROM c ORDER BY c._ts DESC", enable_cross_partition_query=True, max_item_count=1)
516
+ if latest_doc:
517
+ new_doc_structure = latest_doc[0].copy()
518
+ else:
519
+ new_doc_structure = {}
520
+ new_doc = {key: "" for key in new_doc_structure.keys()} # Set all fields to blank
521
+ new_doc['id'] = generate_unique_id() # Generate new unique ID
522
+ new_doc['createdAt'] = datetime.utcnow().isoformat() # Set creation time
523
+ # Insert the new blank document
524
+ response = container.create_item(body=new_doc)
525
+ st.success(f"New blank document saved successfully with ID: {new_doc['id']} πŸŽ‰")
526
+ # Refresh the documents in session state
527
+ st.session_state.documents = list(container.query_items(
528
+ query="SELECT * FROM c ORDER BY c._ts DESC",
529
+ enable_cross_partition_query=True
530
+ ))
531
+ except exceptions.CosmosHttpResponseError as e:
532
+ st.error(f"HTTP error occurred: {str(e)} 🚨")
533
+ except Exception as e:
534
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
535
+
536
+
537
+ # Function to preprocess the pasted content
538
+ def preprocess_text(text):
539
+ # Replace CRLF and other newline variations with the JSON newline escape sequence
540
+ text = text.replace('\r\n', '\\n')
541
+ text = text.replace('\r', '\\n')
542
+ text = text.replace('\n', '\\n')
543
+ # Escape double quotes inside the text
544
+ text = text.replace('"', '\\"')
545
+ # Optionally remove or handle other special characters that might not be JSON-safe
546
+ # Here, we remove characters like tabs or non-ASCII characters (as an example)
547
+ text = re.sub(r'[\t]', ' ', text) # Replace tabs with spaces
548
+ text = re.sub(r'[^\x00-\x7F]+', '', text) # Remove non-ASCII characters
549
+ # Normalize spaces (strip leading/trailing whitespace)
550
+ text = text.strip()
551
+ return text
552
+
553
+
554
+
555
+ def load_file_content(file_path):
556
+ """Load and return file content with error handling"""
557
+ try:
558
+ with open(file_path, 'r', encoding='utf-8') as file:
559
+ return file.read()
560
+ except Exception as e:
561
+ st.error(f"Error loading file: {str(e)}")
562
+ return None
563
+
564
+ def save_file_content(file_path, content):
565
+ """Save file content with error handling"""
566
+ try:
567
+ with open(file_path, 'w', encoding='utf-8') as file:
568
+ file.write(content)
569
+ return True
570
+ except Exception as e:
571
+ st.error(f"Error saving file: {str(e)}")
572
+ return False
573
+
574
+ def display_file_viewer(file_path):
575
+ """Display file content in markdown viewer"""
576
+ content = load_file_content(file_path)
577
+ if content:
578
+ st.markdown("### πŸ“„ File Viewer")
579
+ st.markdown(f"**Viewing:** {file_path}")
580
+
581
+ # Add file metadata
582
+ file_stats = os.stat(file_path)
583
+ st.markdown(f"**Last modified:** {datetime.fromtimestamp(file_stats.st_mtime).strftime('%Y-%m-%d %H:%M:%S')}")
584
+ st.markdown(f"**Size:** {file_stats.st_size} bytes")
585
+
586
+ # Display content in markdown
587
+ st.markdown("---")
588
+ st.markdown(content)
589
+
590
+ # Add download button
591
+ st.download_button(
592
+ label="⬇️ Download File",
593
+ data=content,
594
+ file_name=os.path.basename(file_path),
595
+ mime="text/markdown"
596
+ )
597
+
598
+
599
+
600
+ def display_file_editor(file_path):
601
+ """Display file content in both Markdown and Code Editor views"""
602
+ # Initialize file content in session state if not already present
603
+ if 'file_content' not in st.session_state:
604
+ st.session_state.file_content = {}
605
+
606
+ # Load content if not in session state or if it's a different file
607
+ if file_path not in st.session_state.file_content:
608
+ content = load_file_content(file_path)
609
+ if content is not None:
610
+ st.session_state.file_content[file_path] = content
611
+ else:
612
+ return
613
+
614
+ st.markdown("### ✏️ File Editor")
615
+ st.markdown(f"**Editing:** {file_path}")
616
+
617
+ # Create tabs for different views
618
+ markdown_tab, code_tab = st.tabs(["Markdown View", "Code Editor"])
619
+
620
+ with markdown_tab:
621
+ st.markdown("### πŸ“„ Markdown Preview")
622
+ st.markdown(st.session_state.file_content[file_path])
623
+
624
+ with code_tab:
625
+ st.markdown("### πŸ’» Code Editor")
626
+ # Create a unique key for the text area
627
+ editor_key = f"editor_{hash(file_path)}"
628
+
629
+ # Editor with syntax highlighting for markdown
630
+ new_content = st.text_area(
631
+ "Edit content below:",
632
+ value=st.session_state.file_content[file_path],
633
+ height=400,
634
+ key=editor_key
635
+ )
636
+
637
+ # Add save and download buttons below both views
638
+ col1, col2 = st.columns([1, 5])
639
+ with col1:
640
+ if st.button("πŸ’Ύ Save Changes"):
641
+ if save_file_content(file_path, new_content):
642
+ st.session_state.file_content[file_path] = new_content
643
+ st.success("File saved successfully! πŸŽ‰")
644
+ time.sleep(1)
645
+ st.rerun()
646
+
647
+ with col2:
648
+ st.download_button(
649
+ label="⬇️ Download File",
650
+ data=new_content,
651
+ file_name=os.path.basename(file_path),
652
+ mime="text/markdown"
653
+ )
654
+
655
+
656
+
657
+
658
+ def display_file_editor_old(file_path):
659
+ """Display file content in editor with save functionality"""
660
+ # Initialize file content in session state if not already present
661
+ if 'file_content' not in st.session_state:
662
+ st.session_state.file_content = {}
663
+
664
+ # Load content if not in session state or if it's a different file
665
+ if file_path not in st.session_state.file_content:
666
+ content = load_file_content(file_path)
667
+ if content is not None:
668
+ st.session_state.file_content[file_path] = content
669
+ else:
670
+ return
671
+
672
+ st.markdown("### ✏️ File Editor")
673
+ st.markdown(f"**Editing:** {file_path}")
674
+
675
+ # Create a unique key for the text area
676
+ editor_key = f"editor_{hash(file_path)}"
677
+
678
+ # Editor with syntax highlighting for markdown
679
+ new_content = st.text_area(
680
+ "Edit content below:",
681
+ value=st.session_state.file_content[file_path],
682
+ height=400,
683
+ key=editor_key
684
+ )
685
+
686
+ col1, col2 = st.columns([1, 5])
687
+ with col1:
688
+ if st.button("πŸ’Ύ Save Changes"):
689
+ if save_file_content(file_path, new_content):
690
+ st.session_state.file_content[file_path] = new_content
691
+ st.success("File saved successfully! πŸŽ‰")
692
+ time.sleep(1)
693
+ st.rerun()
694
+
695
+ with col2:
696
+ st.download_button(
697
+ label="⬇️ Download File",
698
+ data=new_content,
699
+ file_name=os.path.basename(file_path),
700
+ mime="text/markdown"
701
+ )
702
+
703
+ def update_file_management_section():
704
+ # Initialize session state variables
705
+ if 'file_view_mode' not in st.session_state:
706
+ st.session_state.file_view_mode = None
707
+ if 'current_file' not in st.session_state:
708
+ st.session_state.current_file = None
709
+ if 'file_content' not in st.session_state:
710
+ st.session_state.file_content = {}
711
+
712
+ all_files = glob.glob("*.md")
713
+ all_files.sort(reverse=True)
714
+
715
+ # File management buttons in sidebar
716
+ st.sidebar.title("πŸ“ File Management")
717
+
718
+ if st.sidebar.button("πŸ—‘ Delete All Files"):
719
+ for file in all_files:
720
+ os.remove(file)
721
+ st.session_state.file_content = {} # Clear the file content cache
722
+ st.session_state.current_file = None
723
+ st.session_state.file_view_mode = None
724
+ st.rerun()
725
+
726
+ if st.sidebar.button("⬇️ Download All Files"):
727
+ zip_file = create_zip_of_files(all_files)
728
+ st.sidebar.markdown(get_download_link(zip_file), unsafe_allow_html=True)
729
+
730
+ # Display files in sidebar with action buttons
731
+ for file in all_files:
732
+ col1, col2, col3, col4 = st.sidebar.columns([1,3,1,1])
733
+
734
+ with col1:
735
+ if st.button("🌐", key=f"view_{file}"):
736
+ st.session_state.current_file = file
737
+ st.session_state.file_view_mode = 'view'
738
+ if file not in st.session_state.file_content:
739
+ content = load_file_content(file)
740
+ if content is not None:
741
+ st.session_state.file_content[file] = content
742
+ st.rerun()
743
+
744
+ with col2:
745
+ st.markdown(get_download_link(file), unsafe_allow_html=True)
746
+
747
+ with col3:
748
+ if st.button("πŸ“‚", key=f"edit_{file}"):
749
+ st.session_state.current_file = file
750
+ st.session_state.file_view_mode = 'edit'
751
+ if file not in st.session_state.file_content:
752
+ content = load_file_content(file)
753
+ if content is not None:
754
+ st.session_state.file_content[file] = content
755
+ st.rerun()
756
+
757
+ with col4:
758
+ if st.button("πŸ—‘", key=f"delete_{file}"):
759
+ os.remove(file)
760
+ if file in st.session_state.file_content:
761
+ del st.session_state.file_content[file]
762
+ if st.session_state.current_file == file:
763
+ st.session_state.current_file = None
764
+ st.session_state.file_view_mode = None
765
+ st.rerun()
766
+
767
+ # Display viewer or editor in main area based on mode
768
+ if st.session_state.current_file:
769
+ if st.session_state.file_view_mode == 'view':
770
+ display_file_viewer(st.session_state.current_file)
771
+ elif st.session_state.file_view_mode == 'edit':
772
+ display_file_editor(st.session_state.current_file)
773
+
774
+
775
+
776
+
777
+ # 🎭 Main function - "All the world's a stage, and all the code merely players" -Shakespeare, probably
778
+ def main():
779
+ st.markdown("### πŸ™Git🌌CosmosπŸ’« - Azure Cosmos DB and Github Agent")
780
+
781
+ # 🎲 Session state vars - "Life is like a session state, you never know what you're gonna get"
782
+ if 'logged_in' not in st.session_state:
783
+ st.session_state.logged_in = False
784
+ if 'selected_records' not in st.session_state:
785
+ st.session_state.selected_records = []
786
+ if 'client' not in st.session_state:
787
+ st.session_state.client = None
788
+ if 'selected_database' not in st.session_state:
789
+ st.session_state.selected_database = None
790
+ if 'selected_container' not in st.session_state:
791
+ st.session_state.selected_container = None
792
+ if 'selected_document_id' not in st.session_state:
793
+ st.session_state.selected_document_id = None
794
+ if 'current_index' not in st.session_state:
795
+ st.session_state.current_index = 0
796
+ if 'cloned_doc' not in st.session_state:
797
+ st.session_state.cloned_doc = None
798
+
799
+ # πŸ” Query processing - "To search or not to search, that is the query"
800
+ try:
801
+ query_params = st.query_params
802
+ query = query_params.get('q') or query_params.get('query') or ''
803
+ if query:
804
+ result, result2, result3, response2 = search_glossary(query)
805
+
806
+ # πŸ’Ύ Save results - "Every file you save is a future you pave"
807
+ try:
808
+ if st.button("Save AI Output"):
809
+ filename = create_file_from_content(result)
810
+ st.success(f"File saved: {filename}")
811
+ filename = create_file_from_content(result2)
812
+ st.success(f"File saved: {filename}")
813
+ filename = create_file_from_content(result3)
814
+ st.success(f"File saved: {filename}")
815
+ filename = create_file_from_content(response2)
816
+ st.success(f"File saved: {filename}")
817
+
818
+ display_saved_files_in_sidebar()
819
+ except Exception as e:
820
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
821
+
822
+ # 🌟 Cosmos DB operations - "In Cosmos DB we trust, but we still handle errors we must"
823
+ try:
824
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result, result)
825
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result2, result2)
826
+ save_to_cosmos_db(st.session_state.cosmos_container, query, result3, result3)
827
+ save_to_cosmos_db(st.session_state.cosmos_container, query, response2[0], response2[0])
828
+ save_to_cosmos_db(st.session_state.cosmos_container, query, response2[1], response2[1])
829
+ except exceptions.CosmosHttpResponseError as e:
830
+ st.error(f"HTTP error occurred: {str(e)} 🚨")
831
+ except Exception as e:
832
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
833
+ st.stop()
834
+ except Exception as e:
835
+ st.markdown(' ')
836
+
837
+ # πŸ” Auth check - "With great keys come great connectivity"
838
+ if Key:
839
+ st.session_state.primary_key = Key
840
+ st.session_state.logged_in = True
841
+ else:
842
+ st.error("Cosmos DB Key is not set in environment variables. πŸ”‘βŒ")
843
+ return
844
+
845
+ if st.session_state.logged_in:
846
+ # 🌌 DB initialization - "In the beginning, there was connection string..."
847
+ try:
848
+ if st.session_state.client is None:
849
+ st.session_state.client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
850
+ # πŸ“š Navigation setup - "Navigation is not about where you are, but where you're going"
851
+ st.sidebar.title("πŸ™Git🌌CosmosπŸ’«πŸ—„οΈNavigator")
852
+ databases = get_databases(st.session_state.client)
853
+ selected_db = st.sidebar.selectbox("πŸ—ƒοΈ Select Database", databases)
854
+ st.markdown(CosmosDBUrl)
855
+
856
+ # πŸ”„ State management - "Change is the only constant in state management"
857
+ if selected_db != st.session_state.selected_database:
858
+ st.session_state.selected_database = selected_db
859
+ st.session_state.selected_container = None
860
+ st.session_state.selected_document_id = None
861
+ st.session_state.current_index = 0
862
+ st.rerun()
863
+
864
+ if st.session_state.selected_database:
865
+ database = st.session_state.client.get_database_client(st.session_state.selected_database)
866
+ containers = get_containers(database)
867
+ selected_container = st.sidebar.selectbox("πŸ“ Select Container", containers)
868
+
869
+ # πŸ”„ Container state handling - "Container changes, state arranges"
870
+ if selected_container != st.session_state.selected_container:
871
+ st.session_state.selected_container = selected_container
872
+ st.session_state.selected_document_id = None
873
+ st.session_state.current_index = 0
874
+ st.rerun()
875
+
876
+ if st.session_state.selected_container:
877
+ container = database.get_container_client(st.session_state.selected_container)
878
+ # πŸ“¦ Export functionality - "Pack it, zip it, ship it"
879
+ if st.sidebar.button("πŸ“¦ Export Container Data"):
880
+ download_link = archive_current_container(st.session_state.selected_database,
881
+ st.session_state.selected_container,
882
+ st.session_state.client)
883
+ if download_link.startswith('<a'):
884
+ st.markdown(download_link, unsafe_allow_html=True)
885
+ else:
886
+ st.error(download_link)
887
+
888
+ # πŸ“ Document handling - "Document, document, on the wall, who's the most recent of them all?"
889
+ documents = get_documents(container)
890
+ total_docs = len(documents)
891
+ # Add a slider to let the user choose how many documents to display
892
+ num_docs_to_display = st.slider(
893
+ "Select number of documents to display", 1, 20, 1
894
+ )
895
+ # Adjust the document display logic based on the slider value
896
+ if total_docs > num_docs_to_display:
897
+ documents_to_display = documents[:num_docs_to_display]
898
+ st.sidebar.info(f"Showing top {num_docs_to_display} most recent documents.")
899
+ else:
900
+ documents_to_display = documents
901
+ st.sidebar.info(f"Showing all {len(documents_to_display)} documents.")
902
+
903
+ if documents_to_display:
904
+ # 🎨 View options - "Different strokes for different folks"
905
+ view_options = ['Show as Markdown', 'Show as Code Editor', 'Show as Run AI', 'Clone Document', 'New Record']
906
+ selected_view = st.sidebar.selectbox("Select Viewer/Editor", view_options, index=2)
907
+
908
+
909
+ if selected_view == 'Show as Markdown':
910
+ Label = '#### πŸ“„ Markdown view - Mark it down, mark it up'
911
+ st.markdown(Label)
912
+ total_docs = len(documents)
913
+ doc = documents[st.session_state.current_index]
914
+ # st.markdown(f"#### Document ID: {doc.get('id', '')}")
915
+
916
+ # πŸ•΅οΈ Value extraction - "Finding spaces in all the right places"
917
+ values_with_space = []
918
+ def extract_values(obj):
919
+ if isinstance(obj, dict):
920
+ for k, v in obj.items():
921
+ extract_values(v)
922
+ elif isinstance(obj, list):
923
+ for item in obj:
924
+ extract_values(item)
925
+ elif isinstance(obj, str):
926
+ if ' ' in obj:
927
+ values_with_space.append(obj)
928
+
929
+ extract_values(doc)
930
+ st.markdown("#### πŸ”— Links for Extracted Texts")
931
+ for term in values_with_space:
932
+ display_glossary_entity(term)
933
+
934
+ content = json.dumps(doc, indent=2)
935
+ st.markdown(f"```json\n{content}\n```")
936
+
937
+ # β¬…οΈβž‘οΈ Navigation - "Left and right, day and night"
938
+ col_prev, col_next = st.columns([1, 1])
939
+ with col_prev:
940
+ if st.button("⬅️ Previous", key='prev_markdown'):
941
+ if st.session_state.current_index > 0:
942
+ st.session_state.current_index -= 1
943
+ st.rerun()
944
+ with col_next:
945
+ if st.button("➑️ Next", key='next_markdown'):
946
+ if st.session_state.current_index < total_docs - 1:
947
+ st.session_state.current_index += 1
948
+ st.rerun()
949
+
950
+ elif selected_view == 'Show as Code Editor':
951
+ Label = '#### πŸ’» Code editor view'
952
+ st.markdown(Label)
953
+ total_docs = len(documents)
954
+
955
+ if total_docs == 0:
956
+ st.warning("No documents available.")
957
+ return
958
+
959
+ doc = documents[st.session_state.current_index]
960
+ doc_str = st.text_area("Edit Document",
961
+ value=json.dumps(doc, indent=2),
962
+ height=300,
963
+ key=f'code_editor_{st.session_state.current_index}')
964
+
965
+ col_prev, col_next = st.columns([1, 1])
966
+ with col_prev:
967
+ if st.button("⬅️ Previous", key='prev_code'):
968
+ if st.session_state.current_index > 0:
969
+ st.session_state.current_index -= 1
970
+ st.rerun()
971
+ with col_next:
972
+ if st.button("➑️ Next", key='next_code'):
973
+ if st.session_state.current_index < total_docs - 1:
974
+ st.session_state.current_index += 1
975
+ st.rerun()
976
+
977
+ col_save, col_delete = st.columns([1, 1])
978
+ with col_save:
979
+ if st.button("πŸ’Ύ Save Changes", key=f'save_button_{st.session_state.current_index}'):
980
+ try:
981
+ updated_doc = json.loads(doc_str)
982
+ response = container.upsert_item(body=updated_doc)
983
+ if response:
984
+ st.success(f"Document {updated_doc['id']} saved successfully.")
985
+ st.session_state.selected_document_id = updated_doc['id']
986
+ st.rerun()
987
+ except json.JSONDecodeError:
988
+ st.error("Invalid JSON format. Please check your edits.")
989
+ except Exception as e:
990
+ st.error(f"Error saving document: {str(e)}")
991
+
992
+ with col_delete:
993
+ if st.button("πŸ—‘οΈ Delete", key=f'delete_button_{st.session_state.current_index}'):
994
+ try:
995
+ current_doc = json.loads(doc_str)
996
+ doc_id = current_doc.get("id")
997
+
998
+ if not doc_id:
999
+ st.error("Document ID not found.")
1000
+ return
1001
+
1002
+ # Confirm deletion
1003
+ if 'confirm_delete' not in st.session_state:
1004
+ st.session_state.confirm_delete = False
1005
+
1006
+ if not st.session_state.confirm_delete:
1007
+ if st.button("⚠️ Click to confirm deletion", key=f'confirm_delete_{st.session_state.current_index}'):
1008
+ st.session_state.confirm_delete = True
1009
+ st.rerun()
1010
+ else:
1011
+ try:
1012
+ # Delete the document
1013
+ container.delete_item(item=doc_id, partition_key=doc_id)
1014
+
1015
+ # Update the session state
1016
+ st.session_state.confirm_delete = False
1017
+
1018
+ # Update the current index if necessary
1019
+ if total_docs > 1:
1020
+ if st.session_state.current_index == total_docs - 1:
1021
+ st.session_state.current_index = max(0, total_docs - 2)
1022
+ documents.pop(st.session_state.current_index)
1023
+ else:
1024
+ st.session_state.current_index = 0
1025
+ documents.clear()
1026
+
1027
+ st.success(f"Document {doc_id} deleted successfully.")
1028
+ st.rerun()
1029
+
1030
+ except Exception as e:
1031
+ st.error(f"Error deleting document: {str(e)}")
1032
+ st.session_state.confirm_delete = False
1033
+
1034
+ except json.JSONDecodeError:
1035
+ st.error("Invalid JSON format. Please check the document.")
1036
+ except Exception as e:
1037
+ st.error(f"Error processing deletion: {str(e)}")
1038
+
1039
+ elif selected_view == 'Show as Code Editor - Old':
1040
+ Label = '#### πŸ’» Code editor view'
1041
+ st.markdown(Label)
1042
+ total_docs = len(documents)
1043
+ doc = documents[st.session_state.current_index]
1044
+ # st.markdown(f"#### Document ID: {doc.get('id', '')}")
1045
+ doc_str = st.text_area("Edit Document",
1046
+ value=json.dumps(doc, indent=2),
1047
+ height=300,
1048
+ key=f'code_editor_{st.session_state.current_index}')
1049
+
1050
+ col_prev, col_next = st.columns([1, 1])
1051
+ with col_prev:
1052
+ if st.button("⬅️ Previous", key='prev_code'):
1053
+ if st.session_state.current_index > 0:
1054
+ st.session_state.current_index -= 1
1055
+ st.rerun()
1056
+ with col_next:
1057
+ if st.button("➑️ Next", key='next_code'):
1058
+ if st.session_state.current_index < total_docs - 1:
1059
+ st.session_state.current_index += 1
1060
+ st.rerun()
1061
+
1062
+ col_save, col_delete = st.columns([1, 1])
1063
+ with col_save:
1064
+ if st.button("πŸ’Ύ Save Changes", key=f'save_button_{st.session_state.current_index}'):
1065
+ try:
1066
+ updated_doc = json.loads(doc_str)
1067
+ response = container.upsert_item(body=updated_doc)
1068
+ if response:
1069
+ st.success(f"Document {updated_doc['id']} saved successfully.")
1070
+ st.session_state.selected_document_id = updated_doc['id']
1071
+ st.rerun()
1072
+ except Exception as e:
1073
+ st.error(f"Error saving document: {str(e)}")
1074
+
1075
+ with col_delete:
1076
+ if st.button("πŸ—‘οΈ Delete", key=f'delete_button_{st.session_state.current_index}'):
1077
+ try:
1078
+ current_doc = json.loads(doc_str)
1079
+ # Direct deletion using container method with id and partition key
1080
+ delete = container.delete_item(current_doc["id"], current_doc["id"])
1081
+ if delete:
1082
+ st.success(f"Document {current_doc['id']} deleted successfully.")
1083
+ if st.session_state.current_index > 0:
1084
+ st.session_state.current_index -= 1
1085
+ st.rerun()
1086
+ except Exception as e:
1087
+ st.error(f"Error deleting document: {str(e)}")
1088
+
1089
+
1090
+
1091
+
1092
+ elif selected_view == 'Show as Run AI':
1093
+ Label = '#### ✏️ Run AI with wisdom, save with precision'
1094
+ st.markdown(Label)
1095
+ num_cols = len(documents_to_display)
1096
+ cols = st.columns(num_cols)
1097
+
1098
+ for idx, (col, doc) in enumerate(zip(cols, documents_to_display)):
1099
+ with col:
1100
+ # ID and Name fields
1101
+ editable_id = st.text_input("ID", value=doc.get('id', ''), key=f'edit_id_{idx}')
1102
+ editable_name = st.text_input("Name", value=doc.get('name', ''), key=f'edit_name_{idx}')
1103
+
1104
+ # Create editable document copy without id and name
1105
+ editable_doc = doc.copy()
1106
+ editable_doc.pop('id', None)
1107
+ editable_doc.pop('name', None)
1108
+
1109
+ doc_str = st.text_area("Document Content (in JSON format)",
1110
+ value=json.dumps(editable_doc, indent=2),
1111
+ height=300,
1112
+ key=f'doc_str_{idx}')
1113
+
1114
+ # Save and AI operations columns
1115
+
1116
+ if st.button("πŸ€– Run AI", key=f'run_with_ai_button_{idx}'):
1117
+ # Your existing AI processing code here
1118
+ values_with_space = []
1119
+ def extract_values2(obj):
1120
+ if isinstance(obj, dict):
1121
+ for k, v in obj.items():
1122
+ extract_values2(v)
1123
+ elif isinstance(obj, list):
1124
+ for item in obj:
1125
+ extract_values2(item)
1126
+ elif isinstance(obj, str):
1127
+ if ' ' in obj:
1128
+ values_with_space.append(obj)
1129
+
1130
+ extract_values2(doc)
1131
+ for term in values_with_space:
1132
+ display_glossary_entity(term)
1133
+ search_glossary(term)
1134
+
1135
+ if st.button("πŸ’Ύ Save Changes", key=f'save_runai_{idx}'):
1136
+ try:
1137
+ updated_doc = json.loads(doc_str)
1138
+ # Reinsert ID and name from editable fields
1139
+ updated_doc['id'] = editable_id
1140
+ updated_doc['name'] = editable_name
1141
+ response = container.upsert_item(body=updated_doc)
1142
+ if response:
1143
+ st.success(f"Document {updated_doc['id']} saved successfully.")
1144
+ st.session_state.selected_document_id = updated_doc['id']
1145
+ st.rerun()
1146
+ except Exception as e:
1147
+ st.error(f"Error saving document: {str(e)}")
1148
+
1149
+
1150
+
1151
+
1152
+
1153
+ elif selected_view == 'Clone Document':
1154
+ st.markdown("#### πŸ“„ Clone Document (Save As)")
1155
+
1156
+ total_docs = len(documents)
1157
+ doc = documents[st.session_state.current_index]
1158
+
1159
+ # Display current document info
1160
+ st.markdown(f"**Original Document ID:** {doc.get('id', '')}")
1161
+ st.markdown(f"**Original Document Name:** {doc.get('name', '')}")
1162
+
1163
+ # Generate new unique ID and name
1164
+ unique_filename = gen_AI_IO_filename("Clone", doc.get('name', ''))
1165
+ new_id = st.text_input("New Document ID", value=unique_filename, key='new_clone_id')
1166
+ new_name = st.text_input("New Document Name", value=f"Clone_{unique_filename[:8]}", key='new_clone_name')
1167
+
1168
+ # Create new document with all original content except system fields
1169
+ new_doc = {
1170
+ 'id': new_id,
1171
+ 'name': new_name,
1172
+ **{k: v for k, v in doc.items() if k not in ['id', 'name', '_rid', '_self', '_etag', '_attachments', '_ts']}
1173
+ }
1174
+
1175
+ # Show editable preview of the new document
1176
+ doc_str = st.text_area(
1177
+ "Edit Document Content (in JSON format)",
1178
+ value=json.dumps(new_doc, indent=2),
1179
+ height=300,
1180
+ key='clone_preview'
1181
+ )
1182
+
1183
+ col1, col2 = st.columns(2)
1184
+
1185
+ with col1:
1186
+ if st.button("πŸ”„ Generate New ID/Name", key='regenerate_id'):
1187
+ # Generate new unique filename
1188
+ new_unique_filename = gen_AI_IO_filename("Clone", doc.get('name', ''))
1189
+ st.session_state.new_clone_id = new_unique_filename
1190
+ st.session_state.new_clone_name = f"Clone_{new_unique_filename[:8]}"
1191
+ st.rerun()
1192
+
1193
+ with col2:
1194
+ if st.button("πŸ’Ύ Save As New Document", key='save_clone'):
1195
+ try:
1196
+ # Parse the edited document content
1197
+ final_doc = json.loads(doc_str)
1198
+
1199
+ # Ensure the new ID and name are used
1200
+ final_doc['id'] = new_id
1201
+ final_doc['name'] = new_name
1202
+
1203
+ # Remove any system fields that might have been copied
1204
+ system_fields = ['_rid', '_self', '_etag', '_attachments', '_ts']
1205
+ for field in system_fields:
1206
+ final_doc.pop(field, None)
1207
+
1208
+ # Create the new document
1209
+ response = container.create_item(body=final_doc)
1210
+
1211
+ if response:
1212
+ st.success(f"""
1213
+ βœ… New document created successfully!
1214
+ - ID: {final_doc['id']}
1215
+ - Name: {final_doc['name']}
1216
+ """)
1217
+ # Update session state to show the new document
1218
+ st.session_state.selected_document_id = final_doc['id']
1219
+ st.rerun()
1220
+ else:
1221
+ st.error("Failed to create new document")
1222
+ except json.JSONDecodeError as e:
1223
+ st.error(f"Invalid JSON format: {str(e)}")
1224
+ except Exception as e:
1225
+ st.error(f"Error creating document: {str(e)}")
1226
+
1227
+ # Navigation buttons for viewing other documents to clone
1228
+ col_prev, col_next = st.columns([1, 1])
1229
+ with col_prev:
1230
+ if st.button("⬅️ Previous", key='prev_clone'):
1231
+ if st.session_state.current_index > 0:
1232
+ st.session_state.current_index -= 1
1233
+ st.rerun()
1234
+ with col_next:
1235
+ if st.button("➑️ Next", key='next_clone'):
1236
+ if st.session_state.current_index < total_docs - 1:
1237
+ st.session_state.current_index += 1
1238
+ st.rerun()
1239
+
1240
+
1241
+ elif selected_view == 'New Record':
1242
+ st.markdown("#### Create a new document:")
1243
+
1244
+ if st.button("πŸ€– Insert Auto-Generated Record"):
1245
+ auto_doc = {
1246
+ "id": generate_unique_id(),
1247
+ "name": f"Auto-generated Record {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
1248
+ "content": "This is an auto-generated record.",
1249
+ "timestamp": datetime.now().isoformat()
1250
+ }
1251
+ success, message = save_or_clone_to_cosmos_db(container, document=auto_doc)
1252
+ if success:
1253
+ st.success(message)
1254
+ st.rerun()
1255
+ else:
1256
+ st.error(message)
1257
+ else:
1258
+ new_id = st.text_input("ID", value=generate_unique_id(), key='new_id')
1259
+ default_doc = {
1260
+ "id": new_id,
1261
+ "name": "New Document",
1262
+ "content": "",
1263
+ "timestamp": datetime.now().isoformat()
1264
+ }
1265
+ new_doc_str = st.text_area("Document Content (in JSON format)",
1266
+ value=json.dumps(default_doc, indent=2),
1267
+ height=300)
1268
+
1269
+ if st.button("βž• Create New Document"):
1270
+ try:
1271
+ # Preprocess the text before loading it into JSON
1272
+ cleaned_doc_str = preprocess_text(new_doc_str)
1273
+ new_doc = json.loads(cleaned_doc_str)
1274
+ new_doc['id'] = new_id # Ensure ID matches input field
1275
+
1276
+ success, message = insert_record(container, new_doc)
1277
+ if success:
1278
+ st.success(f"New document created with id: {new_doc['id']} πŸŽ‰")
1279
+ st.session_state.selected_document_id = new_doc['id']
1280
+ st.rerun()
1281
+ else:
1282
+ st.error(message)
1283
+ except json.JSONDecodeError as e:
1284
+ st.error(f"Invalid JSON: {str(e)} 🚫")
1285
+
1286
+ st.subheader(f"πŸ“Š Container: {st.session_state.selected_container}")
1287
+ if st.session_state.selected_container:
1288
+ if documents_to_display:
1289
+ Label = '#### πŸ“Š Data display - Data tells tales that words cannot'
1290
+ st.markdown(Label)
1291
+ df = pd.DataFrame(documents_to_display)
1292
+ st.dataframe(df)
1293
+ else:
1294
+ st.info("No documents to display. 🧐")
1295
+
1296
+
1297
+ Label = '#### πŸ™ GitHub integration - Git happens'
1298
+ st.subheader("πŸ™ GitHub Operations")
1299
+ github_token = os.environ.get("GITHUB")
1300
+ source_repo = st.text_input("Source GitHub Repository URL",
1301
+ value="https://github.com/AaronCWacker/AIExamples-8-24-Streamlit")
1302
+ new_repo_name = st.text_input("New Repository Name (for cloning)",
1303
+ value=f"AIExample-Clone-{datetime.now().strftime('%Y%m%d_%H%M%S')}")
1304
+
1305
+ col1, col2 = st.columns(2)
1306
+ with col1:
1307
+ if st.button("πŸ“₯ Clone Repository"):
1308
+ if github_token and source_repo:
1309
+
1310
+ st.markdown(Label)
1311
+ try:
1312
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d%H%M%S')}"
1313
+ download_github_repo(source_repo, local_path)
1314
+ zip_filename = f"{new_repo_name}.zip"
1315
+ create_zip_file(local_path, zip_filename[:-4])
1316
+ st.markdown(get_download_link(zip_filename), unsafe_allow_html=True)
1317
+ st.success("Repository cloned successfully! πŸŽ‰")
1318
+ except Exception as e:
1319
+ st.error(f"An error occurred: {str(e)} 😒")
1320
+ finally:
1321
+ if os.path.exists(local_path):
1322
+ shutil.rmtree(local_path)
1323
+ if os.path.exists(zip_filename):
1324
+ os.remove(zip_filename)
1325
+ else:
1326
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided. πŸ”‘β“")
1327
+
1328
+ with col2:
1329
+ if st.button("πŸ“€ Push to New Repository"):
1330
+ if github_token and source_repo:
1331
+
1332
+ st.markdown(Label)
1333
+ try:
1334
+ g = Github(github_token)
1335
+ new_repo = create_repo(g, new_repo_name)
1336
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d%H%M%S')}"
1337
+ download_github_repo(source_repo, local_path)
1338
+ push_to_github(local_path, new_repo, github_token)
1339
+ st.success(f"Repository pushed successfully to {new_repo.html_url} πŸš€")
1340
+ except Exception as e:
1341
+ st.error(f"An error occurred: {str(e)} 😒")
1342
+ finally:
1343
+ if os.path.exists(local_path):
1344
+ shutil.rmtree(local_path)
1345
+ else:
1346
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided. πŸ”‘β“")
1347
+
1348
+
1349
+ st.subheader("πŸ’¬ Chat with Claude")
1350
+ user_input = st.text_area("Message πŸ“¨:", height=100)
1351
+
1352
+ if st.button("Send πŸ“¨"):
1353
+ Label = '#### πŸ’¬ Chat functionality - Every chat is a chance to learn'
1354
+ st.markdown(Label)
1355
+ if user_input:
1356
+ response = anthropicclient.messages.create(
1357
+ model="claude-3-sonnet-20240229",
1358
+ max_tokens=1000,
1359
+ messages=[
1360
+ {"role": "user", "content": user_input}
1361
+ ]
1362
+ )
1363
+ st.write("Claude's reply 🧠:")
1364
+ st.write(response.content[0].text)
1365
+ filename = generate_filename(user_input, "md")
1366
+ create_file(filename, user_input, response.content[0].text)
1367
+ st.session_state.chat_history.append({"user": user_input, "claude": response.content[0].text})
1368
+ # Save to Cosmos DB
1369
+ save_to_cosmos_db(container, user_input, response.content[0].text, "")
1370
+
1371
+
1372
+
1373
+ # πŸ“œ Chat history display - "History repeats itself, first as chat, then as wisdom"
1374
+ st.subheader("Past Conversations πŸ“œ")
1375
+ for chat in st.session_state.chat_history:
1376
+ st.text_area("You said πŸ’¬:", chat["user"], height=100, disabled=True)
1377
+ st.text_area("Claude replied πŸ€–:", chat["claude"], height=200, disabled=True)
1378
+ st.markdown("---")
1379
+
1380
+
1381
+ # πŸ“ File editor - "Edit with care, save with flair"
1382
+ if hasattr(st.session_state, 'current_file'):
1383
+ st.subheader(f"Editing: {st.session_state.current_file} πŸ› ")
1384
+ new_content = st.text_area("File Content ✏️:", st.session_state.file_content, height=300)
1385
+
1386
+ # Preprocess the text before loading it into JSON - Added to protect copy paste into JSON to keep format.
1387
+ cleaned_doc_str = preprocess_text(new_content)
1388
+ new_doc = json.loads(cleaned_doc_str)
1389
+ new_content = cleaned_doc_str
1390
+
1391
+ if st.button("Save Changes πŸ’Ύ"):
1392
+ with open(st.session_state.current_file, 'w', encoding='utf-8') as file:
1393
+ file.write(new_content)
1394
+ st.success("File updated successfully! πŸŽ‰")
1395
+
1396
+ # πŸ“‚ File management - "Manage many, maintain order"
1397
+ update_file_management_section()
1398
+
1399
+ except exceptions.CosmosHttpResponseError as e:
1400
+ st.error(f"Failed to connect to Cosmos DB. HTTP error: {str(e)} 🚨")
1401
+ except Exception as e:
1402
+ st.error(f"An unexpected error occurred: {str(e)} 😱")
1403
+
1404
+ if st.session_state.logged_in and st.sidebar.button("πŸšͺ Logout"):
1405
+ Label = '#### πŸšͺ Logout - All good things must come to an end'
1406
+ st.markdown(Label)
1407
+ st.session_state.logged_in = False
1408
+ st.session_state.selected_records.clear()
1409
+ st.session_state.client = None
1410
+ st.session_state.selected_database = None
1411
+ st.session_state.selected_container = None
1412
+ st.session_state.selected_document_id = None
1413
+ st.session_state.current_index = 0
1414
+ st.rerun()
1415
+
1416
+ if __name__ == "__main__":
1417
+ main()