awacke1 commited on
Commit
7a281ce
Β·
verified Β·
1 Parent(s): 567430f

Update app.py

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