AzureCosmosDBUI / app.py
awacke1's picture
Update app.py
35ad459 verified
raw
history blame
20.6 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")
Key = os.environ.get("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.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.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.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.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 Key:
st.session_state.primary_key = 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()