MarkdownMagicEditor.md / app-backup2-multifilehistoryadded.py
awacke1's picture
Rename app.py to app-backup2-multifilehistoryadded.py
cdca39a verified
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()