awacke1 commited on
Commit
41ceac3
β€’
1 Parent(s): 06a02a3

Create backup14.app.py

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