awacke1 commited on
Commit
aa2905a
β€’
1 Parent(s): 5ffff36

Create backup7.app.py

Browse files
Files changed (1) hide show
  1. backup7.app.py +369 -0
backup7.app.py ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from azure.cosmos import CosmosClient, PartitionKey, exceptions
3
+ import os
4
+ import pandas as pd
5
+ import traceback
6
+ import requests
7
+ import shutil
8
+ import zipfile
9
+ from github import Github
10
+ from git import Repo
11
+ from datetime import datetime
12
+ import base64
13
+ import json
14
+
15
+ st.set_page_config(layout="wide")
16
+
17
+ # Cosmos DB configuration
18
+ ENDPOINT = "https://acae-afd.documents.azure.com:443/"
19
+ SUBSCRIPTION_ID = "003fba60-5b3f-48f4-ab36-3ed11bc40816"
20
+ DATABASE_NAME = os.environ.get("COSMOS_DATABASE_NAME")
21
+ CONTAINER_NAME = os.environ.get("COSMOS_CONTAINER_NAME")
22
+ Key = os.environ.get("Key")
23
+
24
+ # GitHub configuration
25
+ def download_github_repo(url, local_path):
26
+ if os.path.exists(local_path):
27
+ shutil.rmtree(local_path)
28
+ Repo.clone_from(url, local_path)
29
+
30
+ def create_zip_file(source_dir, output_filename):
31
+ shutil.make_archive(output_filename, 'zip', source_dir)
32
+
33
+ def create_repo(g, repo_name):
34
+ user = g.get_user()
35
+ return user.create_repo(repo_name)
36
+
37
+ def push_to_github(local_path, repo, github_token):
38
+ repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
39
+ local_repo = Repo(local_path)
40
+
41
+ if 'origin' in [remote.name for remote in local_repo.remotes]:
42
+ origin = local_repo.remote('origin')
43
+ origin.set_url(repo_url)
44
+ else:
45
+ origin = local_repo.create_remote('origin', repo_url)
46
+
47
+ if not local_repo.heads:
48
+ local_repo.git.checkout('-b', 'main')
49
+ current_branch = 'main'
50
+ else:
51
+ current_branch = local_repo.active_branch.name
52
+
53
+ local_repo.git.add(A=True)
54
+
55
+ if local_repo.is_dirty():
56
+ local_repo.git.commit('-m', 'Initial commit')
57
+
58
+ origin.push(refspec=f'{current_branch}:{current_branch}')
59
+
60
+ def get_base64_download_link(file_path, file_name):
61
+ with open(file_path, "rb") as file:
62
+ contents = file.read()
63
+ base64_encoded = base64.b64encode(contents).decode()
64
+ return f'<a href="data:application/zip;base64,{base64_encoded}" download="{file_name}">Download {file_name}</a>'
65
+
66
+
67
+ # New functions for dynamic sidebar
68
+ def get_databases(client):
69
+ return [db['id'] for db in client.list_databases()]
70
+
71
+ def get_containers(database):
72
+ return [container['id'] for container in database.list_containers()]
73
+
74
+ def get_documents(container, limit=1000):
75
+ query = "SELECT * FROM c"
76
+ items = list(container.query_items(query=query, enable_cross_partition_query=True, max_item_count=limit))
77
+ return items
78
+
79
+
80
+ # Cosmos DB functions
81
+ def insert_record(record):
82
+ try:
83
+ response = container.create_item(body=record)
84
+ return True, response
85
+ except exceptions.CosmosHttpResponseError as e:
86
+ return False, f"HTTP error occurred: {str(e)}. Status code: {e.status_code}"
87
+ except Exception as e:
88
+ return False, f"An unexpected error occurred: {str(e)}"
89
+
90
+ def call_stored_procedure(record):
91
+ try:
92
+ response = container.scripts.execute_stored_procedure(
93
+ sproc="processPrompt",
94
+ params=[record],
95
+ partition_key=record['id']
96
+ )
97
+ return True, response
98
+ except exceptions.CosmosHttpResponseError as e:
99
+ error_message = f"HTTP error occurred: {str(e)}. Status code: {e.status_code}"
100
+ return False, error_message
101
+ except Exception as e:
102
+ error_message = f"An unexpected error occurred: {str(e)}"
103
+ return False, error_message
104
+
105
+ def fetch_all_records():
106
+ try:
107
+ query = "SELECT * FROM c"
108
+ items = list(container.query_items(query=query, enable_cross_partition_query=True))
109
+ return pd.DataFrame(items)
110
+ except exceptions.CosmosHttpResponseError as e:
111
+ st.error(f"HTTP error occurred while fetching records: {str(e)}. Status code: {e.status_code}")
112
+ return pd.DataFrame()
113
+ except Exception as e:
114
+ st.error(f"An unexpected error occurred while fetching records: {str(e)}")
115
+ return pd.DataFrame()
116
+
117
+ def update_record(updated_record):
118
+ try:
119
+ container.upsert_item(body=updated_record)
120
+ return True, f"Record with id {updated_record['id']} successfully updated."
121
+ except exceptions.CosmosHttpResponseError as e:
122
+ return False, f"HTTP error occurred: {str(e)}. Status code: {e.status_code}"
123
+ except Exception as e:
124
+ return False, f"An unexpected error occurred: {traceback.format_exc()}"
125
+
126
+ def delete_record(name, id):
127
+ try:
128
+ container.delete_item(item=id, partition_key=id)
129
+ return True, f"Successfully deleted record with name: {name} and id: {id}"
130
+ except exceptions.CosmosResourceNotFoundError:
131
+ return False, f"Record with id {id} not found. It may have been already deleted."
132
+ except exceptions.CosmosHttpResponseError as e:
133
+ return False, f"HTTP error occurred: {str(e)}. Status code: {e.status_code}"
134
+ except Exception as e:
135
+ return False, f"An unexpected error occurred: {traceback.format_exc()}"
136
+
137
+ # New function to archive current container
138
+ def archive_current_container(database_name, container_name, client):
139
+ try:
140
+ base_dir = "./cosmos_archive_current_container"
141
+ if os.path.exists(base_dir):
142
+ shutil.rmtree(base_dir)
143
+ os.makedirs(base_dir)
144
+
145
+ db_client = client.get_database_client(database_name)
146
+ container_client = db_client.get_container_client(container_name)
147
+ items = list(container_client.read_all_items())
148
+
149
+ container_dir = os.path.join(base_dir, container_name)
150
+ os.makedirs(container_dir)
151
+
152
+ for item in items:
153
+ item_id = item.get('id', f"unknown_{datetime.now().strftime('%Y%m%d%H%M%S')}")
154
+ with open(os.path.join(container_dir, f"{item_id}.json"), 'w') as f:
155
+ json.dump(item, f, indent=2)
156
+
157
+ archive_name = f"{container_name}_archive_{datetime.now().strftime('%Y%m%d%H%M%S')}"
158
+ shutil.make_archive(archive_name, 'zip', base_dir)
159
+
160
+ return get_base64_download_link(f"{archive_name}.zip", f"{archive_name}.zip")
161
+ except Exception as e:
162
+ return f"An error occurred while archiving data: {str(e)}"
163
+
164
+
165
+ # Modify the main app
166
+ def main():
167
+ st.title("🌟 Cosmos DB and GitHub Integration")
168
+
169
+ # Initialize session state
170
+ if 'logged_in' not in st.session_state:
171
+ st.session_state.logged_in = False
172
+ if 'selected_records' not in st.session_state:
173
+ st.session_state.selected_records = []
174
+ if 'client' not in st.session_state:
175
+ st.session_state.client = None
176
+ if 'selected_database' not in st.session_state:
177
+ st.session_state.selected_database = None
178
+ if 'selected_container' not in st.session_state:
179
+ st.session_state.selected_container = None
180
+
181
+ # Login section
182
+ if not st.session_state.logged_in:
183
+ st.subheader("πŸ” Login")
184
+ #input_key = st.text_input("Enter your Cosmos DB key", type="password")
185
+ input_key=Key
186
+
187
+ # Cosmos DB configuration
188
+ if st.button("πŸš€ Login"):
189
+ if input_key:
190
+ st.session_state.primary_key = input_key
191
+ st.session_state.logged_in = True
192
+ st.rerun()
193
+ else:
194
+ st.error("Invalid key. Please check your input.")
195
+ else:
196
+ # Initialize Cosmos DB client
197
+ try:
198
+ if st.session_state.client is None:
199
+ st.session_state.client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
200
+
201
+ # Sidebar for database, container, and document selection
202
+ st.sidebar.title("πŸ—„οΈ Cosmos DB Navigator")
203
+
204
+ databases = get_databases(st.session_state.client)
205
+ selected_db = st.sidebar.selectbox("πŸ—ƒοΈ Select Database", databases)
206
+
207
+ if selected_db != st.session_state.selected_database:
208
+ st.session_state.selected_database = selected_db
209
+ st.session_state.selected_container = None
210
+ st.rerun()
211
+
212
+ if st.session_state.selected_database:
213
+ database = st.session_state.client.get_database_client(st.session_state.selected_database)
214
+ containers = get_containers(database)
215
+ selected_container = st.sidebar.selectbox("πŸ“ Select Container", containers)
216
+
217
+ if selected_container != st.session_state.selected_container:
218
+ st.session_state.selected_container = selected_container
219
+ st.rerun()
220
+
221
+ if st.session_state.selected_container:
222
+ container = database.get_container_client(st.session_state.selected_container)
223
+
224
+ # Add Export button
225
+ if st.button("πŸ“¦ Export Container Data"):
226
+ download_link = archive_current_container(st.session_state.selected_database, st.session_state.selected_container, st.session_state.client)
227
+ if download_link.startswith('<a'):
228
+ st.markdown(download_link, unsafe_allow_html=True)
229
+ else:
230
+ st.error(download_link)
231
+
232
+ limit_to_1000 = st.sidebar.checkbox("πŸ”’ Limit to top 1000 documents", value=True)
233
+ documents = get_documents(container, limit=1000 if limit_to_1000 else None)
234
+
235
+ if documents:
236
+ document_ids = [doc.get('id', 'Unknown') for doc in documents]
237
+ selected_document = st.sidebar.selectbox("πŸ“„ Select Document", document_ids)
238
+
239
+ if selected_document:
240
+ st.subheader(f"πŸ“„ Document Details: {selected_document}")
241
+ selected_doc = next((doc for doc in documents if doc.get('id') == selected_document), None)
242
+ if selected_doc:
243
+ # Add Viewer/Editor selection
244
+ view_options = ['Show as Markdown', 'Show as Code Editor', 'Show as Edit and Save', 'Clone Document', 'New Record']
245
+ selected_view = st.selectbox("Select Viewer/Editor", view_options)
246
+
247
+ if selected_view == 'Show as Markdown':
248
+ # Show as Markdown
249
+ items = get_documents(container)
250
+ for item in items:
251
+ st.markdown(f"### ID: {item.get('id', 'Unknown')}")
252
+ content = item.get('content', '')
253
+ if isinstance(content, dict) or isinstance(content, list):
254
+ content = json.dumps(content, indent=2)
255
+ st.markdown(content)
256
+ elif selected_view == 'Show as Code Editor':
257
+ # Show as Code Editor
258
+ items = get_documents(container)
259
+ for item in items:
260
+ st.code(json.dumps(item, indent=2), language='python')
261
+ elif selected_view == 'Show as Edit and Save':
262
+ # Show as Edit and Save
263
+ doc_str = st.text_area("Edit Document", value=json.dumps(selected_doc, indent=2), height=300)
264
+ if st.button("πŸ’Ύ Save"):
265
+ try:
266
+ updated_doc = json.loads(doc_str)
267
+ success, message = update_record(updated_doc)
268
+ if success:
269
+ st.success(message)
270
+ else:
271
+ st.error(message)
272
+ except json.JSONDecodeError as e:
273
+ st.error(f"Invalid JSON: {str(e)}")
274
+ elif selected_view == 'Clone Document':
275
+ # Clone Document
276
+ if st.button("πŸ“„ Clone Document"):
277
+ cloned_doc = selected_doc.copy()
278
+ timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
279
+ cloned_doc['id'] = f"{cloned_doc['id']}_clone_{timestamp}"
280
+ success, message = insert_record(cloned_doc)
281
+ if success:
282
+ st.success(f"Document cloned with new id: {cloned_doc['id']}")
283
+ else:
284
+ st.error(message)
285
+ elif selected_view == 'New Record':
286
+ # New Record
287
+ new_doc_str = st.text_area("New Document", value='{}', height=300)
288
+ if st.button("βž• Create New Document"):
289
+ try:
290
+ new_doc = json.loads(new_doc_str)
291
+ if 'id' not in new_doc:
292
+ new_doc['id'] = f"new_doc_{datetime.now().strftime('%Y%m%d%H%M%S')}"
293
+ success, message = insert_record(new_doc)
294
+ if success:
295
+ st.success(f"New document created with id: {new_doc['id']}")
296
+ else:
297
+ st.error(message)
298
+ except json.JSONDecodeError as e:
299
+ st.error(f"Invalid JSON: {str(e)}")
300
+ else:
301
+ st.sidebar.info("No documents found in this container.")
302
+
303
+ # Main content area
304
+ st.subheader(f"πŸ“Š Container: {st.session_state.selected_container}")
305
+ if st.session_state.selected_container:
306
+ df = pd.DataFrame(documents)
307
+ st.dataframe(df)
308
+
309
+ # GitHub section
310
+ st.subheader("πŸ™ GitHub Operations")
311
+ github_token = os.environ.get("GITHUB") # Read GitHub token from environment variable
312
+ source_repo = st.text_input("Source GitHub Repository URL", value="https://github.com/AaronCWacker/AIExamples-8-24-Streamlit")
313
+ new_repo_name = st.text_input("New Repository Name (for cloning)", value=f"AIExample-Clone-{datetime.now().strftime('%Y%m%d_%H%M%S')}")
314
+
315
+ col1, col2 = st.columns(2)
316
+ with col1:
317
+ if st.button("πŸ“₯ Clone Repository"):
318
+ if github_token and source_repo:
319
+ try:
320
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
321
+ download_github_repo(source_repo, local_path)
322
+ zip_filename = f"{new_repo_name}.zip"
323
+ create_zip_file(local_path, zip_filename[:-4])
324
+ st.markdown(get_base64_download_link(zip_filename, zip_filename), unsafe_allow_html=True)
325
+ st.success("Repository cloned successfully!")
326
+ except Exception as e:
327
+ st.error(f"An error occurred: {str(e)}")
328
+ finally:
329
+ if os.path.exists(local_path):
330
+ shutil.rmtree(local_path)
331
+ if os.path.exists(zip_filename):
332
+ os.remove(zip_filename)
333
+ else:
334
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided.")
335
+
336
+ with col2:
337
+ if st.button("πŸ“€ Push to New Repository"):
338
+ if github_token and source_repo:
339
+ try:
340
+ g = Github(github_token)
341
+ new_repo = create_repo(g, new_repo_name)
342
+ local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
343
+ download_github_repo(source_repo, local_path)
344
+ push_to_github(local_path, new_repo, github_token)
345
+ st.success(f"Repository pushed successfully to {new_repo.html_url}")
346
+ except Exception as e:
347
+ st.error(f"An error occurred: {str(e)}")
348
+ finally:
349
+ if os.path.exists(local_path):
350
+ shutil.rmtree(local_path)
351
+ else:
352
+ st.error("Please ensure GitHub token is set in environment variables and source repository URL is provided.")
353
+
354
+ except exceptions.CosmosHttpResponseError as e:
355
+ st.error(f"Failed to connect to Cosmos DB. HTTP error: {str(e)}. Status code: {e.status_code}")
356
+ except Exception as e:
357
+ st.error(f"An unexpected error occurred: {str(e)}")
358
+
359
+ # Logout button
360
+ if st.session_state.logged_in and st.sidebar.button("πŸšͺ Logout"):
361
+ st.session_state.logged_in = False
362
+ st.session_state.selected_records.clear()
363
+ st.session_state.client = None
364
+ st.session_state.selected_database = None
365
+ st.session_state.selected_container = None
366
+ st.rerun()
367
+
368
+ if __name__ == "__main__":
369
+ main()