Spaces:
Running
Running
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 = [] | |
if 'combined_markdown' not in st.session_state: | |
st.session_state.combined_markdown = "" | |
def delete_all_md_files(): | |
"""Delete all markdown files except README.md""" | |
files_to_remove = [ | |
f for f in st.session_state.md_files_history | |
if f["filename"] != "README.md" | |
] | |
for file in files_to_remove: | |
filename = file["filename"] | |
if filename in st.session_state.file_data: | |
del st.session_state.file_data[filename] | |
if filename in st.session_state.file_types: | |
del st.session_state.file_types[filename] | |
if filename in st.session_state.md_outline: | |
del st.session_state.md_outline[filename] | |
if filename in st.session_state.rendered_content: | |
del st.session_state.rendered_content[filename] | |
if filename in st.session_state.md_versions: | |
del st.session_state.md_versions[filename] | |
st.session_state.md_files_history = [ | |
f for f in st.session_state.md_files_history | |
if f["filename"] == "README.md" | |
] | |
st.session_state.combined_markdown = "" | |
return len(files_to_remove) | |
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 combine_markdown_files(): | |
"""Combine all markdown files into a single document""" | |
combined = [] | |
for md_file in sorted(st.session_state.md_files_history, key=lambda x: x["filename"]): | |
content = decode_content(md_file["content"]) | |
combined.append(f"# {md_file['filename']}\n\n{content}\n\n---\n\n") | |
return "".join(combined) | |
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 | |
}) | |
# Update combined markdown | |
st.session_state.combined_markdown = combine_markdown_files() | |
def show_sidebar_history(): | |
"""Display markdown file history in the sidebar""" | |
st.sidebar.markdown("### π Markdown Files History") | |
# Add Delete All button | |
if st.sidebar.button("ποΈ Delete All (except README.md)"): | |
deleted_count = delete_all_md_files() | |
st.sidebar.success(f"Deleted {deleted_count} markdown files") | |
st.experimental_rerun() | |
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_book_view(): | |
"""Display all markdown files in a book-like format""" | |
if st.session_state.combined_markdown: | |
st.markdown("## π Book View") | |
st.markdown(st.session_state.combined_markdown) | |
# [Previous functions remain the same: show_file_history, show_markdown_versions, | |
# parse_markdown_outline, create_markdown_tabs, read_file_content, save_file_content] | |
def main(): | |
st.title("πβ¨ Super Smart File Handler with Markdown Magic! β¨π") | |
# Show markdown history in sidebar | |
show_sidebar_history() | |
# Add tabs for different upload methods | |
upload_tab, book_tab = st.tabs(["π€ File Upload", "π Book View"]) | |
with upload_tab: | |
col1, col2 = st.columns(2) | |
with col1: | |
uploaded_file = st.file_uploader( | |
"π€ Upload single file", | |
type=list(FILE_TYPES.keys()), | |
help="Supports: " + ", ".join([f"{v} (.{k})" for k, v in FILE_TYPES.items()]) | |
) | |
with col2: | |
uploaded_files = st.file_uploader( | |
"π Upload multiple files", | |
type=list(FILE_TYPES.keys()), | |
accept_multiple_files=True, | |
help="Upload multiple files to view as a book" | |
) | |
# Process single file upload | |
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}") | |
# Process multiple file upload | |
if uploaded_files: | |
for uploaded_file in uploaded_files: | |
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 {len(uploaded_files)} files") | |
# Show file history | |
show_file_history() | |
# Show individual files | |
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!") | |
with book_tab: | |
show_book_view() | |
if __name__ == "__main__": | |
main() |