Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -15,7 +15,7 @@ import traceback
|
|
15 |
import uuid
|
16 |
import zipfile
|
17 |
from PIL import Image
|
18 |
-
from azure.cosmos import CosmosClient, exceptions
|
19 |
from datetime import datetime
|
20 |
from git import Repo
|
21 |
from github import Github
|
@@ -187,42 +187,23 @@ def update_record(container, updated_record):
|
|
187 |
|
188 |
# ποΈ Delete a record from Cosmos DB using /id as partition key
|
189 |
def delete_record(container, record):
|
190 |
-
"""
|
191 |
-
Delete a record from Cosmos DB using its 'id' field as both the item ID and partition key.
|
192 |
-
|
193 |
-
Args:
|
194 |
-
container: Cosmos DB container client
|
195 |
-
record: Dictionary containing at least 'id'
|
196 |
-
|
197 |
-
Returns:
|
198 |
-
tuple: (success: bool, message: str)
|
199 |
-
"""
|
200 |
try:
|
201 |
-
# Ensure record has an ID
|
202 |
if "id" not in record:
|
203 |
return False, "Record must contain an 'id' field. π"
|
204 |
-
|
205 |
doc_id = record["id"]
|
206 |
-
|
207 |
-
# Log the document being deleted (persistent in session state)
|
208 |
if "delete_log" not in st.session_state:
|
209 |
st.session_state.delete_log = []
|
210 |
st.session_state.delete_log.append(f"Attempting to delete document: {json.dumps(record, indent=2)}")
|
211 |
-
|
212 |
-
# Use 'id' as the partition key since container is partitioned on /id
|
213 |
partition_key_value = doc_id
|
214 |
st.session_state.delete_log.append(f"Using ID and Partition Key: {partition_key_value}")
|
215 |
-
|
216 |
-
# Perform the deletion
|
217 |
container.delete_item(item=doc_id, partition_key=partition_key_value)
|
218 |
success_msg = f"Record {doc_id} successfully deleted from Cosmos DB. ποΈ"
|
219 |
st.session_state.delete_log.append(success_msg)
|
220 |
return True, success_msg
|
221 |
-
|
222 |
except exceptions.CosmosResourceNotFoundError:
|
223 |
success_msg = f"Record {doc_id} not found in Cosmos DB (already deleted or never existed). ποΈ"
|
224 |
st.session_state.delete_log.append(success_msg)
|
225 |
-
return True, success_msg
|
226 |
except exceptions.CosmosHttpResponseError as e:
|
227 |
error_msg = f"HTTP error deleting {doc_id}: {str(e)}. π¨"
|
228 |
st.session_state.delete_log.append(error_msg)
|
@@ -279,23 +260,75 @@ def archive_current_container(database_name, container_name, client):
|
|
279 |
except Exception as e:
|
280 |
return f"Archive error: {str(e)} π’"
|
281 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
# %% βββββββββββββ GITHUB FUNCTIONS βββββββββββββ
|
283 |
-
# π₯ Clone a GitHub repository locally
|
284 |
def download_github_repo(url, local_path):
|
285 |
if os.path.exists(local_path):
|
286 |
shutil.rmtree(local_path)
|
287 |
Repo.clone_from(url, local_path)
|
288 |
|
289 |
-
# ποΈ Zip a directory
|
290 |
def create_zip_file(source_dir, output_filename):
|
291 |
shutil.make_archive(output_filename, 'zip', source_dir)
|
292 |
|
293 |
-
# ποΈ Create a new GitHub repo via API
|
294 |
def create_repo(g, repo_name):
|
295 |
user = g.get_user()
|
296 |
return user.create_repo(repo_name)
|
297 |
|
298 |
-
# π Push local repo changes to GitHub
|
299 |
def push_to_github(local_path, repo, github_token):
|
300 |
repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
|
301 |
local_repo = Repo(local_path)
|
@@ -315,7 +348,6 @@ def push_to_github(local_path, repo, github_token):
|
|
315 |
origin.push(refspec=f'{current_branch}:{current_branch}')
|
316 |
|
317 |
# %% βββββββββββββ FILE & MEDIA MANAGEMENT FUNCTIONS βββββββββββββ
|
318 |
-
# π List saved Markdown files in sidebar with actions
|
319 |
def display_saved_files_in_sidebar():
|
320 |
all_files = sorted([f for f in glob.glob("*.md") if not f.lower().startswith('readme')], reverse=True)
|
321 |
st.sidebar.markdown("## π Files")
|
@@ -334,7 +366,6 @@ def display_saved_files_in_sidebar():
|
|
334 |
os.remove(file)
|
335 |
st.rerun()
|
336 |
|
337 |
-
# π Display file viewer in main area
|
338 |
def display_file_viewer(file_path):
|
339 |
content = load_file(file_path)
|
340 |
if content:
|
@@ -346,7 +377,6 @@ def display_file_viewer(file_path):
|
|
346 |
st.markdown(content)
|
347 |
st.download_button("β¬οΈ", data=content, file_name=os.path.basename(file_path), mime="text/markdown")
|
348 |
|
349 |
-
# βοΈ Display file editor (Markdown & Code)
|
350 |
def display_file_editor(file_path):
|
351 |
if 'file_content' not in st.session_state:
|
352 |
st.session_state.file_content = {}
|
@@ -374,7 +404,6 @@ def display_file_editor(file_path):
|
|
374 |
with col2:
|
375 |
st.download_button("β¬οΈ", data=new_content, file_name=os.path.basename(file_path), mime="text/markdown")
|
376 |
|
377 |
-
# πΎ Save content to a file (with error handling)
|
378 |
def save_file_content(file_path, content):
|
379 |
try:
|
380 |
with open(file_path, 'w', encoding='utf-8') as file:
|
@@ -384,7 +413,6 @@ def save_file_content(file_path, content):
|
|
384 |
st.error(f"Save error: {str(e)}")
|
385 |
return False
|
386 |
|
387 |
-
# ποΈ Update file management UI section (view, edit, delete)
|
388 |
def update_file_management_section():
|
389 |
if 'file_view_mode' not in st.session_state:
|
390 |
st.session_state.file_view_mode = None
|
@@ -449,7 +477,6 @@ def update_file_management_section():
|
|
449 |
display_file_editor(st.session_state.current_file)
|
450 |
|
451 |
# %% βββββββββββββ VIDEO & AUDIO UI FUNCTIONS βββββββββββββ
|
452 |
-
# πΌοΈ Validate and preprocess an image for video generation
|
453 |
def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
|
454 |
try:
|
455 |
st.write("Preprocessing image...")
|
@@ -484,7 +511,6 @@ def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
|
|
484 |
st.error(f"Image error: {str(e)}")
|
485 |
return None
|
486 |
|
487 |
-
# βΆοΈ Add video generation UI with Gradio client
|
488 |
def add_video_generation_ui(container):
|
489 |
st.markdown("### π₯ Video Gen")
|
490 |
col1, col2 = st.columns([2, 1])
|
@@ -564,7 +590,6 @@ def add_video_generation_ui(container):
|
|
564 |
st.error(f"Upload error: {str(e)}")
|
565 |
|
566 |
# %% βββββββββββββ MAIN FUNCTION βββββββββββββ
|
567 |
-
# π Main app entry point
|
568 |
def main():
|
569 |
st.markdown("### π GitCosmos - Cosmos & Git Hub")
|
570 |
if "chat_history" not in st.session_state:
|
@@ -666,11 +691,9 @@ def main():
|
|
666 |
st.error(message)
|
667 |
except Exception as e:
|
668 |
st.error(f"Delete err: {str(e)}")
|
669 |
-
|
670 |
-
# Display delete log persistently
|
671 |
if "delete_log" in st.session_state and st.session_state.delete_log:
|
672 |
st.subheader("Delete Log")
|
673 |
-
for log_entry in st.session_state.delete_log[-5:]:
|
674 |
st.write(log_entry)
|
675 |
elif selected_view == 'Run AI':
|
676 |
st.markdown("#### π€ Run AI (stub)")
|
@@ -753,7 +776,82 @@ def main():
|
|
753 |
st.dataframe(df)
|
754 |
else:
|
755 |
st.info("No docs.")
|
756 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
757 |
st.subheader("π GitHub Ops")
|
758 |
github_token = os.environ.get("GITHUB")
|
759 |
source_repo = st.text_input("Source Repo URL", value="https://github.com/AaronCWacker/AIExamples-8-24-Streamlit")
|
@@ -795,7 +893,6 @@ def main():
|
|
795 |
shutil.rmtree(local_path)
|
796 |
else:
|
797 |
st.error("Missing token or URL πβ")
|
798 |
-
# --- File Management Section ---
|
799 |
update_file_management_section()
|
800 |
except exceptions.CosmosHttpResponseError as e:
|
801 |
st.error(f"Cosmos error: {str(e)} π¨")
|
|
|
15 |
import uuid
|
16 |
import zipfile
|
17 |
from PIL import Image
|
18 |
+
from azure.cosmos import CosmosClient, PartitionKey, exceptions
|
19 |
from datetime import datetime
|
20 |
from git import Repo
|
21 |
from github import Github
|
|
|
187 |
|
188 |
# ποΈ Delete a record from Cosmos DB using /id as partition key
|
189 |
def delete_record(container, record):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
try:
|
|
|
191 |
if "id" not in record:
|
192 |
return False, "Record must contain an 'id' field. π"
|
|
|
193 |
doc_id = record["id"]
|
|
|
|
|
194 |
if "delete_log" not in st.session_state:
|
195 |
st.session_state.delete_log = []
|
196 |
st.session_state.delete_log.append(f"Attempting to delete document: {json.dumps(record, indent=2)}")
|
|
|
|
|
197 |
partition_key_value = doc_id
|
198 |
st.session_state.delete_log.append(f"Using ID and Partition Key: {partition_key_value}")
|
|
|
|
|
199 |
container.delete_item(item=doc_id, partition_key=partition_key_value)
|
200 |
success_msg = f"Record {doc_id} successfully deleted from Cosmos DB. ποΈ"
|
201 |
st.session_state.delete_log.append(success_msg)
|
202 |
return True, success_msg
|
|
|
203 |
except exceptions.CosmosResourceNotFoundError:
|
204 |
success_msg = f"Record {doc_id} not found in Cosmos DB (already deleted or never existed). ποΈ"
|
205 |
st.session_state.delete_log.append(success_msg)
|
206 |
+
return True, success_msg
|
207 |
except exceptions.CosmosHttpResponseError as e:
|
208 |
error_msg = f"HTTP error deleting {doc_id}: {str(e)}. π¨"
|
209 |
st.session_state.delete_log.append(error_msg)
|
|
|
260 |
except Exception as e:
|
261 |
return f"Archive error: {str(e)} π’"
|
262 |
|
263 |
+
# %% βββββββββββββ ADVANCED COSMOS FUNCTIONS βββββββββββββ
|
264 |
+
def create_new_container(database, container_id, partition_key_path,
|
265 |
+
analytical_storage_ttl=None, indexing_policy=None, vector_embedding_policy=None):
|
266 |
+
try:
|
267 |
+
if analytical_storage_ttl is not None:
|
268 |
+
container = database.create_container(
|
269 |
+
id=container_id,
|
270 |
+
partition_key=PartitionKey(path=partition_key_path),
|
271 |
+
analytical_storage_ttl=analytical_storage_ttl,
|
272 |
+
indexing_policy=indexing_policy,
|
273 |
+
vector_embedding_policy=vector_embedding_policy
|
274 |
+
)
|
275 |
+
else:
|
276 |
+
container = database.create_container(
|
277 |
+
id=container_id,
|
278 |
+
partition_key=PartitionKey(path=partition_key_path),
|
279 |
+
indexing_policy=indexing_policy,
|
280 |
+
vector_embedding_policy=vector_embedding_policy
|
281 |
+
)
|
282 |
+
except exceptions.CosmosResourceExistsError:
|
283 |
+
container = database.get_container_client(container_id)
|
284 |
+
except exceptions.CosmosHttpResponseError as e:
|
285 |
+
st.error(f"Error creating container: {str(e)}")
|
286 |
+
return None
|
287 |
+
return container
|
288 |
+
|
289 |
+
def advanced_insert_item(container, item):
|
290 |
+
try:
|
291 |
+
container.upsert_item(item)
|
292 |
+
return True, f"Item {item.get('id', '')} inserted. β"
|
293 |
+
except Exception as e:
|
294 |
+
return False, str(e)
|
295 |
+
|
296 |
+
def advanced_update_item(container, item):
|
297 |
+
try:
|
298 |
+
container.upsert_item(item)
|
299 |
+
return True, f"Item {item.get('id', '')} updated. βοΈ"
|
300 |
+
except Exception as e:
|
301 |
+
return False, str(e)
|
302 |
+
|
303 |
+
def advanced_delete_item(container, item_id, partition_key_value):
|
304 |
+
try:
|
305 |
+
container.delete_item(item=item_id, partition_key=partition_key_value)
|
306 |
+
return True, f"Item {item_id} deleted. ποΈ"
|
307 |
+
except Exception as e:
|
308 |
+
return False, str(e)
|
309 |
+
|
310 |
+
def vector_search(container, query_vector, vector_field, top=10, exact_search=False):
|
311 |
+
# Convert the vector list to a JSON string
|
312 |
+
query_vector_str = json.dumps(query_vector)
|
313 |
+
query = f"""SELECT TOP {top} c.id, VectorDistance(c.{vector_field}, {query_vector_str}, {str(exact_search).lower()},
|
314 |
+
{{'dataType':'float32','distanceFunction':'cosine'}}) AS SimilarityScore
|
315 |
+
FROM c ORDER BY SimilarityScore"""
|
316 |
+
results = list(container.query_items(query=query, enable_cross_partition_query=True))
|
317 |
+
return results
|
318 |
+
|
319 |
# %% βββββββββββββ GITHUB FUNCTIONS βββββββββββββ
|
|
|
320 |
def download_github_repo(url, local_path):
|
321 |
if os.path.exists(local_path):
|
322 |
shutil.rmtree(local_path)
|
323 |
Repo.clone_from(url, local_path)
|
324 |
|
|
|
325 |
def create_zip_file(source_dir, output_filename):
|
326 |
shutil.make_archive(output_filename, 'zip', source_dir)
|
327 |
|
|
|
328 |
def create_repo(g, repo_name):
|
329 |
user = g.get_user()
|
330 |
return user.create_repo(repo_name)
|
331 |
|
|
|
332 |
def push_to_github(local_path, repo, github_token):
|
333 |
repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
|
334 |
local_repo = Repo(local_path)
|
|
|
348 |
origin.push(refspec=f'{current_branch}:{current_branch}')
|
349 |
|
350 |
# %% βββββββββββββ FILE & MEDIA MANAGEMENT FUNCTIONS βββββββββββββ
|
|
|
351 |
def display_saved_files_in_sidebar():
|
352 |
all_files = sorted([f for f in glob.glob("*.md") if not f.lower().startswith('readme')], reverse=True)
|
353 |
st.sidebar.markdown("## π Files")
|
|
|
366 |
os.remove(file)
|
367 |
st.rerun()
|
368 |
|
|
|
369 |
def display_file_viewer(file_path):
|
370 |
content = load_file(file_path)
|
371 |
if content:
|
|
|
377 |
st.markdown(content)
|
378 |
st.download_button("β¬οΈ", data=content, file_name=os.path.basename(file_path), mime="text/markdown")
|
379 |
|
|
|
380 |
def display_file_editor(file_path):
|
381 |
if 'file_content' not in st.session_state:
|
382 |
st.session_state.file_content = {}
|
|
|
404 |
with col2:
|
405 |
st.download_button("β¬οΈ", data=new_content, file_name=os.path.basename(file_path), mime="text/markdown")
|
406 |
|
|
|
407 |
def save_file_content(file_path, content):
|
408 |
try:
|
409 |
with open(file_path, 'w', encoding='utf-8') as file:
|
|
|
413 |
st.error(f"Save error: {str(e)}")
|
414 |
return False
|
415 |
|
|
|
416 |
def update_file_management_section():
|
417 |
if 'file_view_mode' not in st.session_state:
|
418 |
st.session_state.file_view_mode = None
|
|
|
477 |
display_file_editor(st.session_state.current_file)
|
478 |
|
479 |
# %% βββββββββββββ VIDEO & AUDIO UI FUNCTIONS βββββββββββββ
|
|
|
480 |
def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
|
481 |
try:
|
482 |
st.write("Preprocessing image...")
|
|
|
511 |
st.error(f"Image error: {str(e)}")
|
512 |
return None
|
513 |
|
|
|
514 |
def add_video_generation_ui(container):
|
515 |
st.markdown("### π₯ Video Gen")
|
516 |
col1, col2 = st.columns([2, 1])
|
|
|
590 |
st.error(f"Upload error: {str(e)}")
|
591 |
|
592 |
# %% βββββββββββββ MAIN FUNCTION βββββββββββββ
|
|
|
593 |
def main():
|
594 |
st.markdown("### π GitCosmos - Cosmos & Git Hub")
|
595 |
if "chat_history" not in st.session_state:
|
|
|
691 |
st.error(message)
|
692 |
except Exception as e:
|
693 |
st.error(f"Delete err: {str(e)}")
|
|
|
|
|
694 |
if "delete_log" in st.session_state and st.session_state.delete_log:
|
695 |
st.subheader("Delete Log")
|
696 |
+
for log_entry in st.session_state.delete_log[-5:]:
|
697 |
st.write(log_entry)
|
698 |
elif selected_view == 'Run AI':
|
699 |
st.markdown("#### π€ Run AI (stub)")
|
|
|
776 |
st.dataframe(df)
|
777 |
else:
|
778 |
st.info("No docs.")
|
779 |
+
|
780 |
+
# βββββ Advanced Cosmos Ops βββββ
|
781 |
+
with st.sidebar.expander("Advanced Cosmos Ops"):
|
782 |
+
st.markdown("### Advanced Cosmos Operations")
|
783 |
+
# Create Container
|
784 |
+
with st.form("create_container_form"):
|
785 |
+
container_id = st.text_input("Container ID", value="newContainer")
|
786 |
+
partition_key_path = st.text_input("Partition Key Path", value="/id")
|
787 |
+
analytical = st.checkbox("Enable Analytical Store", value=False)
|
788 |
+
submitted = st.form_submit_button("π Create Container")
|
789 |
+
if submitted:
|
790 |
+
analytical_ttl = -1 if analytical else None
|
791 |
+
new_container = create_new_container(database, container_id, partition_key_path,
|
792 |
+
analytical_storage_ttl=analytical_ttl)
|
793 |
+
if new_container:
|
794 |
+
st.success(f"Container '{container_id}' created.")
|
795 |
+
else:
|
796 |
+
st.error("Container creation failed.")
|
797 |
+
|
798 |
+
# Insert Item
|
799 |
+
with st.form("insert_item_form"):
|
800 |
+
item_json = st.text_area("Item JSON", value='{"id": "itemX", "productName": "Widget", "productModel": "Model X"}')
|
801 |
+
submitted = st.form_submit_button("β Insert Item")
|
802 |
+
if submitted:
|
803 |
+
try:
|
804 |
+
item = json.loads(item_json)
|
805 |
+
success, msg = advanced_insert_item(container, item)
|
806 |
+
if success:
|
807 |
+
st.success(msg)
|
808 |
+
else:
|
809 |
+
st.error(msg)
|
810 |
+
except Exception as e:
|
811 |
+
st.error(str(e))
|
812 |
+
|
813 |
+
# Update Item
|
814 |
+
with st.form("update_item_form"):
|
815 |
+
update_json = st.text_area("Update Item JSON", value='{"id": "itemX", "productName": "Widget", "productModel": "Updated Model"}')
|
816 |
+
submitted = st.form_submit_button("βοΈ Update Item")
|
817 |
+
if submitted:
|
818 |
+
try:
|
819 |
+
item = json.loads(update_json)
|
820 |
+
success, msg = advanced_update_item(container, item)
|
821 |
+
if success:
|
822 |
+
st.success(msg)
|
823 |
+
else:
|
824 |
+
st.error(msg)
|
825 |
+
except Exception as e:
|
826 |
+
st.error(str(e))
|
827 |
+
|
828 |
+
# Delete Item
|
829 |
+
with st.form("delete_item_form"):
|
830 |
+
del_item_id = st.text_input("Item ID to delete", value="itemX")
|
831 |
+
del_partition = st.text_input("Partition Key Value", value="Widget")
|
832 |
+
submitted = st.form_submit_button("ποΈ Delete Item")
|
833 |
+
if submitted:
|
834 |
+
success, msg = advanced_delete_item(container, del_item_id, del_partition)
|
835 |
+
if success:
|
836 |
+
st.success(msg)
|
837 |
+
else:
|
838 |
+
st.error(msg)
|
839 |
+
|
840 |
+
# Vector Search
|
841 |
+
with st.form("vector_search_form"):
|
842 |
+
vector_str = st.text_input("Query Vector (comma separated)", value="0.1, 0.2, 0.3, 0.4")
|
843 |
+
top_n = st.number_input("Top N Results", min_value=1, max_value=100, value=10)
|
844 |
+
vector_field = st.text_input("Vector Field", value="vector")
|
845 |
+
submitted = st.form_submit_button("π Vector Search")
|
846 |
+
if submitted:
|
847 |
+
try:
|
848 |
+
query_vector = [float(x.strip()) for x in vector_str.split(",") if x.strip()]
|
849 |
+
results = vector_search(container, query_vector, vector_field, top=top_n)
|
850 |
+
st.write(results)
|
851 |
+
except Exception as e:
|
852 |
+
st.error(str(e))
|
853 |
+
|
854 |
+
# βββββ End Advanced Ops βββββ
|
855 |
st.subheader("π GitHub Ops")
|
856 |
github_token = os.environ.get("GITHUB")
|
857 |
source_repo = st.text_input("Source Repo URL", value="https://github.com/AaronCWacker/AIExamples-8-24-Streamlit")
|
|
|
893 |
shutil.rmtree(local_path)
|
894 |
else:
|
895 |
st.error("Missing token or URL πβ")
|
|
|
896 |
update_file_management_section()
|
897 |
except exceptions.CosmosHttpResponseError as e:
|
898 |
st.error(f"Cosmos error: {str(e)} π¨")
|