File size: 9,380 Bytes
dc79d04
 
 
 
 
 
 
 
 
 
 
9f29fc7
dc79d04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587e3a6
 
 
 
bec170a
 
 
 
 
 
 
 
 
 
 
587e3a6
 
dc79d04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a6ad59e
 
587e3a6
737533c
 
5223b7f
3a0a225
bc1f061
 
5223b7f
d02fc66
2cd70f2
a6ad59e
3fc1e3d
ce4f901
 
8344b3b
 
737533c
 
3a0a225
3fc1e3d
b0c0467
278d3ee
737533c
 
b0c0467
 
 
278d3ee
 
 
 
 
 
 
b0c0467
5223b7f
 
 
dc79d04
 
 
 
 
 
472b72c
dc79d04
4cc33fb
 
 
 
 
 
 
 
 
 
472b72c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a6ad59e
 
 
 
 
 
 
 
 
472b72c
a6ad59e
472b72c
6c91704
a6ad59e
 
472b72c
dc79d04
 
 
 
 
939b4b0
 
 
 
 
 
 
 
dc79d04
 
bccb934
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc79d04
bccb934
dc79d04
bccb934
dc79d04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
import gradio as gr
import sqlite3
import pandas as pd
from huggingface_hub import hf_hub_download
import os

# Download the database from HF dataset
def download_database():
    """Download vla_foundry.db from the HF dataset"""
    try:
        db_path = hf_hub_download(
            repo_id="TRI-ML/vla_foundry_db",
            filename="vla_foundry.db",
            repo_type="dataset"
        )
        return db_path
    except Exception as e:
        print(f"Error downloading database: {e}")
        return None

# Load data from database
def load_database_tables(db_path):
    """Load all tables from the database"""
    if not db_path or not os.path.exists(db_path):
        return {}, []

    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    # Get all table names
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    tables = [row[0] for row in cursor.fetchall()]

    # Load each table into a DataFrame
    table_data = {}
    for table in tables:
        try:
            df = pd.read_sql_query(f"SELECT * FROM {table}", conn)
            table_data[table] = df
        except Exception as e:
            print(f"Error loading table {table}: {e}")

    conn.close()
    return table_data, tables

# Initialize database
db_path = download_database()
table_data, table_names = load_database_tables(db_path)

# Column width configuration (in pixels)
# Specify widths for specific columns across all tables
# Format: {"column_name": width_in_px}
column_widths = {
    "created_by": 150,
    "cfg": 500,
    "git_commit_hash": 150,
    "git_branch": 150,
    "git_remote_url": 150,
    "git_has_local_changes": 150,
    "git_local_chances": 150,
    "dataset_source_paths": 500,
    "model_checkpoints_path": 500,
    "fixed_model_path": 500,
    "completed": 150,
}

# Function to get table data with filters
def get_filtered_data(table_name, search_query="", column_filter="All", sort_column="", sort_order="Ascending"):
    """Get filtered and sorted data from selected table"""
    if table_name not in table_data:
        return pd.DataFrame()

    df = table_data[table_name].copy()

    # Apply search filter
    if search_query.strip():
        # Search across all columns
        mask = df.astype(str).apply(lambda x: x.str.contains(search_query, case=False, na=False)).any(axis=1)
        df = df[mask]

    # Apply column-specific filter
    if column_filter != "All" and column_filter in df.columns:
        # Show only rows where the selected column has non-null values
        df = df[df[column_filter].notna()]

    # Apply sorting
    if sort_column and sort_column in df.columns:
        ascending = (sort_order == "Ascending")
        df = df.sort_values(by=sort_column, ascending=ascending)

    return df

def update_column_choices(table_name):
    """Update column choices based on selected table"""
    if table_name not in table_data:
        return gr.update(choices=["All"]), gr.update(choices=[])

    columns = ["All"] + list(table_data[table_name].columns)
    return gr.update(choices=columns, value="All"), gr.update(choices=list(table_data[table_name].columns), value="")

def get_table_info(table_name):
    """Get information about the selected table"""
    if table_name not in table_data:
        return "No table selected"

    df = table_data[table_name]
    info = f"**Table: {table_name}**\n\n"
    info += f"- Total rows: {len(df)}\n"
    info += f"- Total columns: {len(df.columns)}\n"
    info += f"- Columns: {', '.join(df.columns)}\n"

    return info

# Create Gradio interface with CSS
css = """
    /* Default table cell styling */
    table td,
    table th {
        white-space: nowrap !important;
        overflow-x: auto !important;
        font-size: 12px !important;
        padding: 4px 8px !important;
    }

    /* Make table container scrollable */
    .table-wrap {
        max-height: 600px !important;
        overflow-y: auto !important;
        overflow-x: visible !important;
    }

    /* Ensure table uses fixed layout */
    table {
        table-layout: fixed !important;
    }

    /* Prevent editing - make cells read-only but allow selection */
    table input,
    table textarea {
        background-color: transparent !important;
        border: none !important;
        cursor: text !important;
        user-select: text !important;
    }

    /* Make cells read-only by preventing editing on focus */
    table input:focus,
    table textarea:focus {
        outline: none !important;
    }
"""

with gr.Blocks(title="VLA Foundry Database Viewer", css=css) as demo:
    gr.Markdown("# 🤖 VLA Foundry Database Viewer")
    gr.Markdown("Explore the VLA Foundry database with searchable, filterable, and sortable tables.")

    if not table_data:
        gr.Markdown("⚠️ **Error**: Could not load database. Please check if the database file exists in the dataset.")
    else:
        # Top section: Table selector and info
        with gr.Row():
            with gr.Column(scale=2):
                table_selector = gr.Dropdown(
                    choices=table_names,
                    label="Select Table",
                    value=table_names[0] if table_names else None
                )
            with gr.Column(scale=3):
                table_info = gr.Markdown(
                    value=get_table_info(table_names[0]) if table_names else ""
                )

        # Filters and sorting section
        with gr.Row():
            search_box = gr.Textbox(
                label="Search (across all columns)",
                placeholder="Enter search term...",
                value="",
                scale=2
            )
            column_filter = gr.Dropdown(
                choices=["All"],
                label="Filter by Column (show non-null)",
                value="All",
                scale=1
            )
            sort_column = gr.Dropdown(
                choices=[],
                label="Sort by Column",
                value="",
                scale=1
            )
            sort_order = gr.Radio(
                choices=["Ascending", "Descending"],
                label="Sort Order",
                value="Ascending",
                scale=1
            )
            clear_btn = gr.Button("Clear Filters", scale=1)

        # Data table with custom column widths
        initial_df = table_data[table_names[0]] if table_names else pd.DataFrame()

        # Build column_widths list based on the column_widths config
        col_width_list = []
        if not initial_df.empty:
            for col in initial_df.columns:
                col_width_list.append(column_widths.get(col, 300))

        data_table = gr.Dataframe(
            value=initial_df,
            label="Table Data",
            interactive=True,
            wrap=False,
            column_widths=col_width_list if col_width_list else None
        )

        # Event handlers
        def update_table(table_name, search, col_filter, sort_col, sort_ord):
            filtered_df = get_filtered_data(table_name, search, col_filter, sort_col, sort_ord)
            info = get_table_info(table_name)

            # Build column widths for the current table
            col_width_list = []
            if not filtered_df.empty:
                for col in filtered_df.columns:
                    col_width_list.append(column_widths.get(col, 300))

            return gr.update(value=filtered_df, column_widths=col_width_list if col_width_list else None), info

        # Update columns when table changes
        def on_table_change(table_name):
            # Reset filters and update column choices
            col_filter_update, sort_col_update = update_column_choices(table_name)
            # Get the updated table with reset filters
            filtered_df = get_filtered_data(table_name, "", "All", "", "Ascending")
            info = get_table_info(table_name)

            # Build column widths for the new table
            col_width_list = []
            if not filtered_df.empty:
                for col in filtered_df.columns:
                    col_width_list.append(column_widths.get(col, 300))

            table_update = gr.update(value=filtered_df, column_widths=col_width_list if col_width_list else None)

            return col_filter_update, sort_col_update, table_update, info, "", "Ascending"

        table_selector.change(
            fn=on_table_change,
            inputs=[table_selector],
            outputs=[column_filter, sort_column, data_table, table_info, search_box, sort_order]
        )

        # Update table when filters/sorting change
        for component in [search_box, column_filter, sort_column, sort_order]:
            component.change(
                fn=update_table,
                inputs=[table_selector, search_box, column_filter, sort_column, sort_order],
                outputs=[data_table, table_info]
            )

        # Clear filters
        def clear_filters():
            return "", "All", "", "Ascending"

        clear_btn.click(
            fn=clear_filters,
            outputs=[search_box, column_filter, sort_column, sort_order]
        ).then(
            fn=update_table,
            inputs=[table_selector, search_box, column_filter, sort_column, sort_order],
            outputs=[data_table, table_info]
        )

if __name__ == "__main__":
    demo.launch()