Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| from streamlit.components.v1 import html | |
| from pathlib import Path | |
| import json | |
| import time | |
| from datetime import datetime | |
| import re | |
| import pandas as pd | |
| import yaml | |
| from io import StringIO | |
| import openpyxl | |
| import csv | |
| import base64 | |
| # Supported file types and their handlers | |
| FILE_TYPES = { | |
| "md": "π Markdown", | |
| "txt": "π Text", | |
| "json": "π§ JSON", | |
| "csv": "π CSV", | |
| "xlsx": "π Excel", | |
| "yaml": "βοΈ YAML", | |
| "xml": "π XML" | |
| } | |
| # Enhanced state initialization | |
| if 'file_data' not in st.session_state: | |
| st.session_state.file_data = {} | |
| if 'file_types' not in st.session_state: | |
| st.session_state.file_types = {} | |
| if 'md_outline' not in st.session_state: | |
| st.session_state.md_outline = {} | |
| if 'rendered_content' not in st.session_state: | |
| st.session_state.rendered_content = {} | |
| if 'file_history' not in st.session_state: | |
| st.session_state.file_history = [] | |
| if 'md_versions' not in st.session_state: | |
| st.session_state.md_versions = {} | |
| if 'md_files_history' not in st.session_state: | |
| st.session_state.md_files_history = [] | |
| def get_binary_file_downloader_html(bin_file, file_label='File'): | |
| """Generate a link allowing the data in a given file to be downloaded""" | |
| b64 = base64.b64encode(bin_file.encode()).decode() | |
| return f'<a href="data:text/plain;base64,{b64}" download="{file_label}">π₯ Download {file_label}</a>' | |
| def encode_content(content): | |
| """Encode content to base64""" | |
| return base64.b64encode(content.encode()).decode() | |
| def decode_content(encoded_content): | |
| """Decode content from base64""" | |
| return base64.b64decode(encoded_content.encode()).decode() | |
| def add_to_history(filename, content, action="uploaded"): | |
| """Add a file action to the history with timestamp""" | |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| encoded_content = encode_content(content) | |
| history_entry = { | |
| "timestamp": timestamp, | |
| "filename": filename, | |
| "action": action, | |
| "content": encoded_content | |
| } | |
| st.session_state.file_history.insert(0, history_entry) | |
| # Store version if it's a markdown file | |
| if filename.endswith('.md'): | |
| if filename not in st.session_state.md_versions: | |
| st.session_state.md_versions[filename] = [] | |
| st.session_state.md_versions[filename].append({ | |
| "timestamp": timestamp, | |
| "content": encoded_content, | |
| "action": action | |
| }) | |
| # Add to MD files history if not already present | |
| if filename not in [f["filename"] for f in st.session_state.md_files_history]: | |
| st.session_state.md_files_history.append({ | |
| "filename": filename, | |
| "timestamp": timestamp, | |
| "content": encoded_content | |
| }) | |
| def show_sidebar_history(): | |
| """Display markdown file history in the sidebar""" | |
| st.sidebar.markdown("### π Markdown Files History") | |
| for md_file in st.session_state.md_files_history: | |
| col1, col2, col3 = st.sidebar.columns([2, 1, 1]) | |
| with col1: | |
| st.markdown(f"**{md_file['filename']}**") | |
| with col2: | |
| if st.button("π Open", key=f"open_{md_file['filename']}"): | |
| content = decode_content(md_file['content']) | |
| st.session_state.file_data[md_file['filename']] = content | |
| st.session_state.file_types[md_file['filename']] = "md" | |
| st.session_state.md_outline[md_file['filename']] = parse_markdown_outline(content) | |
| st.experimental_rerun() | |
| with col3: | |
| download_link = get_binary_file_downloader_html( | |
| decode_content(md_file['content']), | |
| md_file['filename'] | |
| ) | |
| st.markdown(download_link, unsafe_allow_html=True) | |
| def show_file_history(): | |
| """Display the file history in a collapsible section""" | |
| if st.session_state.file_history: | |
| with st.expander("π File History", expanded=False): | |
| st.markdown("### Recent File Activities") | |
| for entry in st.session_state.file_history: | |
| col1, col2 = st.columns([2, 3]) | |
| with col1: | |
| st.markdown(f"**{entry['timestamp']}**") | |
| with col2: | |
| st.markdown(f"{entry['action'].title()}: {entry['filename']}") | |
| def show_markdown_versions(filename): | |
| """Display previous versions of a markdown file""" | |
| if filename in st.session_state.md_versions: | |
| versions = st.session_state.md_versions[filename] | |
| if len(versions) > 1: | |
| st.markdown("### π Previous Versions") | |
| version_idx = st.selectbox( | |
| "Select version to view", | |
| range(len(versions)-1), | |
| format_func=lambda x: f"Version {len(versions)-1-x} - {versions[x]['timestamp']}" | |
| ) | |
| if version_idx is not None: | |
| version = versions[version_idx] | |
| decoded_content = decode_content(version['content']) | |
| st.text_area( | |
| "Content", | |
| decoded_content, | |
| height=200, | |
| key=f"version_{filename}_{version_idx}", | |
| disabled=True | |
| ) | |
| if st.button(f"Restore to this version", key=f"restore_{filename}_{version_idx}"): | |
| st.session_state.file_data[filename] = decoded_content | |
| st.session_state.md_outline[filename] = parse_markdown_outline(decoded_content) | |
| add_to_history(filename, decoded_content, "restored") | |
| st.experimental_rerun() | |
| def parse_markdown_outline(content): | |
| """Generate an outline from markdown content""" | |
| lines = content.split('\n') | |
| outline = [] | |
| for line in lines: | |
| if line.strip().startswith('#'): | |
| level = len(line.split()[0]) | |
| title = line.strip('#').strip() | |
| outline.append({ | |
| 'level': level, | |
| 'title': title, | |
| 'indent': ' ' * (level - 1) | |
| }) | |
| return outline | |
| def create_markdown_tabs(content, filename): | |
| """Create tabs for markdown content viewing and editing""" | |
| tab1, tab2, tab3 = st.tabs(["π Editor", "π Preview", "π History"]) | |
| with tab1: | |
| edited_content = st.text_area( | |
| "Edit your markdown", | |
| content, | |
| height=300, | |
| key=f"edit_{filename}" | |
| ) | |
| if edited_content != content: | |
| st.session_state.file_data[filename] = edited_content | |
| st.session_state.md_outline[filename] = parse_markdown_outline(edited_content) | |
| add_to_history(filename, edited_content, "edited") | |
| content = edited_content | |
| with tab2: | |
| st.markdown("### Preview") | |
| st.markdown(content) | |
| if filename in st.session_state.md_outline: | |
| st.markdown("---") | |
| st.markdown("### π Document Outline") | |
| for item in st.session_state.md_outline[filename]: | |
| st.markdown(f"{item['indent']}β’ {item['title']}") | |
| with tab3: | |
| show_markdown_versions(filename) | |
| return content | |
| def read_file_content(uploaded_file): | |
| """Smart file reader with enhanced markdown handling""" | |
| file_type = uploaded_file.name.split('.')[-1].lower() | |
| try: | |
| if file_type == 'md': | |
| content = uploaded_file.getvalue().decode() | |
| st.session_state.md_outline[uploaded_file.name] = parse_markdown_outline(content) | |
| st.session_state.rendered_content[uploaded_file.name] = content | |
| add_to_history(uploaded_file.name, content) | |
| return content, "md" | |
| elif file_type == 'csv': | |
| df = pd.read_csv(uploaded_file) | |
| return df.to_string(), "csv" | |
| elif file_type == 'xlsx': | |
| df = pd.read_excel(uploaded_file) | |
| return df.to_string(), "xlsx" | |
| elif file_type == 'json': | |
| content = json.load(uploaded_file) | |
| return json.dumps(content, indent=2), "json" | |
| elif file_type == 'yaml': | |
| content = yaml.safe_load(uploaded_file) | |
| return yaml.dump(content), "yaml" | |
| else: # Default text handling | |
| return uploaded_file.getvalue().decode(), "txt" | |
| except Exception as e: | |
| st.error(f"π¨ Oops! Error reading {uploaded_file.name}: {str(e)}") | |
| return None, None | |
| def save_file_content(content, filename, file_type): | |
| """Smart file saver with enhanced markdown handling""" | |
| try: | |
| if file_type == "md": | |
| with open(filename, 'w') as f: | |
| f.write(content) | |
| st.session_state.rendered_content[filename] = content | |
| add_to_history(filename, content, "saved") | |
| elif file_type in ["csv", "xlsx"]: | |
| df = pd.read_csv(StringIO(content)) if file_type == "csv" else pd.read_excel(StringIO(content)) | |
| if file_type == "csv": | |
| df.to_csv(filename, index=False) | |
| else: | |
| df.to_excel(filename, index=False) | |
| elif file_type == "json": | |
| with open(filename, 'w') as f: | |
| json.dump(json.loads(content), f, indent=2) | |
| elif file_type == "yaml": | |
| with open(filename, 'w') as f: | |
| yaml.dump(yaml.safe_load(content), f) | |
| else: # Default text handling | |
| with open(filename, 'w') as f: | |
| f.write(content) | |
| return True | |
| except Exception as e: | |
| st.error(f"π¨ Error saving {filename}: {str(e)}") | |
| return False | |
| def main(): | |
| st.title("πβ¨ Super Smart File Handler with Markdown Magic! β¨π") | |
| # Show markdown history in sidebar | |
| show_sidebar_history() | |
| uploaded_file = st.file_uploader( | |
| "π€ Upload your file!", | |
| type=list(FILE_TYPES.keys()), | |
| help="Supports: " + ", ".join([f"{v} (.{k})" for k, v in FILE_TYPES.items()]) | |
| ) | |
| # Show file history at the top | |
| show_file_history() | |
| if uploaded_file: | |
| content, file_type = read_file_content(uploaded_file) | |
| if content is not None: | |
| st.session_state.file_data[uploaded_file.name] = content | |
| st.session_state.file_types[uploaded_file.name] = file_type | |
| st.success(f"π Loaded {FILE_TYPES.get(file_type, 'π')} file: {uploaded_file.name}") | |
| if st.session_state.file_data: | |
| st.subheader("π Your Files") | |
| for filename, content in st.session_state.file_data.items(): | |
| file_type = st.session_state.file_types[filename] | |
| with st.expander(f"{FILE_TYPES.get(file_type, 'π')} {filename}"): | |
| if file_type == "md": | |
| content = create_markdown_tabs(content, filename) | |
| else: | |
| edited_content = st.text_area( | |
| "Content", | |
| content, | |
| height=300, | |
| key=f"edit_{filename}" | |
| ) | |
| if edited_content != content: | |
| st.session_state.file_data[filename] = edited_content | |
| content = edited_content | |
| if st.button(f"πΎ Save {filename}"): | |
| if save_file_content(content, filename, file_type): | |
| st.success(f"β¨ Saved {filename} successfully!") | |
| if __name__ == "__main__": | |
| main() |