Spaces:
Build error
Build error
| import os | |
| import streamlit as st | |
| import pyperclip | |
| import yaml | |
| from datetime import datetime | |
| # Function to format date | |
| def format_date(timestamp): | |
| return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") | |
| # Function to convert folder names to readable format | |
| def format_folder_name(folder_name): | |
| return folder_name.replace("-", " ").title() | |
| # Function to load markdown files and extract YAML front matter and content | |
| def load_markdown(file_path): | |
| with open(file_path, 'r') as file: | |
| content = file.read() | |
| # Check for YAML front matter | |
| if content.startswith('---'): | |
| parts = content.split('---', 2) | |
| if len(parts) >= 3: | |
| yaml_content = parts[1].strip() | |
| markdown_content = parts[2].strip() | |
| try: | |
| front_matter = yaml.safe_load(yaml_content) | |
| # Ensure tags is a list | |
| if 'tags' in front_matter: | |
| if isinstance(front_matter['tags'], str): | |
| front_matter['tags'] = [tag.strip() for tag in front_matter['tags'].split(',')] | |
| else: | |
| front_matter['tags'] = [] | |
| return front_matter, markdown_content | |
| except yaml.YAMLError: | |
| return {'tags': []}, content | |
| return {'tags': []}, content | |
| # Function to extract the first header from markdown content | |
| def extract_title_and_body(markdown_content): | |
| lines = markdown_content.split('\n') | |
| title = "Untitled Configuration" | |
| body = markdown_content | |
| for i, line in enumerate(lines): | |
| if line.startswith('# '): | |
| title = line.strip('# ').strip() | |
| body = '\n'.join(lines[i+1:]).strip() | |
| break | |
| return title, body | |
| # Function to recursively build the sidebar navigation | |
| def build_sidebar_navigation(base_path, current_path): | |
| items = os.listdir(current_path) | |
| for item in sorted(items): | |
| item_path = os.path.join(current_path, item) | |
| if os.path.isdir(item_path): | |
| with st.sidebar.expander(format_folder_name(item)): | |
| build_sidebar_navigation(base_path, item_path) | |
| elif item.endswith('.md'): | |
| front_matter, markdown_content = load_markdown(item_path) | |
| title, _ = extract_title_and_body(markdown_content) | |
| # Add binoculars icon if vision is enabled | |
| vision = front_matter.get("vision", "") | |
| vision_icon = " π" if str(vision).lower() == "yes" else "" | |
| if st.sidebar.button(f"{title}{vision_icon}", key=item_path): | |
| st.session_state['selected_file'] = item_path | |
| # Function to search for configurations | |
| def search_configurations(base_path, search_term, selected_tags=None): | |
| matches = [] | |
| for root, dirs, files in os.walk(base_path): | |
| for file in files: | |
| if file.endswith('.md'): | |
| file_path = os.path.join(root, file) | |
| front_matter, markdown_content = load_markdown(file_path) | |
| title, body = extract_title_and_body(markdown_content) | |
| # Check if content matches search term and tags | |
| content_matches = search_term.lower() in markdown_content.lower() | |
| tags_match = True | |
| if selected_tags: | |
| tags_match = any(tag in front_matter.get('tags', []) for tag in selected_tags) | |
| if content_matches and tags_match: | |
| matches.append((file_path, title, front_matter.get('tags', []))) | |
| return matches | |
| # Main function to run the Streamlit app | |
| def main(): | |
| st.set_page_config(page_title="AI Agent Configurations", layout="wide") | |
| # Define the base path for agent configurations | |
| base_path = "agent-configs" | |
| # Initialize session state | |
| if 'selected_file' not in st.session_state: | |
| st.session_state['selected_file'] = None | |
| if 'dark_mode' not in st.session_state: | |
| st.session_state['dark_mode'] = False | |
| if 'favorites' not in st.session_state: | |
| st.session_state['favorites'] = set() | |
| # Apply dark mode if enabled | |
| if st.session_state['dark_mode']: | |
| st.markdown(""" | |
| <style> | |
| .stApp { | |
| background-color: #1E1E1E; | |
| color: #FFFFFF; | |
| } | |
| .sidebar .sidebar-content { | |
| background-color: #2D2D2D; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Sidebar for navigation and search | |
| st.sidebar.title("AI Agent Configurations") | |
| # Dark mode toggle | |
| st.sidebar.checkbox("Dark Mode", key="dark_mode", value=st.session_state['dark_mode']) | |
| # GitHub repository badge in sidebar | |
| st.sidebar.markdown( | |
| "[](https://github.com/danielrosehill/LLM-Assistants-Web-Library)", | |
| unsafe_allow_html=True | |
| ) | |
| # Collect all configurations and their metadata | |
| all_configs = [] | |
| all_tags = set() | |
| for root, _, files in os.walk(base_path): | |
| for file in files: | |
| if file.endswith('.md'): | |
| file_path = os.path.join(root, file) | |
| front_matter, _ = load_markdown(file_path) | |
| title, _ = extract_title_and_body(_) | |
| last_modified = os.path.getmtime(file_path) | |
| all_configs.append({ | |
| 'path': file_path, | |
| 'title': title, | |
| 'tags': front_matter.get('tags', []), | |
| 'last_modified': last_modified | |
| }) | |
| all_tags.update(front_matter.get('tags', [])) | |
| # Sorting options | |
| sort_options = { | |
| 'Title (A-Z)': lambda x: x['title'].lower(), | |
| 'Title (Z-A)': lambda x: x['title'].lower(), | |
| 'Last Modified (Newest)': lambda x: x['last_modified'], | |
| 'Last Modified (Oldest)': lambda x: x['last_modified'] | |
| } | |
| sort_by = st.sidebar.selectbox('Sort by', list(sort_options.keys())) | |
| # Sort configurations | |
| all_configs.sort(key=sort_options[sort_by]) | |
| if sort_by == 'Title (Z-A)' or sort_by == 'Last Modified (Newest)': | |
| all_configs.reverse() | |
| # Search and filter functionality | |
| search_term = st.sidebar.text_input("Search configurations") | |
| selected_tags = st.sidebar.multiselect("Filter by tags", sorted(list(all_tags))) | |
| # Show favorites section if there are any | |
| if st.session_state['favorites']: | |
| st.sidebar.markdown("### Favorites") | |
| for file_path in st.session_state['favorites']: | |
| front_matter, _ = load_markdown(file_path) | |
| title, _ = extract_title_and_body(_) | |
| if st.sidebar.button(f"β {title}", key=f"fav_{file_path}"): | |
| st.session_state['selected_file'] = file_path | |
| st.sidebar.divider() | |
| if search_term or selected_tags: | |
| matches = search_configurations(base_path, search_term, selected_tags) | |
| if matches: | |
| st.sidebar.write("Search Results:") | |
| for file_path, title, tags in matches: | |
| if st.sidebar.button(f"{title} ({', '.join(tags)})", key=f"search_{file_path}"): | |
| st.session_state['selected_file'] = file_path | |
| else: | |
| st.sidebar.write("No matches found.") | |
| else: | |
| # Build the sidebar navigation | |
| build_sidebar_navigation(base_path, base_path) | |
| # Main content area | |
| st.title("Daniel Rosehill AI Assistant Library") | |
| st.markdown( | |
| """ | |
| <div style="background-color: #f0f0f0; padding: 10px; border-radius: 10px; margin-bottom: 20px;"> | |
| <p style="margin: 0;">This microsite contains open source configurations for AI assistants.</p> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| if st.session_state['selected_file']: | |
| front_matter, markdown_content = load_markdown(st.session_state['selected_file']) | |
| title, body = extract_title_and_body(markdown_content) | |
| # Display title and metadata | |
| st.markdown(f"# {title}") | |
| # Display tags if present | |
| if front_matter.get('tags'): | |
| st.markdown("**Tags:** " + ", ".join(f"`{tag}`" for tag in front_matter['tags'])) | |
| # Display last modified date | |
| last_modified = os.path.getmtime(st.session_state['selected_file']) | |
| st.markdown(f"**Last Modified:** {format_date(last_modified)}") | |
| # Create a container for buttons | |
| with st.container(): | |
| st.write("Options:") | |
| button_col1, button_col2, button_col3, button_col4, _ = st.columns([2, 2, 2, 2, 4]) | |
| with button_col1: | |
| if st.button("π Copy Title", | |
| key="copy_title", | |
| help="Copy title to clipboard", | |
| type="secondary"): | |
| pyperclip.copy(title) | |
| st.success("Title copied!") | |
| with button_col2: | |
| if st.button("π Copy Content", | |
| key="copy_body", | |
| help="Copy full content to clipboard", | |
| type="secondary"): | |
| pyperclip.copy(body) | |
| st.success("Content copied!") | |
| with button_col3: | |
| is_favorite = st.session_state['selected_file'] in st.session_state['favorites'] | |
| if st.button("β " + ("Unfavorite" if is_favorite else "Favorite"), | |
| key="toggle_favorite", | |
| help="Add/remove from favorites", | |
| type="secondary"): | |
| if is_favorite: | |
| st.session_state['favorites'].remove(st.session_state['selected_file']) | |
| else: | |
| st.session_state['favorites'].add(st.session_state['selected_file']) | |
| with button_col4: | |
| if st.button("π Share", | |
| key="share_config", | |
| help="Copy shareable link", | |
| type="secondary"): | |
| share_url = f"https://github.com/danielrosehill/LLM-Assistants-Web-Library/blob/main/{st.session_state['selected_file']}" | |
| pyperclip.copy(share_url) | |
| st.success("Share link copied!") | |
| st.divider() | |
| # Display markdown content | |
| st.markdown(body, unsafe_allow_html=True) | |
| else: | |
| st.write("Select a configuration from the sidebar to view its details.") | |
| # Footer with GitHub badge | |
| st.markdown( | |
| """ | |
| <div style="position: fixed; bottom: 0; width: 100%; background-color: #f0f0f0; padding: 10px; text-align: center;"> | |
| <a href="https://github.com/danielrosehill/LLM-Assistants-Web-Library" target="_blank"> | |
| <img src="https://img.shields.io/badge/View_on_GitHub-181717?style=for-the-badge&logo=github&logoColor=white" alt="View on GitHub"> | |
| </a> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| if __name__ == "__main__": | |
| main() | |