awacke1 commited on
Commit
dcea03e
Β·
verified Β·
1 Parent(s): 3c303ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +502 -339
app.py CHANGED
@@ -1,4 +1,7 @@
1
- # πŸ“šπŸ“šπŸ“š IMPORTS πŸ“šπŸ“šπŸ“š
 
 
 
2
  import base64
3
  import glob
4
  import hashlib
@@ -26,7 +29,9 @@ import requests
26
  import numpy as np
27
  from urllib.parse import quote
28
 
29
- # 🌐🌐🌐 EXTERNAL HELP LINKS (Always visible in sidebar) 🌐🌐🌐
 
 
30
  external_links = [
31
  {"title": "CosmosDB GenAI Full Text Search", "url": "https://learn.microsoft.com/en-us/azure/cosmos-db/gen-ai/full-text-search", "emoji": "πŸ’»"},
32
  {"title": "CosmosDB SQL API Client Library", "url": "https://learn.microsoft.com/en-us/python/api/overview/azure/cosmos-readme?view=azure-python", "emoji": "πŸ’»"},
@@ -41,7 +46,9 @@ external_links = [
41
  {"title": "arcee.ai Official Website", "url": "https://arcee.ai", "emoji": "🌐"},
42
  ]
43
 
44
- # πŸš€πŸš€πŸš€ APP CONFIGURATION πŸš€πŸš€πŸš€
 
 
45
  Site_Name = 'πŸ™ GitCosmos'
46
  title = "πŸ™ GitCosmos"
47
  helpURL = 'https://huggingface.co/awacke1'
@@ -59,7 +66,7 @@ st.set_page_config(
59
  }
60
  )
61
 
62
- # 🌌🌌🌌 COSMOS DB & APP CONFIGURATION 🌌🌌🌌
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")
@@ -67,7 +74,9 @@ Key = os.environ.get("Key")
67
  LOCAL_APP_URL = "https://huggingface.co/spaces/awacke1/AzureCosmosDBUI"
68
  CosmosDBUrl = 'https://portal.azure.com/#@AaronCWackergmail.onmicrosoft.com/resource/subscriptions/003fba60-5b3f-48f4-ab36-3ed11bc40816/resourceGroups/datasets/providers/Microsoft.DocumentDB/databaseAccounts/acae-afd/dataExplorer'
69
 
70
- # πŸ”§πŸ”§πŸ”§ HELPER FUNCTIONS πŸ”§πŸ”§πŸ”§
 
 
71
  def get_download_link(file_path):
72
  with open(file_path, "rb") as file:
73
  contents = file.read()
@@ -141,12 +150,17 @@ def preprocess_text(text):
141
  text = re.sub(r'[^\x00-\x7F]+', '', text)
142
  return text.strip()
143
 
 
144
  def sanitize_json_text(text):
 
145
  text = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F]', '', text)
 
146
  text = text.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
147
  return text
148
 
149
- # 🌌🌌🌌 COSMOS DB FUNCTIONS 🌌🌌🌌
 
 
150
  def get_databases(client):
151
  return [db['id'] for db in client.list_databases()]
152
 
@@ -181,15 +195,52 @@ def delete_record(container, record):
181
  if "id" not in record:
182
  return False, "Record must contain an 'id' field. πŸ›‘"
183
  doc_id = record["id"]
 
 
 
184
  partition_key_value = record.get("pk", doc_id)
 
185
  container.delete_item(item=doc_id, partition_key=partition_key_value)
186
- return True, f"Record {doc_id} successfully deleted from Cosmos DB. πŸ—‘οΈ"
 
 
187
  except exceptions.CosmosResourceNotFoundError:
188
- return True, f"Record {doc_id} not found in Cosmos DB (already deleted or never existed). πŸ—‘οΈ"
 
 
189
  except exceptions.CosmosHttpResponseError as e:
190
- return False, f"HTTP error deleting {doc_id}: {str(e)}. 🚨"
 
 
191
  except Exception as e:
192
- return False, f"Unexpected error deleting {doc_id}: {str(traceback.format_exc())}. 😱"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  def archive_current_container(database_name, container_name, client):
195
  try:
@@ -212,273 +263,111 @@ def archive_current_container(database_name, container_name, client):
212
  except Exception as e:
213
  return f"Archive error: {str(e)} 😒"
214
 
215
- # 🌠🌠🌠 ADVANCED COSMOS FUNCTIONS (if needed) 🌠🌠🌠
216
- # (Include your advanced Cosmos functions here if needed)
217
- # For example, you might have functions like create_new_container(), etc.
218
-
219
- # πŸŽ‰πŸŽ‰πŸŽ‰ NEW COSMOSDB DEMO FUNCTIONS (Using ENDPOINT and Key) πŸŽ‰πŸŽ‰πŸŽ‰
220
- def demo_create_database():
221
- st.markdown("### Demo: Create Database")
222
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_name")
223
- if st.button("Create Database", key="btn_create_db"):
224
- if not ENDPOINT or not Key:
225
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
226
- return
227
- client_demo = CosmosClient(ENDPOINT, credential=Key)
228
- try:
229
- database = client_demo.create_database(database_name)
230
- st.success(f"Database '{database_name}' created.")
231
- st.write(database)
232
- except exceptions.CosmosResourceExistsError:
233
- database = client_demo.get_database_client(database_name)
234
- st.info(f"Database '{database_name}' already exists.")
235
- st.write(database)
236
- except Exception as e:
237
- st.error(f"Error: {str(e)}")
238
-
239
- def demo_create_container():
240
- st.markdown("### Demo: Create Container")
241
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_for_container")
242
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_name")
243
- partition_key = st.text_input("Enter Partition Key Path", value="/productName", key="demo_partition_key")
244
- if st.button("Create Container", key="btn_create_container"):
245
- if not ENDPOINT or not Key:
246
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
247
- return
248
- client_demo = CosmosClient(ENDPOINT, credential=Key)
249
- try:
250
- database = client_demo.get_database_client(database_name)
251
- container = database.create_container(id=container_name, partition_key=PartitionKey(path=partition_key))
252
- st.success(f"Container '{container_name}' created.")
253
- st.write(container)
254
- except exceptions.CosmosResourceExistsError:
255
- container = database.get_container_client(container_name)
256
- st.info(f"Container '{container_name}' already exists.")
257
- st.write(container)
258
- except exceptions.CosmosHttpResponseError as e:
259
- st.error(f"HTTP error: {str(e)}")
260
- except Exception as e:
261
- st.error(f"Error: {str(e)}")
262
-
263
- def demo_create_analytical_container():
264
- st.markdown("### Demo: Create Analytical Store Enabled Container")
265
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_for_analytical")
266
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_analytical")
267
- partition_key = st.text_input("Enter Partition Key Path", value="/productName", key="demo_partition_key_analytical")
268
- if st.button("Create Analytical Container", key="btn_create_analytical"):
269
- if not ENDPOINT or not Key:
270
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
271
- return
272
- client_demo = CosmosClient(ENDPOINT, credential=Key)
273
- try:
274
- database = client_demo.get_database_client(database_name)
275
  container = database.create_container(
276
- id=container_name,
277
- partition_key=PartitionKey(path=partition_key),
278
- analytical_storage_ttl=-1
 
 
279
  )
280
- st.success(f"Analytical container '{container_name}' created.")
281
- st.write(container)
282
- except exceptions.CosmosResourceExistsError:
283
- container = database.get_container_client(container_name)
284
- st.info(f"Container '{container_name}' already exists.")
285
- st.write(container)
286
- except exceptions.CosmosHttpResponseError as e:
287
- st.error(f"HTTP error: {str(e)}")
288
- except Exception as e:
289
- st.error(f"Error: {str(e)}")
290
-
291
- def demo_get_existing_container():
292
- st.markdown("### Demo: Get Existing Container")
293
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_get")
294
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_get")
295
- if st.button("Get Container", key="btn_get_container"):
296
- if not ENDPOINT or not Key:
297
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
298
- return
299
- client_demo = CosmosClient(ENDPOINT, credential=Key)
300
- try:
301
- database = client_demo.get_database_client(database_name)
302
- container = database.get_container_client(container_name)
303
- st.success(f"Retrieved container '{container_name}'.")
304
- st.write(container)
305
- except Exception as e:
306
- st.error(f"Error: {str(e)}")
307
 
308
- def demo_insert_data():
309
- st.markdown("### Demo: Insert Data")
310
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_insert")
311
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_insert")
312
- num_items = st.number_input("Number of items to insert", min_value=1, max_value=20, value=9, key="demo_num_items")
313
- if st.button("Insert Data", key="btn_insert_data"):
314
- if not ENDPOINT or not Key:
315
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
316
- return
317
- client_demo = CosmosClient(ENDPOINT, credential=Key)
318
- try:
319
- database = client_demo.get_database_client(database_name)
320
- container = database.get_container_client(container_name)
321
- for i in range(1, int(num_items) + 1):
322
- container.upsert_item({
323
- 'id': f'item{i}',
324
- 'productName': 'Widget',
325
- 'productModel': f'Model {i}'
326
- })
327
- st.success(f"Inserted {num_items} items.")
328
- except Exception as e:
329
- st.error(f"Error: {str(e)}")
330
 
331
- def demo_delete_data():
332
- st.markdown("### Demo: Delete Data")
333
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_delete")
334
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_delete")
335
- query_model = st.text_input("Product Model to delete", value="Model 2", key="demo_query_model")
336
- if st.button("Delete Data", key="btn_delete_data"):
337
- if not ENDPOINT or not Key:
338
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
339
- return
340
- client_demo = CosmosClient(ENDPOINT, credential=Key)
341
- try:
342
- database = client_demo.get_database_client(database_name)
343
- container = database.get_container_client(container_name)
344
- items = list(container.query_items(
345
- query=f'SELECT * FROM products p WHERE p.productModel = "{query_model}"',
346
- enable_cross_partition_query=True
347
- ))
348
- count = 0
349
- for item in items:
350
- container.delete_item(item, partition_key=item.get("productName", "Widget"))
351
- count += 1
352
- st.success(f"Deleted {count} items with productModel = '{query_model}'.")
353
- except Exception as e:
354
- st.error(f"Error: {str(e)}")
355
 
356
- def demo_query_database():
357
- st.markdown("### Demo: Query Database")
358
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_query")
359
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_query")
360
- query_str = st.text_area("Enter SQL Query", value='SELECT * FROM mycontainer r WHERE r.id="item3"', key="demo_query_str")
361
- if st.button("Run Query", key="btn_query_database"):
362
- if not ENDPOINT or not Key:
363
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
364
- return
365
- client_demo = CosmosClient(ENDPOINT, credential=Key)
366
- try:
367
- database = client_demo.get_database_client(database_name)
368
- container = database.get_container_client(container_name)
369
- results = list(container.query_items(query=query_str, enable_cross_partition_query=True))
370
- if results:
371
- for item in results:
372
- st.json(item)
373
- else:
374
- st.info("No results found.")
375
- except Exception as e:
376
- st.error(f"Error: {str(e)}")
377
 
378
- def demo_parameterized_query():
379
- st.markdown("### Demo: Parameterized Query")
380
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_param")
381
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_param")
382
- model_value = st.text_input("Enter productModel value", value="Model 7", key="demo_model_value")
383
- if st.button("Run Parameterized Query", key="btn_param_query"):
384
- if not ENDPOINT or not Key:
385
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
386
- return
387
- client_demo = CosmosClient(ENDPOINT, credential=Key)
388
- try:
389
- database = client_demo.get_database_client(database_name)
390
- container = database.get_container_client(container_name)
391
- discontinued_items = container.query_items(
392
- query='SELECT * FROM products p WHERE p.productModel = @model',
393
- parameters=[{"name": "@model", "value": model_value}],
394
- enable_cross_partition_query=True
395
- )
396
- for item in discontinued_items:
397
- st.json(item)
398
- except Exception as e:
399
- st.error(f"Error: {str(e)}")
400
 
401
- def demo_get_db_properties():
402
- st.markdown("### Demo: Get Database Properties")
403
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_props")
404
- if st.button("Get Properties", key="btn_db_props"):
405
- if not ENDPOINT or not Key:
406
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
407
- return
408
- client_demo = CosmosClient(ENDPOINT, credential=Key)
409
- try:
410
- database = client_demo.get_database_client(database_name)
411
- props = database.read()
412
- st.json(props)
413
- except Exception as e:
414
- st.error(f"Error: {str(e)}")
415
 
416
- def demo_get_throughput():
417
- st.markdown("### Demo: Get Throughput (Database & Container)")
418
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_throughput")
419
- container_name = st.text_input("Enter Container Name (for container throughput)", value="testContainer", key="demo_container_throughput")
420
- if st.button("Get Throughput", key="btn_get_throughput"):
421
- if not ENDPOINT or not Key:
422
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
423
- return
424
- client_demo = CosmosClient(ENDPOINT, credential=Key)
425
- try:
426
- database = client_demo.get_database_client(database_name)
427
- db_offer = database.get_throughput()
428
- st.write(f"Database Offer: {db_offer.properties['id']} with throughput {db_offer.properties['content']['offerThroughput']}")
429
- try:
430
- container = database.get_container_client(container_name)
431
- container_offer = container.get_throughput()
432
- st.write(f"Container Offer: {container_offer.properties['id']} with throughput {container_offer.properties['content']['offerThroughput']}")
433
- except exceptions.CosmosHttpResponseError as e:
434
- st.error(f"Container throughput error: {str(e)}")
435
- except Exception as e:
436
- st.error(f"Error: {str(e)}")
437
 
438
- def demo_modify_container_properties():
439
- st.markdown("### Demo: Modify Container Properties (Set default TTL)")
440
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_modify")
441
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_modify")
442
- new_ttl = st.number_input("Enter new default TTL (seconds)", min_value=0, value=10, key="demo_new_ttl")
443
- if st.button("Modify Container", key="btn_modify_container"):
444
- if not ENDPOINT or not Key:
445
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
446
- return
447
- client_demo = CosmosClient(ENDPOINT, credential=Key)
448
- try:
449
- database = client_demo.get_database_client(database_name)
450
- container = database.get_container_client(container_name)
451
- # Using replace_container as in your snippet.
452
- database.replace_container(
453
- container,
454
- partition_key=PartitionKey(path="/productName"),
455
- default_ttl=new_ttl,
456
- )
457
- container_props = container.read()
458
- st.write("New default TTL:", container_props.get("defaultTtl"))
459
- except Exception as e:
460
- st.error(f"Error: {str(e)}")
461
 
462
- def demo_item_response_headers():
463
- st.markdown("### Demo: Using Item Point Operation Response Headers")
464
- database_name = st.text_input("Enter Database Name", value="testDatabase", key="demo_db_headers")
465
- container_name = st.text_input("Enter Container Name", value="products", key="demo_container_headers")
466
- if st.button("Create Item & Show Headers", key="btn_item_headers"):
467
- if not ENDPOINT or not Key:
468
- st.error("Missing Cosmos configuration: ENDPOINT or Key")
469
- return
470
- client_demo = CosmosClient(ENDPOINT, credential=Key)
471
- try:
472
- database = client_demo.get_database_client(database_name)
473
- container = database.get_container_client(container_name)
474
- operation_response = container.create_item({"id": "test_item", "productName": "test_item"})
475
- headers = operation_response.get_response_headers()
476
- st.write("ETag:", headers.get("etag"))
477
- st.write("Request Charge:", headers.get("x-ms-request-charge"))
478
- except Exception as e:
479
- st.error(f"Error: {str(e)}")
480
 
481
- # πŸ“πŸ“πŸ“ FILE & MEDIA MANAGEMENT FUNCTIONS πŸ“πŸ“πŸ“
 
 
482
  def display_saved_files_in_sidebar():
483
  all_files = sorted([f for f in glob.glob("*.md") if not f.lower().startswith('readme')], reverse=True)
484
  st.sidebar.markdown("## πŸ“ Files")
@@ -523,7 +412,7 @@ def display_file_editor(file_path):
523
  with md_tab:
524
  st.markdown(st.session_state.file_content[file_path])
525
  with code_tab:
526
- new_content = st.text_area("Edit:", value=st.session_state.file_content[file_path], height=400, key=f"editor_{hash(file_path)}", on_change=lambda: None)
527
  col1, col2 = st.columns([1, 5])
528
  with col1:
529
  if st.button("πŸ’Ύ Save"):
@@ -610,7 +499,9 @@ def update_file_management_section():
610
  elif st.session_state.file_view_mode == 'edit':
611
  display_file_editor(st.session_state.current_file)
612
 
613
- # πŸ“ŠπŸ“ŠπŸ“Š SIDEBAR DATA GRID (Records with formatted timestamps) πŸ“ŠπŸ“ŠπŸ“Š
 
 
614
  def show_sidebar_data_grid():
615
  if st.session_state.get("current_container"):
616
  try:
@@ -636,7 +527,29 @@ def show_sidebar_data_grid():
636
  else:
637
  st.sidebar.info("No container selected for data grid.")
638
 
639
- # πŸ“πŸ“πŸ“ DOCUMENTS LIST VIEW (Editable List with Sorting) πŸ“πŸ“πŸ“
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
640
  def edit_documents_list(container):
641
  records = get_documents(container)
642
  sort_option = st.selectbox("Sort by", ["Timestamp", "Name"], key="sort_option")
@@ -674,9 +587,11 @@ def edit_documents_list(container):
674
  st.success(f"Updated {doc_id} πŸ‘")
675
  else:
676
  st.error(f"Error updating {doc_id}: {message}")
677
- st.rerun()
678
 
679
- # πŸŽ₯🎡πŸŽ₯ VIDEO & AUDIO UI FUNCTIONS πŸŽ₯🎡πŸŽ₯
 
 
680
  def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
681
  try:
682
  st.write("Preprocessing image...")
@@ -790,7 +705,9 @@ def add_video_generation_ui(container):
790
  except Exception as e:
791
  st.error(f"Upload error: {str(e)}")
792
 
793
- # βž•βž•βž• NEW ITEM & FIELD FUNCTIONS βž•βž•βž•
 
 
794
  def new_item_default(container):
795
  new_id = generate_unique_id()
796
  default_doc = {
@@ -835,7 +752,9 @@ def add_field_to_doc():
835
  except Exception as e:
836
  st.error(f"Error adding field: {str(e)}")
837
 
838
- # πŸ”πŸ”πŸ” VECTOR SEARCH INTERFACE πŸ”πŸ”πŸ”
 
 
839
  def vector_keyword_search(keyword, container):
840
  try:
841
  query = f"SELECT * FROM c WHERE CONTAINS(c.content, '{keyword}')"
@@ -845,24 +764,9 @@ def vector_keyword_search(keyword, container):
845
  st.error(f"Vector search error: {str(e)}")
846
  return []
847
 
848
- def display_search_results(keyword, container):
849
- results = vector_keyword_search(keyword, container)
850
- st.markdown("### πŸ” Search Results")
851
- for res in results:
852
- doc_id = res.get("id", "")
853
- exp = st.expander(f"Result {doc_id}")
854
- with exp:
855
- edited = st.text_area("Edit Document", value=json.dumps(res, indent=2), key=f"search_{doc_id}")
856
- if st.button(f"πŸ’Ύ Save changes for {doc_id}", key=f"save_search_{doc_id}"):
857
- try:
858
- updated_doc = json.loads(edited)
859
- container.upsert_item(body=updated_doc)
860
- st.success(f"Updated {doc_id}!")
861
- st.rerun()
862
- except Exception as e:
863
- st.error(f"Error saving {doc_id}: {str(e)}")
864
-
865
- # πŸ€–πŸ€–πŸ€– NEW AI MODALITY RECORD TEMPLATES πŸ€–πŸ€–πŸ€–
866
  def new_ai_record(container):
867
  new_id = generate_unique_id()
868
  default_doc = {
@@ -904,7 +808,9 @@ def new_links_record(container):
904
  st.error("Error creating links record: " + message)
905
  return None
906
 
907
- # 🏷️🏷️🏷️ SIDEBAR DATA GRID (Editable Names Grid) 🏷️🏷️🏷️
 
 
908
  def edit_names_grid(container):
909
  records = get_documents(container)
910
  data = []
@@ -935,9 +841,298 @@ def edit_names_grid(container):
935
  st.sidebar.success(f"Updated Name for {doc_id} to '{row['Name']}'")
936
  else:
937
  st.sidebar.error(f"Update error for {doc_id}: {message}")
938
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939
 
940
- # πŸ”ŽπŸ”ŽπŸ”Ž SEARCH DOCUMENTS UI πŸ”ŽπŸ”ŽπŸ”Ž
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
941
  def search_documents_ui(container):
942
  with st.sidebar.form("search_form"):
943
  keyword = st.text_input("Search Keyword", key="search_keyword")
@@ -945,7 +1140,9 @@ def search_documents_ui(container):
945
  if submitted and keyword:
946
  display_search_results(keyword, container)
947
 
948
- # πŸ› οΈπŸ› οΈπŸ› οΈ MAIN FUNCTION πŸ› οΈπŸ› οΈπŸ› οΈ
 
 
949
  def main():
950
  st.markdown("### πŸ™ GitCosmos - Cosmos & Git Hub")
951
  st.markdown(f"[πŸ”— Portal]({CosmosDBUrl})")
@@ -958,42 +1155,6 @@ def main():
958
  else:
959
  st.error("Missing Cosmos Key πŸ”‘βŒ")
960
  return
961
-
962
- # ── CosmosDB Demo Features in Sidebar ──
963
- st.sidebar.markdown("## CosmosDB Demo Features")
964
- demo_feature = st.sidebar.selectbox("Select a Demo",
965
- ["Select", "Create Database", "Create Container", "Create Analytical Container",
966
- "Get Existing Container", "Insert Data", "Delete Data", "Query Database",
967
- "Parameterized Query", "Get Database Properties", "Get Throughput",
968
- "Modify Container Properties", "Item Response Headers"],
969
- key="demo_select")
970
- if demo_feature != "Select":
971
- if demo_feature == "Create Database":
972
- demo_create_database()
973
- elif demo_feature == "Create Container":
974
- demo_create_container()
975
- elif demo_feature == "Create Analytical Container":
976
- demo_create_analytical_container()
977
- elif demo_feature == "Get Existing Container":
978
- demo_get_existing_container()
979
- elif demo_feature == "Insert Data":
980
- demo_insert_data()
981
- elif demo_feature == "Delete Data":
982
- demo_delete_data()
983
- elif demo_feature == "Query Database":
984
- demo_query_database()
985
- elif demo_feature == "Parameterized Query":
986
- demo_parameterized_query()
987
- elif demo_feature == "Get Database Properties":
988
- demo_get_db_properties()
989
- elif demo_feature == "Get Throughput":
990
- demo_get_throughput()
991
- elif demo_feature == "Modify Container Properties":
992
- demo_modify_container_properties()
993
- elif demo_feature == "Item Response Headers":
994
- demo_item_response_headers()
995
-
996
- # ── Existing Sidebar Items (Item Management, File Management, etc.) ──
997
  st.sidebar.markdown("## πŸ› οΈ Item Management")
998
  if st.sidebar.button("New Item"):
999
  if st.session_state.get("current_container"):
@@ -1023,7 +1184,10 @@ def main():
1023
  search_documents_ui(st.session_state.get("current_container"))
1024
  show_sidebar_data_grid()
1025
 
1026
- # Continue with your other UI sections (navigation, file management, document editing, etc.)
 
 
 
1027
  try:
1028
  if st.session_state.get("client") is None:
1029
  st.session_state.client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
@@ -1050,12 +1214,7 @@ def main():
1050
  submitted = st.form_submit_button("Create Container")
1051
  if submitted:
1052
  analytical_ttl = -1 if new_analytical else None
1053
- # Using create_container method directly (adjust if you have an advanced function)
1054
- new_container = database.create_container(
1055
- id=new_container_id,
1056
- partition_key=PartitionKey(path=new_partition_key),
1057
- analytical_storage_ttl=analytical_ttl
1058
- )
1059
  if new_container:
1060
  st.success(f"Container '{new_container_id}' created.")
1061
  default_id = generate_unique_id()
@@ -1155,12 +1314,16 @@ def main():
1155
  st.error(message)
1156
  except Exception as e:
1157
  st.error(f"Delete err: {str(e)}")
 
 
 
 
1158
  elif selected_view == 'Run AI':
1159
  st.markdown("#### πŸ€– Run AI")
1160
  ai_query = st.text_area("Enter your query for ArXiv search:", key="arxiv_query", height=100)
1161
  if st.button("Send"):
1162
  st.session_state.last_query = ai_query
1163
- st.info("Performing AI lookup (function not implemented in this demo)...")
1164
  elif selected_view == 'Clone':
1165
  st.markdown("#### πŸ“„ Clone")
1166
  if documents:
 
1
+ app.py
2
+ # =============================================================================
3
+ # ───────────── IMPORTS ─────────────
4
+ # =============================================================================
5
  import base64
6
  import glob
7
  import hashlib
 
29
  import numpy as np
30
  from urllib.parse import quote
31
 
32
+ # =============================================================================
33
+ # ───────────── EXTERNAL HELP LINKS (Always visible in sidebar) ─────────────
34
+ # =============================================================================
35
  external_links = [
36
  {"title": "CosmosDB GenAI Full Text Search", "url": "https://learn.microsoft.com/en-us/azure/cosmos-db/gen-ai/full-text-search", "emoji": "πŸ’»"},
37
  {"title": "CosmosDB SQL API Client Library", "url": "https://learn.microsoft.com/en-us/python/api/overview/azure/cosmos-readme?view=azure-python", "emoji": "πŸ’»"},
 
46
  {"title": "arcee.ai Official Website", "url": "https://arcee.ai", "emoji": "🌐"},
47
  ]
48
 
49
+ # =============================================================================
50
+ # ───────────── APP CONFIGURATION ─────────────
51
+ # =============================================================================
52
  Site_Name = 'πŸ™ GitCosmos'
53
  title = "πŸ™ GitCosmos"
54
  helpURL = 'https://huggingface.co/awacke1'
 
66
  }
67
  )
68
 
69
+ # Cosmos DB & App URLs
70
  ENDPOINT = "https://acae-afd.documents.azure.com:443/"
71
  DATABASE_NAME = os.environ.get("COSMOS_DATABASE_NAME")
72
  CONTAINER_NAME = os.environ.get("COSMOS_CONTAINER_NAME")
 
74
  LOCAL_APP_URL = "https://huggingface.co/spaces/awacke1/AzureCosmosDBUI"
75
  CosmosDBUrl = 'https://portal.azure.com/#@AaronCWackergmail.onmicrosoft.com/resource/subscriptions/003fba60-5b3f-48f4-ab36-3ed11bc40816/resourceGroups/datasets/providers/Microsoft.DocumentDB/databaseAccounts/acae-afd/dataExplorer'
76
 
77
+ # =============================================================================
78
+ # ───────────── HELPER FUNCTIONS ─────────────
79
+ # =============================================================================
80
  def get_download_link(file_path):
81
  with open(file_path, "rb") as file:
82
  contents = file.read()
 
150
  text = re.sub(r'[^\x00-\x7F]+', '', text)
151
  return text.strip()
152
 
153
+ # NEW: Sanitize JSON text before saving (remove problematic control characters)
154
  def sanitize_json_text(text):
155
+ # Remove control characters except newline, carriage return, and tab
156
  text = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F]', '', text)
157
+ # Escape newline, tab, and carriage return
158
  text = text.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
159
  return text
160
 
161
+ # =============================================================================
162
+ # ───────────── COSMOS DB FUNCTIONS ─────────────
163
+ # =============================================================================
164
  def get_databases(client):
165
  return [db['id'] for db in client.list_databases()]
166
 
 
195
  if "id" not in record:
196
  return False, "Record must contain an 'id' field. πŸ›‘"
197
  doc_id = record["id"]
198
+ if "delete_log" not in st.session_state:
199
+ st.session_state.delete_log = []
200
+ st.session_state.delete_log.append(f"Attempting to delete document: {json.dumps(record, indent=2)}")
201
  partition_key_value = record.get("pk", doc_id)
202
+ st.session_state.delete_log.append(f"Using ID and Partition Key: {partition_key_value}")
203
  container.delete_item(item=doc_id, partition_key=partition_key_value)
204
+ success_msg = f"Record {doc_id} successfully deleted from Cosmos DB. πŸ—‘οΈ"
205
+ st.session_state.delete_log.append(success_msg)
206
+ return True, success_msg
207
  except exceptions.CosmosResourceNotFoundError:
208
+ success_msg = f"Record {doc_id} not found in Cosmos DB (already deleted or never existed). πŸ—‘οΈ"
209
+ st.session_state.delete_log.append(success_msg)
210
+ return True, success_msg
211
  except exceptions.CosmosHttpResponseError as e:
212
+ error_msg = f"HTTP error deleting {doc_id}: {str(e)}. 🚨"
213
+ st.session_state.delete_log.append(error_msg)
214
+ return False, error_msg
215
  except Exception as e:
216
+ error_msg = f"Unexpected error deleting {doc_id}: {str(traceback.format_exc())}. 😱"
217
+ st.session_state.delete_log.append(error_msg)
218
+ return False, error_msg
219
+
220
+ def save_to_cosmos_db(container, query, response1, response2):
221
+ try:
222
+ if container:
223
+ timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
224
+ unique_uuid = str(uuid.uuid4())
225
+ new_id = f"{timestamp}-{unique_uuid}"
226
+ record = {
227
+ "id": new_id,
228
+ "pk": new_id,
229
+ "name": new_id,
230
+ "query": query,
231
+ "response1": response1,
232
+ "response2": response2,
233
+ "timestamp": datetime.utcnow().isoformat(),
234
+ "type": "ai_response",
235
+ "version": "1.0"
236
+ }
237
+ container.create_item(body=record)
238
+ st.success(f"Saved: {record['id']}")
239
+ st.session_state.documents = get_documents(container)
240
+ else:
241
+ st.error("Cosmos container not initialized.")
242
+ except Exception as e:
243
+ st.error(f"Save error: {str(e)}")
244
 
245
  def archive_current_container(database_name, container_name, client):
246
  try:
 
263
  except Exception as e:
264
  return f"Archive error: {str(e)} 😒"
265
 
266
+ # =============================================================================
267
+ # ───────────── ADVANCED COSMOS FUNCTIONS ─────────────
268
+ # =============================================================================
269
+ def create_new_container(database, container_id, partition_key_path,
270
+ analytical_storage_ttl=None, indexing_policy=None, vector_embedding_policy=None):
271
+ try:
272
+ if analytical_storage_ttl is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  container = database.create_container(
274
+ id=container_id,
275
+ partition_key=PartitionKey(path=partition_key_path),
276
+ analytical_storage_ttl=analytical_storage_ttl,
277
+ indexing_policy=indexing_policy,
278
+ vector_embedding_policy=vector_embedding_policy
279
  )
280
+ else:
281
+ container = database.create_container(
282
+ id=container_id,
283
+ partition_key=PartitionKey(path=partition_key_path),
284
+ indexing_policy=indexing_policy,
285
+ vector_embedding_policy=vector_embedding_policy
286
+ )
287
+ except exceptions.CosmosHttpResponseError as e:
288
+ if analytical_storage_ttl is not None and "analyticalStorageTtl" in str(e):
289
+ try:
290
+ container = database.create_container(
291
+ id=container_id,
292
+ partition_key=PartitionKey(path=partition_key_path),
293
+ indexing_policy=indexing_policy,
294
+ vector_embedding_policy=vector_embedding_policy
295
+ )
296
+ except Exception as e2:
297
+ st.error(f"Error creating container without analytical_storage_ttl: {str(e2)}")
298
+ return None
299
+ elif isinstance(e, exceptions.CosmosResourceExistsError):
300
+ container = database.get_container_client(container_id)
301
+ else:
302
+ st.error(f"Error creating container: {str(e)}")
303
+ return None
304
+ return container
 
 
305
 
306
+ def advanced_insert_item(container, item):
307
+ try:
308
+ container.upsert_item(item)
309
+ return True, f"Item {item.get('id', '')} inserted. βž•"
310
+ except Exception as e:
311
+ return False, str(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
+ def advanced_update_item(container, item):
314
+ try:
315
+ container.upsert_item(item)
316
+ return True, f"Item {item.get('id', '')} updated. ✏️"
317
+ except Exception as e:
318
+ return False, str(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
 
320
+ def advanced_delete_item(container, item_id, partition_key_value):
321
+ try:
322
+ container.delete_item(item=item_id, partition_key=partition_key_value)
323
+ return True, f"Item {item_id} deleted. πŸ—‘οΈ"
324
+ except Exception as e:
325
+ return False, str(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
+ def vector_search(container, query_vector, vector_field, top=10, exact_search=False):
328
+ query_vector_str = json.dumps(query_vector)
329
+ query = f"""SELECT TOP {top} c.id, VectorDistance(c.{vector_field}, {query_vector_str}, {str(exact_search).lower()},
330
+ {{'dataType':'float32','distanceFunction':'cosine'}}) AS SimilarityScore
331
+ FROM c ORDER BY SimilarityScore"""
332
+ results = list(container.query_items(query=query, enable_cross_partition_query=True))
333
+ return results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
+ # =============================================================================
336
+ # ───────────── GITHUB FUNCTIONS ─────────────
337
+ # =============================================================================
338
+ def download_github_repo(url, local_path):
339
+ if os.path.exists(local_path):
340
+ shutil.rmtree(local_path)
341
+ Repo.clone_from(url, local_path)
 
 
 
 
 
 
 
342
 
343
+ def create_zip_file(source_dir, output_filename):
344
+ shutil.make_archive(output_filename, 'zip', source_dir)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
 
346
+ def create_repo(g, repo_name):
347
+ user = g.get_user()
348
+ return user.create_repo(repo_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
 
350
+ def push_to_github(local_path, repo, github_token):
351
+ repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
352
+ local_repo = Repo(local_path)
353
+ if 'origin' in [remote.name for remote in local_repo.remotes]:
354
+ origin = local_repo.remote('origin')
355
+ origin.set_url(repo_url)
356
+ else:
357
+ origin = local_repo.create_remote('origin', repo_url)
358
+ if not local_repo.heads:
359
+ local_repo.git.checkout('-b', 'main')
360
+ current_branch = 'main'
361
+ else:
362
+ current_branch = local_repo.active_branch.name
363
+ local_repo.git.add(A=True)
364
+ if local_repo.is_dirty():
365
+ local_repo.git.commit('-m', 'Initial commit')
366
+ origin.push(refspec=f'{current_branch}:{current_branch}')
 
367
 
368
+ # =============================================================================
369
+ # ───────────── FILE & MEDIA MANAGEMENT FUNCTIONS ─────────────
370
+ # =============================================================================
371
  def display_saved_files_in_sidebar():
372
  all_files = sorted([f for f in glob.glob("*.md") if not f.lower().startswith('readme')], reverse=True)
373
  st.sidebar.markdown("## πŸ“ Files")
 
412
  with md_tab:
413
  st.markdown(st.session_state.file_content[file_path])
414
  with code_tab:
415
+ new_content = st.text_area("Edit:", value=st.session_state.file_content[file_path], height=400, key=f"editor_{hash(file_path)}", on_change=lambda: auto_save_edit())
416
  col1, col2 = st.columns([1, 5])
417
  with col1:
418
  if st.button("πŸ’Ύ Save"):
 
499
  elif st.session_state.file_view_mode == 'edit':
500
  display_file_editor(st.session_state.current_file)
501
 
502
+ # =============================================================================
503
+ # ───────────── SIDEBAR DATA GRID (Records with formatted timestamps) ─────────────
504
+ # =============================================================================
505
  def show_sidebar_data_grid():
506
  if st.session_state.get("current_container"):
507
  try:
 
527
  else:
528
  st.sidebar.info("No container selected for data grid.")
529
 
530
+ # =============================================================================
531
+ # ───────────── SEARCH RESULTS DISPLAY (Editable Code Editors)
532
+ # =============================================================================
533
+ def display_search_results(keyword, container):
534
+ results = vector_keyword_search(keyword, container)
535
+ st.markdown("### πŸ” Search Results")
536
+ for res in results:
537
+ doc_id = res.get("id", "")
538
+ exp = st.expander(f"Result {doc_id}")
539
+ with exp:
540
+ edited = st.text_area("Edit Document", value=json.dumps(res, indent=2), key=f"search_{doc_id}")
541
+ if st.button(f"πŸ’Ύ Save changes for {doc_id}", key=f"save_search_{doc_id}"):
542
+ try:
543
+ updated_doc = json.loads(edited)
544
+ container.upsert_item(body=updated_doc)
545
+ st.success(f"Updated {doc_id}!")
546
+ st.experimental_rerun()
547
+ except Exception as e:
548
+ st.error(f"Error saving {doc_id}: {str(e)}")
549
+
550
+ # =============================================================================
551
+ # ───────────── DOCUMENTS LIST VIEW (Editable List with Sorting)
552
+ # =============================================================================
553
  def edit_documents_list(container):
554
  records = get_documents(container)
555
  sort_option = st.selectbox("Sort by", ["Timestamp", "Name"], key="sort_option")
 
587
  st.success(f"Updated {doc_id} πŸ‘")
588
  else:
589
  st.error(f"Error updating {doc_id}: {message}")
590
+ st.experimental_rerun()
591
 
592
+ # =============================================================================
593
+ # ───────────── VIDEO & AUDIO UI FUNCTIONS ─────────────
594
+ # =============================================================================
595
  def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
596
  try:
597
  st.write("Preprocessing image...")
 
705
  except Exception as e:
706
  st.error(f"Upload error: {str(e)}")
707
 
708
+ # =============================================================================
709
+ # ───────────── NEW ITEM & FIELD FUNCTIONS
710
+ # =============================================================================
711
  def new_item_default(container):
712
  new_id = generate_unique_id()
713
  default_doc = {
 
752
  except Exception as e:
753
  st.error(f"Error adding field: {str(e)}")
754
 
755
+ # =============================================================================
756
+ # ───────────── VECTOR SEARCH INTERFACE (Simple keyword search)
757
+ # =============================================================================
758
  def vector_keyword_search(keyword, container):
759
  try:
760
  query = f"SELECT * FROM c WHERE CONTAINS(c.content, '{keyword}')"
 
764
  st.error(f"Vector search error: {str(e)}")
765
  return []
766
 
767
+ # =============================================================================
768
+ # ───────────── NEW AI MODALITY RECORD TEMPLATES
769
+ # =============================================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
  def new_ai_record(container):
771
  new_id = generate_unique_id()
772
  default_doc = {
 
808
  st.error("Error creating links record: " + message)
809
  return None
810
 
811
+ # =============================================================================
812
+ # ───────────── SIDEBAR DATA GRID (Editable Names Grid)
813
+ # =============================================================================
814
  def edit_names_grid(container):
815
  records = get_documents(container)
816
  data = []
 
841
  st.sidebar.success(f"Updated Name for {doc_id} to '{row['Name']}'")
842
  else:
843
  st.sidebar.error(f"Update error for {doc_id}: {message}")
844
+ st.experimental_rerun()
845
+
846
+ # =============================================================================
847
+ # ───────────── SEARCH RESULTS DISPLAY (Editable Code Editors)
848
+ # =============================================================================
849
+ def display_search_results(keyword, container):
850
+ results = vector_keyword_search(keyword, container)
851
+ st.markdown("### πŸ” Search Results")
852
+ for res in results:
853
+ doc_id = res.get("id", "")
854
+ exp = st.expander(f"Result {doc_id}")
855
+ with exp:
856
+ edited = st.text_area("Edit Document", value=json.dumps(res, indent=2), key=f"search_{doc_id}")
857
+ if st.button(f"πŸ’Ύ Save changes for {doc_id}", key=f"save_search_{doc_id}"):
858
+ try:
859
+ updated_doc = json.loads(edited)
860
+ container.upsert_item(body=updated_doc)
861
+ st.success(f"Updated {doc_id}!")
862
+ st.experimental_rerun()
863
+ except Exception as e:
864
+ st.error(f"Error saving {doc_id}: {str(e)}")
865
+
866
+ # =============================================================================
867
+ # ───────────── DOCUMENTS LIST VIEW (Editable List with Sorting)
868
+ # =============================================================================
869
+ def edit_documents_list(container):
870
+ records = get_documents(container)
871
+ sort_option = st.selectbox("Sort by", ["Timestamp", "Name"], key="sort_option")
872
+ if sort_option == "Name":
873
+ records.sort(key=lambda r: r.get("name", "").lower())
874
+ else:
875
+ records.sort(key=lambda r: r.get("timestamp", ""), reverse=True)
876
+ data = []
877
+ for rec in records:
878
+ ts = rec.get("timestamp", "")
879
+ try:
880
+ dt = datetime.fromisoformat(ts)
881
+ formatted = dt.strftime("%I:%M %p %m/%d/%Y")
882
+ except Exception:
883
+ formatted = ts
884
+ data.append({
885
+ "ID": rec.get("id", ""),
886
+ "Name": rec.get("name", ""),
887
+ "Content": rec.get("content", "")[:100] + "..." if rec.get("content", "") else "",
888
+ "Timestamp": formatted
889
+ })
890
+ df = pd.DataFrame(data)
891
+ edited_df = st.data_editor(df[["Name", "Content", "Timestamp"]], key="docs_editor", num_rows="dynamic")
892
+ if st.button("πŸ’Ύ Save List Changes"):
893
+ for idx, row in edited_df.iterrows():
894
+ original = data[idx]
895
+ if row["Name"] != original["Name"] or row["Content"] != original["Content"]:
896
+ doc_id = original["ID"]
897
+ doc = next((r for r in records if r.get("id") == doc_id), None)
898
+ if doc:
899
+ doc["name"] = row["Name"]
900
+ doc["content"] = row["Content"]
901
+ success, message = update_record(container, doc)
902
+ if success:
903
+ st.success(f"Updated {doc_id} πŸ‘")
904
+ else:
905
+ st.error(f"Error updating {doc_id}: {message}")
906
+ st.experimental_rerun()
907
 
908
+ # =============================================================================
909
+ # ───────────── VIDEO & AUDIO UI FUNCTIONS ─────────────
910
+ # =============================================================================
911
+ def validate_and_preprocess_image(file_data, target_size=(576, 1024)):
912
+ try:
913
+ st.write("Preprocessing image...")
914
+ if isinstance(file_data, bytes):
915
+ img = Image.open(io.BytesIO(file_data))
916
+ elif hasattr(file_data, 'read'):
917
+ if hasattr(file_data, 'seek'):
918
+ file_data.seek(0)
919
+ img = Image.open(file_data)
920
+ elif isinstance(file_data, Image.Image):
921
+ img = file_data
922
+ else:
923
+ raise ValueError(f"Unsupported input: {type(file_data)}")
924
+ if img.mode != 'RGB':
925
+ img = img.convert('RGB')
926
+ aspect_ratio = img.size[0] / img.size[1]
927
+ if aspect_ratio > target_size[0] / target_size[1]:
928
+ new_width = target_size[0]
929
+ new_height = int(new_width / aspect_ratio)
930
+ else:
931
+ new_height = target_size[1]
932
+ new_width = int(new_height * aspect_ratio)
933
+ new_width = (new_width // 2) * 2
934
+ new_height = (new_height // 2) * 2
935
+ resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
936
+ final_img = Image.new('RGB', target_size, (255, 255, 255))
937
+ paste_x = (target_size[0] - new_width) // 2
938
+ paste_y = (target_size[1] - new_height) // 2
939
+ final_img.paste(resized_img, (paste_x, paste_y))
940
+ return final_img
941
+ except Exception as e:
942
+ st.error(f"Image error: {str(e)}")
943
+ return None
944
+
945
+ def add_video_generation_ui(container):
946
+ st.markdown("### πŸŽ₯ Video Gen")
947
+ col1, col2 = st.columns([2, 1])
948
+ with col1:
949
+ uploaded_file = st.file_uploader("Upload Image πŸ–ΌοΈ", type=['png', 'jpg', 'jpeg'])
950
+ with col2:
951
+ st.markdown("#### Params")
952
+ motion = st.slider("🌊 Motion", 1, 255, 127)
953
+ fps = st.slider("🎬 FPS", 1, 30, 6)
954
+ with st.expander("Advanced"):
955
+ use_custom = st.checkbox("Custom Seed")
956
+ seed = st.number_input("Seed", value=int(time.time() * 1000)) if use_custom else None
957
+ if uploaded_file is not None:
958
+ try:
959
+ file_data = uploaded_file.read()
960
+ preview1, preview2 = st.columns(2)
961
+ with preview1:
962
+ st.write("Original")
963
+ st.image(Image.open(io.BytesIO(file_data)), use_column_width=True)
964
+ with preview2:
965
+ proc_img = validate_and_preprocess_image(io.BytesIO(file_data))
966
+ if proc_img:
967
+ st.write("Processed")
968
+ st.image(proc_img, use_column_width=True)
969
+ else:
970
+ st.error("Preprocess failed")
971
+ return
972
+ if st.button("πŸŽ₯ Generate"):
973
+ with st.spinner("Generating video..."):
974
+ with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
975
+ proc_img.save(temp_file.name, format='PNG')
976
+ try:
977
+ client = Client("awacke1/stable-video-diffusion", hf_token=os.environ.get("HUGGINGFACE_TOKEN"))
978
+ result = client.predict(
979
+ image=temp_file.name,
980
+ seed=seed if seed is not None else int(time.time() * 1000),
981
+ randomize_seed=seed is None,
982
+ motion_bucket_id=motion,
983
+ fps_id=fps,
984
+ api_name="/video"
985
+ )
986
+ if result and isinstance(result, tuple) and len(result) >= 1:
987
+ video_path = result[0].get('video') if isinstance(result[0], dict) else None
988
+ if video_path and os.path.exists(video_path):
989
+ video_filename = f"generated_video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
990
+ shutil.copy(video_path, video_filename)
991
+ st.success(f"Video generated! πŸŽ‰")
992
+ st.video(video_filename)
993
+ if container:
994
+ video_record = {
995
+ "id": generate_unique_id(),
996
+ "pk": generate_unique_id(),
997
+ "type": "generated_video",
998
+ "filename": video_filename,
999
+ "seed": seed if seed is not None else "random",
1000
+ "motion": motion,
1001
+ "fps": fps,
1002
+ "timestamp": datetime.now().isoformat()
1003
+ }
1004
+ success, message = insert_record(container, video_record)
1005
+ if success:
1006
+ st.success("DB record saved!")
1007
+ else:
1008
+ st.error(f"DB error: {message}")
1009
+ else:
1010
+ st.error("Invalid result format")
1011
+ else:
1012
+ st.error("No result returned")
1013
+ except Exception as e:
1014
+ st.error(f"Video gen error: {str(e)}")
1015
+ finally:
1016
+ try:
1017
+ os.unlink(temp_file.name)
1018
+ st.write("Temp file removed")
1019
+ except Exception as e:
1020
+ st.warning(f"Cleanup error: {str(e)}")
1021
+ except Exception as e:
1022
+ st.error(f"Upload error: {str(e)}")
1023
+
1024
+ # =============================================================================
1025
+ # ───────────── NEW ITEM & FIELD FUNCTIONS
1026
+ # =============================================================================
1027
+ def new_item_default(container):
1028
+ new_id = generate_unique_id()
1029
+ default_doc = {
1030
+ "id": new_id,
1031
+ "pk": new_id,
1032
+ "name": "New Sample Document",
1033
+ "content": "Start editing your document here...",
1034
+ "timestamp": datetime.now().isoformat(),
1035
+ "type": "sample"
1036
+ }
1037
+ success, message = insert_record(container, default_doc)
1038
+ if success:
1039
+ st.success("New sample document created! ✨")
1040
+ return default_doc
1041
+ else:
1042
+ st.error("Error creating new item: " + message)
1043
+ return None
1044
+
1045
+ def auto_save_edit():
1046
+ try:
1047
+ edited_str = st.session_state.doc_editor
1048
+ try:
1049
+ json.loads(edited_str)
1050
+ except Exception:
1051
+ edited_str = sanitize_json_text(edited_str)
1052
+ edited_doc = json.loads(edited_str)
1053
+ container = st.session_state.current_container
1054
+ container.upsert_item(edited_doc)
1055
+ st.success("Auto-saved! πŸ’Ύ")
1056
+ except Exception as e:
1057
+ st.error(f"Auto-save error: {str(e)}")
1058
+
1059
+ def add_field_to_doc():
1060
+ key = st.session_state.new_field_key
1061
+ value = st.session_state.new_field_value
1062
+ try:
1063
+ doc = json.loads(st.session_state.doc_editor)
1064
+ doc[key] = value
1065
+ st.session_state.doc_editor = json.dumps(doc, indent=2)
1066
+ auto_save_edit()
1067
+ st.success(f"Added field {key} πŸ‘")
1068
+ except Exception as e:
1069
+ st.error(f"Error adding field: {str(e)}")
1070
+
1071
+ # =============================================================================
1072
+ # ───────────── SEARCH RESULTS DISPLAY (Editable Code Editors)
1073
+ # =============================================================================
1074
+ def display_search_results(keyword, container):
1075
+ results = vector_keyword_search(keyword, container)
1076
+ st.markdown("### πŸ” Search Results")
1077
+ for res in results:
1078
+ doc_id = res.get("id", "")
1079
+ exp = st.expander(f"Result {doc_id}")
1080
+ with exp:
1081
+ edited = st.text_area("Edit Document", value=json.dumps(res, indent=2), key=f"search_{doc_id}")
1082
+ if st.button(f"πŸ’Ύ Save changes for {doc_id}", key=f"save_search_{doc_id}"):
1083
+ try:
1084
+ updated_doc = json.loads(edited)
1085
+ container.upsert_item(body=updated_doc)
1086
+ st.success(f"Updated {doc_id}!")
1087
+ st.experimental_rerun()
1088
+ except Exception as e:
1089
+ st.error(f"Error saving {doc_id}: {str(e)}")
1090
+
1091
+ # =============================================================================
1092
+ # ───────────── DOCUMENTS LIST VIEW (Editable List with Sorting)
1093
+ # =============================================================================
1094
+ def edit_documents_list(container):
1095
+ records = get_documents(container)
1096
+ sort_option = st.selectbox("Sort by", ["Timestamp", "Name"], key="sort_option")
1097
+ if sort_option == "Name":
1098
+ records.sort(key=lambda r: r.get("name", "").lower())
1099
+ else:
1100
+ records.sort(key=lambda r: r.get("timestamp", ""), reverse=True)
1101
+ data = []
1102
+ for rec in records:
1103
+ ts = rec.get("timestamp", "")
1104
+ try:
1105
+ dt = datetime.fromisoformat(ts)
1106
+ formatted = dt.strftime("%I:%M %p %m/%d/%Y")
1107
+ except Exception:
1108
+ formatted = ts
1109
+ data.append({
1110
+ "ID": rec.get("id", ""),
1111
+ "Name": rec.get("name", ""),
1112
+ "Content": rec.get("content", "")[:100] + "..." if rec.get("content", "") else "",
1113
+ "Timestamp": formatted
1114
+ })
1115
+ df = pd.DataFrame(data)
1116
+ edited_df = st.data_editor(df[["Name", "Content", "Timestamp"]], key="docs_editor", num_rows="dynamic")
1117
+ if st.button("πŸ’Ύ Save List Changes"):
1118
+ for idx, row in edited_df.iterrows():
1119
+ original = data[idx]
1120
+ if row["Name"] != original["Name"] or row["Content"] != original["Content"]:
1121
+ doc_id = original["ID"]
1122
+ doc = next((r for r in records if r.get("id") == doc_id), None)
1123
+ if doc:
1124
+ doc["name"] = row["Name"]
1125
+ doc["content"] = row["Content"]
1126
+ success, message = update_record(container, doc)
1127
+ if success:
1128
+ st.success(f"Updated {doc_id} πŸ‘")
1129
+ else:
1130
+ st.error(f"Error updating {doc_id}: {message}")
1131
+ st.experimental_rerun()
1132
+
1133
+ # =============================================================================
1134
+ # ───────────── SEARCH DOCUMENTS UI (Enter Key triggers search)
1135
+ # =============================================================================
1136
  def search_documents_ui(container):
1137
  with st.sidebar.form("search_form"):
1138
  keyword = st.text_input("Search Keyword", key="search_keyword")
 
1140
  if submitted and keyword:
1141
  display_search_results(keyword, container)
1142
 
1143
+ # =============================================================================
1144
+ # ───────────── MAIN FUNCTION ─────────────
1145
+ # =============================================================================
1146
  def main():
1147
  st.markdown("### πŸ™ GitCosmos - Cosmos & Git Hub")
1148
  st.markdown(f"[πŸ”— Portal]({CosmosDBUrl})")
 
1155
  else:
1156
  st.error("Missing Cosmos Key πŸ”‘βŒ")
1157
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
  st.sidebar.markdown("## πŸ› οΈ Item Management")
1159
  if st.sidebar.button("New Item"):
1160
  if st.session_state.get("current_container"):
 
1184
  search_documents_ui(st.session_state.get("current_container"))
1185
  show_sidebar_data_grid()
1186
 
1187
+
1188
+
1189
+ if st.session_state.get("current_container"):
1190
+ edit_names_grid(st.session_state.current_container)
1191
  try:
1192
  if st.session_state.get("client") is None:
1193
  st.session_state.client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
 
1214
  submitted = st.form_submit_button("Create Container")
1215
  if submitted:
1216
  analytical_ttl = -1 if new_analytical else None
1217
+ new_container = create_new_container(database, new_container_id, new_partition_key, analytical_storage_ttl=analytical_ttl)
 
 
 
 
 
1218
  if new_container:
1219
  st.success(f"Container '{new_container_id}' created.")
1220
  default_id = generate_unique_id()
 
1314
  st.error(message)
1315
  except Exception as e:
1316
  st.error(f"Delete err: {str(e)}")
1317
+ if "delete_log" in st.session_state and st.session_state.delete_log:
1318
+ st.subheader("Delete Log")
1319
+ for log_entry in st.session_state.delete_log[-5:]:
1320
+ st.write(log_entry)
1321
  elif selected_view == 'Run AI':
1322
  st.markdown("#### πŸ€– Run AI")
1323
  ai_query = st.text_area("Enter your query for ArXiv search:", key="arxiv_query", height=100)
1324
  if st.button("Send"):
1325
  st.session_state.last_query = ai_query
1326
+ perform_ai_lookup(ai_query, vocal_summary=True, extended_refs=False, titles_summary=True, full_audio=True, useArxiv=True, useArxivAudio=False)
1327
  elif selected_view == 'Clone':
1328
  st.markdown("#### πŸ“„ Clone")
1329
  if documents: