| import os |
| import sqlite3 |
| import shutil |
| import mimetypes |
| from datetime import datetime, timezone |
| import gradio as gr |
|
|
| DB_NAME = "files.db" |
| UPLOAD_DIR = "uploads" |
| MAX_EMBEDDED_SIZE = 1 * 1024 * 1024 |
|
|
| def init_db(db_path=DB_NAME): |
| """Initialize the SQLite database schema if it doesn't exist.""" |
| conn = sqlite3.connect(db_path) |
| cursor = conn.cursor() |
| cursor.execute(""" |
| CREATE TABLE IF NOT EXISTS files ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| filename TEXT NOT NULL, |
| file_type TEXT, |
| file_size_bytes INTEGER NOT NULL, |
| upload_timestamp TEXT NOT NULL, |
| is_large_file INTEGER NOT NULL, |
| file_content_blob BLOB, |
| relative_path TEXT |
| ) |
| """) |
| conn.commit() |
| conn.close() |
| os.makedirs(UPLOAD_DIR, exist_ok=True) |
|
|
| def process_uploaded_files(files, db_path=DB_NAME, upload_dir=UPLOAD_DIR): |
| """Process multiple uploaded files and log them into the SQLite database.""" |
| if not files: |
| return "No files uploaded.", get_records_df(db_path), gr.update() |
|
|
| init_db(db_path) |
| conn = sqlite3.connect(db_path) |
| cursor = conn.cursor() |
| |
| uploaded_count = 0 |
| for file_obj in files: |
| |
| file_path = file_obj.name if hasattr(file_obj, "name") else str(file_obj) |
| orig_filename = os.path.basename(file_path) |
| file_size = os.path.getsize(file_path) |
| file_type, _ = mimetypes.guess_type(file_path) |
| if not file_type: |
| file_type = "application/octet-stream" |
| |
| timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") |
|
|
| if file_size > MAX_EMBEDDED_SIZE: |
| |
| os.makedirs(upload_dir, exist_ok=True) |
| dest_filename = f"{int(datetime.now(timezone.utc).timestamp())}_{orig_filename}" |
| dest_path = os.path.join(upload_dir, dest_filename) |
| shutil.copy(file_path, dest_path) |
| |
| cursor.execute(""" |
| INSERT INTO files (filename, file_type, file_size_bytes, upload_timestamp, is_large_file, file_content_blob, relative_path) |
| VALUES (?, ?, ?, ?, ?, ?, ?) |
| """, (orig_filename, file_type, file_size, timestamp, 1, None, dest_path)) |
| else: |
| |
| with open(file_path, "rb") as f: |
| blob_data = f.read() |
| |
| cursor.execute(""" |
| INSERT INTO files (filename, file_type, file_size_bytes, upload_timestamp, is_large_file, file_content_blob, relative_path) |
| VALUES (?, ?, ?, ?, ?, ?, ?) |
| """, (orig_filename, file_type, file_size, timestamp, 0, blob_data, None)) |
| |
| uploaded_count += 1 |
|
|
| conn.commit() |
| conn.close() |
|
|
| df = get_records_df(db_path) |
| large_files_dropdown = get_large_files_choices(db_path) |
| return f"Successfully processed and logged {uploaded_count} file(s).", df, large_files_dropdown |
|
|
| def get_records_df(db_path=DB_NAME): |
| """Retrieve database records as a list of lists for Gradio Dataframe.""" |
| if not os.path.exists(db_path): |
| return [] |
| |
| conn = sqlite3.connect(db_path) |
| cursor = conn.cursor() |
| cursor.execute(""" |
| SELECT id, filename, file_type, file_size_bytes, upload_timestamp, is_large_file, |
| CASE WHEN file_content_blob IS NOT NULL THEN 'Stored in DB (BLOB)' ELSE 'Not Stored (BLOB IS NULL)' END as blob_status, |
| COALESCE(relative_path, 'N/A') as relative_path |
| FROM files |
| ORDER BY id DESC |
| """) |
| rows = cursor.fetchall() |
| conn.close() |
| return rows |
|
|
| def get_large_files_choices(db_path=DB_NAME): |
| """Get list of choices for large file download dropdown.""" |
| if not os.path.exists(db_path): |
| return gr.update(choices=[], value=None) |
| |
| conn = sqlite3.connect(db_path) |
| cursor = conn.cursor() |
| cursor.execute(""" |
| SELECT id, filename, relative_path |
| FROM files |
| WHERE is_large_file = 1 AND relative_path IS NOT NULL |
| ORDER BY id DESC |
| """) |
| rows = cursor.fetchall() |
| conn.close() |
| |
| choices = [f"ID {r[0]}: {r[1]} ({r[2]})" for r in rows] |
| val = choices[0] if choices else None |
| return gr.update(choices=choices, value=val) |
|
|
| def download_selected_large_file(selected_item, db_path=DB_NAME): |
| """Return the file path for the selected large file to allow download.""" |
| if not selected_item: |
| return None |
| |
| try: |
| file_id = int(selected_item.split(":")[0].replace("ID", "").strip()) |
| except Exception: |
| return None |
|
|
| conn = sqlite3.connect(db_path) |
| cursor = conn.cursor() |
| cursor.execute("SELECT relative_path FROM files WHERE id = ?", (file_id,)) |
| row = cursor.fetchone() |
| conn.close() |
|
|
| if row and row[0] and os.path.exists(row[0]): |
| return row[0] |
| return None |
|
|
| def download_database(db_path=DB_NAME): |
| """Return database file for downloading.""" |
| if os.path.exists(db_path): |
| return db_path |
| return None |
|
|
| |
| init_db() |
|
|
| |
| with gr.Blocks(title="Personal SQL DB Generator") as demo: |
| gr.Markdown("# ๐๏ธ Personal SQL DB File Generator & Logger") |
| gr.Markdown( |
| "Upload multiple files of any type. Files **<= 1MB** are stored directly as binary BLOBs inside the SQLite database. " |
| "Files **> 1MB** are stored on disk with relative path references stored in the database. " |
| "You can inspect logged entries, download the complete SQLite `.db` database file, and download big files." |
| ) |
|
|
| with gr.Tab("Upload Files & Log to SQL"): |
| file_input = gr.File( |
| label="Select or Drag & Drop Multiple Files", |
| file_count="multiple", |
| type="filepath" |
| ) |
| upload_button = gr.Button("Upload & Log to Database", variant="primary") |
| status_output = gr.Textbox(label="Status Log", interactive=False) |
|
|
| with gr.Tab("Database Records"): |
| refresh_button = gr.Button("๐ Refresh Database Table") |
| db_table = gr.Dataframe( |
| headers=["ID", "Filename", "Type", "Size (bytes)", "Timestamp", "Is Large (>1MB)", "BLOB Status", "Relative Path"], |
| value=get_records_df(), |
| interactive=False, |
| wrap=True |
| ) |
|
|
| with gr.Tab("Downloads"): |
| with gr.Row(): |
| with gr.Column(): |
| gr.Markdown("### ๐ฆ Download SQLite Database") |
| db_download_btn = gr.Button("Prepare Database File") |
| db_file_output = gr.File(label="Download SQLite DB (.db)") |
|
|
| with gr.Column(): |
| gr.Markdown("### ๐ Download Large Files (>1MB)") |
| large_files_dropdown = gr.Dropdown( |
| label="Select Large File to Download", |
| choices=[c for c in get_large_files_choices()["choices"]] if isinstance(get_large_files_choices(), dict) else [], |
| interactive=True |
| ) |
| refresh_dropdown_btn = gr.Button("Refresh Large Files List") |
| download_large_btn = gr.Button("Prepare Large File Download") |
| large_file_output = gr.File(label="Download File") |
|
|
| |
| upload_button.click( |
| fn=process_uploaded_files, |
| inputs=[file_input], |
| outputs=[status_output, db_table, large_files_dropdown] |
| ) |
|
|
| refresh_button.click( |
| fn=get_records_df, |
| inputs=[], |
| outputs=[db_table] |
| ) |
|
|
| db_download_btn.click( |
| fn=download_database, |
| inputs=[], |
| outputs=[db_file_output] |
| ) |
|
|
| refresh_dropdown_btn.click( |
| fn=get_large_files_choices, |
| inputs=[], |
| outputs=[large_files_dropdown] |
| ) |
|
|
| download_large_btn.click( |
| fn=download_selected_large_file, |
| inputs=[large_files_dropdown], |
| outputs=[large_file_output] |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|