File size: 8,182 Bytes
078a3d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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  # 1 MB in bytes

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_obj is a Gradio file object or filepath string depending on Gradio version
        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:
            # File > 1MB: save to uploads directory and reference relative path
            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:
            # File <= 1MB: store binary content directly in database
            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

# Initialize DB on load
init_db()

# Build Gradio UI
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")

    # Event handlers
    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()