AzureCosmosDBUI / app.py
awacke1's picture
Update app.py
4358a38 verified
raw
history blame
20.7 kB
# CosmicApp.py
import streamlit as st
from azure.cosmos import CosmosClient, exceptions
import os
import pandas as pd
import json
from datetime import datetime
import shutil
from github import Github
from git import Repo
import base64
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Cosmos DB configuration
ENDPOINT = os.getenv("ENDPOINT")
PRIMARY_KEY = os.getenv("PRIMARY_KEY")
# GitHub configuration
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
# 🌟 Helper Functions Galore 🌟
def download_github_repo(url, local_path):
"""
🌀 Clone a GitHub repo faster than a swirling vortex!
"""
if os.path.exists(local_path):
shutil.rmtree(local_path)
Repo.clone_from(url, local_path)
def create_repo(github_token, repo_name):
"""
🐣 Hatch a new GitHub repo like a pro!
"""
g = Github(github_token)
user = g.get_user()
return user.create_repo(repo_name)
def push_to_github(local_path, repo, github_token):
"""
🚀 Push your changes to GitHub at warp speed!
"""
repo_url = f"https://{github_token}@github.com/{repo.full_name}.git"
local_repo = Repo(local_path)
if 'origin' in [remote.name for remote in local_repo.remotes]:
origin = local_repo.remote('origin')
origin.set_url(repo_url)
else:
origin = local_repo.create_remote('origin', repo_url)
local_repo.git.add(A=True)
if local_repo.is_dirty():
local_repo.git.commit('-m', 'Initial commit')
origin.push(refspec=f"{local_repo.active_branch.name}:{local_repo.active_branch.name}")
def get_base64_download_link(file_path, file_name):
"""
🔗 Get a base64 download link for instant gratification!
"""
with open(file_path, "rb") as file:
contents = file.read()
base64_encoded = base64.b64encode(contents).decode()
return f'<a href="data:application/zip;base64,{base64_encoded}" download="{file_name}">🛸 Download {file_name} 🛸</a>'
def fetch_db_structure(client):
"""
📂 Fetch the cosmic database structure—no telescope needed!
"""
structure = {}
for database in client.list_databases():
db_name = database['id']
structure[db_name] = []
db_client = client.get_database_client(db_name)
for container in db_client.list_containers():
structure[db_name].append(container['id'])
return structure
def fetch_items(client, db_name, container_name):
"""
🛰️ Fetch items from a container—beep boop!
"""
container = client.get_database_client(db_name).get_container_client(container_name)
items = list(container.read_all_items())
return items
def create_item(client, db_name, container_name):
"""
🌱 Create a new cosmic item—let it grow!
"""
st.subheader("🌱 Create New Item")
item_id = st.text_input("🆔 Item ID")
item_data = st.text_area("📝 Item Data (in JSON format)")
if st.button("💾 Save New Item"):
try:
container = client.get_database_client(db_name).get_container_client(container_name)
json_data = json.loads(item_data)
json_data['id'] = item_id
container.create_item(body=json_data)
st.success("🎉 New item created successfully!")
st.json(json_data)
st.experimental_rerun()
except Exception as e:
st.error(f"🚨 Error creating item: {str(e)}")
def edit_item(client, db_name, container_name, item_id):
"""
✏️ Edit an existing item—because change is the only constant!
"""
container = client.get_database_client(db_name).get_container_client(container_name)
item = container.read_item(item=item_id, partition_key=item_id)
st.subheader(f"✏️ Editing Item: {item_id}")
edited_item = st.text_area("📝 Edit Item Data (in JSON format)", value=json.dumps(item, indent=2))
if st.button("💾 Save Changes"):
try:
json_data = json.loads(edited_item)
container.upsert_item(body=json_data)
st.success("✨ Item updated successfully!")
st.json(json_data)
st.experimental_rerun()
except Exception as e:
st.error(f"🚨 Error updating item: {str(e)}")
def delete_item(client, db_name, container_name, item_id):
"""
🗑️ Delete an item—because sometimes less is more!
"""
st.subheader(f"🗑️ Delete Item: {item_id}")
if st.button("⚠️ Confirm Delete"):
try:
container = client.get_database_client(db_name).get_container_client(container_name)
container.delete_item(item=item_id, partition_key=item_id)
st.success(f"🔥 Item {item_id} deleted successfully!")
st.experimental_rerun()
except Exception as e:
st.error(f"🚨 Error deleting item: {str(e)}")
def archive_all_data(client):
"""
📦 Archive all your data—pack it up, pack it in!
"""
try:
base_dir = "./cosmos_archive"
if os.path.exists(base_dir):
shutil.rmtree(base_dir)
os.makedirs(base_dir)
for database in client.list_databases():
db_name = database['id']
db_dir = os.path.join(base_dir, db_name)
os.makedirs(db_dir)
db_client = client.get_database_client(db_name)
for container in db_client.list_containers():
container_name = container['id']
container_dir = os.path.join(db_dir, container_name)
os.makedirs(container_dir)
container_client = db_client.get_container_client(container_name)
items = list(container_client.read_all_items())
with open(os.path.join(container_dir, f"{container_name}.json"), 'w') as f:
json.dump(items, f, indent=2)
archive_name = f"cosmos_archive_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
shutil.make_archive(archive_name, 'zip', base_dir)
return get_base64_download_link(f"{archive_name}.zip", f"{archive_name}.zip")
except Exception as e:
st.error(f"🚨 An error occurred while archiving data: {str(e)}")
def download_all_code():
"""
💾 Download all the code—because sharing is caring!
"""
try:
base_dir = "."
exclude_dirs = ['.git', '__pycache__', 'cosmos_archive']
exclude_files = ['.env', '.gitignore', 'cosmos_archive.zip']
zip_filename = f"CosmosDBAICode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
shutil.make_archive(zip_filename[:-4], 'zip', base_dir)
return get_base64_download_link(zip_filename, zip_filename)
except Exception as e:
st.error(f"🚨 An error occurred while creating the code archive: {str(e)}")
def render_sidebar(client, structure):
"""
🎛️ Render the cosmic sidebar—control your destiny!
"""
st.sidebar.title("🌌 Cosmic Control Panel")
# 🚦 Navigation
app_mode = st.sidebar.radio("🚀 Choose Your Adventure", ["App Mode 🌟", "Tutorial Mode 📖"])
if app_mode == "App Mode 🌟":
# 🗄️ Database and Container selection
selected_db = st.sidebar.selectbox("🗄️ Select Database", list(structure.keys()))
selected_container = st.sidebar.selectbox("📦 Select Container", structure[selected_db])
# 📝 Fetch items for the selected container
items = fetch_items(client, selected_db, selected_container)
# 📄 Item selection
item_ids = [item['id'] for item in items]
selected_item = st.sidebar.selectbox("📄 Select Item", ["Create New Item"] + item_ids)
# 🎬 Action buttons
if selected_item != "Create New Item":
if st.sidebar.button("✏️ Edit Item"):
st.session_state.action = "edit"
st.session_state.selected_item = selected_item
if st.sidebar.button("🗑️ Delete Item"):
st.session_state.action = "delete"
st.session_state.selected_item = selected_item
else:
if st.sidebar.button("🌱 Create New Item"):
st.session_state.action = "create"
# 🐙 GitHub Operations
st.sidebar.subheader("🐙 GitHub Operations")
source_repo = st.sidebar.text_input("🔗 Source Repo URL")
new_repo_name = st.sidebar.text_input("🆕 New Repo Name", value=f"Clone-{datetime.now().strftime('%Y%m%d_%H%M%S')}")
if st.sidebar.button("📥 Clone Repository"):
clone_github_repo(source_repo, new_repo_name)
if st.sidebar.button("📤 Push to New Repository"):
push_to_new_repo(source_repo, new_repo_name)
# 📦 Archive data button
if st.sidebar.button("📦 Archive All Data"):
download_link = archive_all_data(client)
st.sidebar.markdown(download_link, unsafe_allow_html=True)
# 💾 Download All Code button
if st.sidebar.button("💾 Download All Code"):
download_link = download_all_code()
st.sidebar.markdown(download_link, unsafe_allow_html=True)
# 🚪 Logout button
if st.sidebar.button("🚪 Logout"):
st.session_state.logged_in = False
st.session_state.action = None
st.session_state.selected_item = None
st.experimental_rerun()
return selected_db, selected_container, selected_item, app_mode
else:
# For tutorial mode
return None, None, None, app_mode
def clone_github_repo(source_repo, new_repo_name):
"""
📥 Clone a GitHub repo—it's like magic!
"""
if GITHUB_TOKEN and source_repo:
try:
local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
download_github_repo(source_repo, local_path)
zip_filename = f"{new_repo_name}.zip"
shutil.make_archive(zip_filename[:-4], 'zip', local_path)
st.sidebar.markdown(get_base64_download_link(zip_filename, zip_filename), unsafe_allow_html=True)
st.sidebar.success("🎉 Repository cloned successfully!")
except Exception as e:
st.sidebar.error(f"🚨 An error occurred: {str(e)}")
finally:
if os.path.exists(local_path):
shutil.rmtree(local_path)
if os.path.exists(zip_filename):
os.remove(zip_filename)
else:
st.sidebar.error("🚨 Please ensure GitHub token is set and source repository URL is provided.")
def push_to_new_repo(source_repo, new_repo_name):
"""
📤 Push to a new GitHub repo—reach for the stars!
"""
if GITHUB_TOKEN and source_repo:
try:
new_repo = create_repo(GITHUB_TOKEN, new_repo_name)
local_path = f"./temp_repo_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
download_github_repo(source_repo, local_path)
push_to_github(local_path, new_repo, GITHUB_TOKEN)
st.sidebar.success(f"🚀 Repository pushed successfully to {new_repo.html_url}")
except Exception as e:
st.sidebar.error(f"🚨 An error occurred: {str(e)}")
finally:
if os.path.exists(local_path):
shutil.rmtree(local_path)
else:
st.sidebar.error("🚨 Please ensure GitHub token is set and source repository URL is provided.")
def main():
"""
🛸 Main function—where all the magic happens!
"""
st.set_page_config(layout="wide")
st.title("🚀 Cosmos DB & GitHub Integration App with Streamlit 🎉")
# Initialize session state
if 'logged_in' not in st.session_state:
st.session_state.logged_in = False
if 'action' not in st.session_state:
st.session_state.action = None
if 'selected_item' not in st.session_state:
st.session_state.selected_item = None
# Login section
if not st.session_state.logged_in:
st.subheader("🔐 Login to Your Cosmic Account")
if st.button("🚀 Launch"):
if PRIMARY_KEY:
st.session_state.primary_key = PRIMARY_KEY
st.session_state.logged_in = True
st.experimental_rerun()
else:
st.error("🚨 Invalid key. Please check your environment variables.")
else:
# Initialize Cosmos DB client
try:
client = CosmosClient(ENDPOINT, credential=st.session_state.primary_key)
# Fetch database structure
structure = fetch_db_structure(client)
# Render sidebar and get selections
selected_db, selected_container, selected_item, app_mode = render_sidebar(client, structure)
if app_mode == "App Mode 🌟":
# Main area
if st.session_state.action == "create":
create_item(client, selected_db, selected_container)
elif st.session_state.action == "edit":
edit_item(client, selected_db, selected_container, st.session_state.selected_item)
elif st.session_state.action == "delete":
delete_item(client, selected_db, selected_container, st.session_state.selected_item)
else:
st.write("🌟 Select an action from the sidebar to get started.")
elif app_mode == "Tutorial Mode 📖":
display_tutorial()
except exceptions.CosmosHttpResponseError as e:
st.error(f"🚨 Failed to connect to Cosmos DB: {str(e)}")
except Exception as e:
st.error(f"🚨 An unexpected error occurred: {str(e)}")
def display_tutorial():
"""
📖 Display the in-app tutorial—knowledge is power!
"""
st.header("📖 Welcome to the Cosmic Tutorial!")
st.markdown("""
### 🚀 Introduction
**Greetings, Earthling!** 👽 Ready to embark on a cosmic journey through the universe of Azure Cosmos DB and GitHub? Buckle up! This tutorial is not just informative—it's a blast! 🎆
**What You'll Learn:**
- 🌌 Connecting to **Azure Cosmos DB** using Python—no rocket science degree required!
- 🛠️ Performing **CRUD operations** on Cosmos DB containers—because you can!
- 🐙 Integrating **GitHub functionalities** within the app—unleash the octopus!
- 🎨 Building an interactive UI with **Streamlit**—your canvas awaits!
---
### 🌟 Prerequisites
Before we launch into space, make sure you've got:
- 🛰️ An **Azure Cosmos DB** account—your mission control.
- 🐙 A **GitHub** account with a personal access token—tentacles not included.
- 🐍 **Python 3.7+** installed—because snakes are cool.
- 🧠 Basic knowledge of Python and Streamlit—you've got this!
---
### 🛠️ Setting Up the Environment
**1. Clone the Repository**
Open your terminal and run:
""")
st.code("""
git clone https://github.com/yourusername/cosmosdb-streamlit-app.git
cd cosmosdb-streamlit-app
""", language='bash')
st.markdown("""
**2. Create a Virtual Environment**
Let's keep things tidy:
""")
st.code("""
python -m venv venv
# On Windows
venv\\Scripts\\activate
# On macOS/Linux
source venv/bin/activate
""", language='bash')
st.markdown("""
**3. Install Dependencies**
Time to get those packages:
""")
st.code("""
pip install -r requirements.txt
""", language='bash')
st.markdown("""
**4. Set Up Environment Variables**
Create a `.env` file and add:
""")
st.code("""
ENDPOINT=https://your-cosmos-db-account.documents.azure.com:443/
PRIMARY_KEY=your_cosmos_db_primary_key
GITHUB_TOKEN=your_github_personal_access_token
""", language='text')
st.warning("⚠️ **Note:** Keep your `.env` file secret—just like your secret stash of cookies! 🍪")
st.markdown("---")
st.markdown("""
### 🔧 Application Architecture
**Components:**
- 🗄️ **Cosmos DB Operations**: Functions to connect and interact with Azure Cosmos DB.
- 🐙 **GitHub Integration**: Clone, create, and push repositories like a boss.
- 🎨 **Streamlit Interface**: The front-end that brings it all together.
**Data Flow:**
1. 🎛️ **User Interaction**: Users make choices in the app.
2. 🗄️ **Database Operations**: App performs actions on Cosmos DB.
3. 🐙 **GitHub Actions**: Clone and push repositories.
4. 📦 **Archiving Data**: Archive and download database contents.
---
### 🧩 Implementing the Application
**Importing Libraries**
""")
st.code("""
import streamlit as st
from azure.cosmos import CosmosClient, exceptions
import os
import json
from datetime import datetime
import shutil
from github import Github
from git import Repo
import base64
from dotenv import load_dotenv
load_dotenv()
""", language='python')
st.markdown("""
**Configuring Cosmos DB and GitHub**
""")
st.code("""
# Cosmos DB configuration
ENDPOINT = os.getenv("ENDPOINT")
PRIMARY_KEY = os.getenv("PRIMARY_KEY")
# GitHub configuration
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
""", language='python')
st.markdown("""
**Helper Functions**
Here's where the magic happens! ✨
*GitHub Operations*
""")
st.code("""
def download_github_repo(url, local_path):
# Function implementation
def create_repo(github_token, repo_name):
# Function implementation
def push_to_github(local_path, repo, github_token):
# Function implementation
""", language='python')
st.markdown("""
*Base64 Download Link*
""")
st.code("""
def get_base64_download_link(file_path, file_name):
# Function implementation
""", language='python')
st.markdown("""
**Cosmos DB Operations**
*Fetching Database Structure*
""")
st.code("""
def fetch_db_structure(client):
# Function implementation
""", language='python')
st.markdown("""
*CRUD Operations*
**Create Item**
""")
st.code("""
def create_item(client, db_name, container_name):
# Function implementation
""", language='python')
st.markdown("""
**Edit Item**
""")
st.code("""
def edit_item(client, db_name, container_name, item_id):
# Function implementation
""", language='python')
st.markdown("""
**Delete Item**
""")
st.code("""
def delete_item(client, db_name, container_name, item_id):
# Function implementation
""", language='python')
st.markdown("""
**Archiving Data**
""")
st.code("""
def archive_all_data(client):
# Function implementation
""", language='python')
st.markdown("""
**Streamlit Interface**
*Rendering the Sidebar*
""")
st.code("""
def render_sidebar(client, structure):
# Function implementation
""", language='python')
st.markdown("""
*Main Function*
""")
st.code("""
def main():
# Function implementation
if __name__ == "__main__":
main()
""", language='python')
st.markdown("---")
st.markdown("""
### 🚀 Running the Application
**Start the Streamlit App**
""")
st.code("""
streamlit run CosmicApp.py
""", language='bash')
st.markdown("""
**Login**
- Open your browser and go to `http://localhost:8501`.
- Click **Launch** to enter the app.
**Using the App**
- **Database Selection**: Choose your database and container from the sidebar.
- **Item Operations**:
- 🌱 **Create New Item**
- ✏️ **Edit Item**
- 🗑️ **Delete Item**
- **GitHub Operations**:
- 📥 **Clone Repository**
- 📤 **Push to New Repository**
- **Archive Data**: Click **📦 Archive All Data** to download a ZIP file.
- **Download Code**: Click **💾 Download All Code** to get the app's source code.
---
### 🌠 Conclusion
You've reached the end of our cosmic tutorial! 🚀 We hope you had a stellar time learning and exploring the universe of Cosmos DB and GitHub integration.
**Keep Reaching for the Stars!** 🌟
---
""")
if __name__ == "__main__":
main()