ChaosTong commited on
Commit
2b9c75d
·
verified ·
1 Parent(s): ba63511

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +173 -0
  2. data.json +22 -0
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import json
4
+ import os
5
+
6
+ # --- Configuration & Helpers ---
7
+ DATA_DIR = '.' # Directory to scan for JSON files (current directory)
8
+
9
+ def find_json_files(directory):
10
+ """Finds all .json files in the specified directory."""
11
+ try:
12
+ files = [f for f in os.listdir(directory) if f.endswith('.json') and os.path.isfile(os.path.join(directory, f))]
13
+ return files
14
+ except FileNotFoundError:
15
+ return []
16
+
17
+ # --- Data Processing Functions ---
18
+
19
+ def load_data(selected_file):
20
+ """Loads data from the selected JSON file into a Pandas DataFrame."""
21
+ if not selected_file:
22
+ # No file selected, return empty DataFrame and instructions
23
+ df = pd.DataFrame(columns=['Name', 'Title', 'Params'])
24
+ status = "Please select a JSON file from the dropdown to load."
25
+ return df, status
26
+
27
+ file_path = os.path.join(DATA_DIR, selected_file)
28
+
29
+ if not os.path.exists(file_path):
30
+ # Should not happen if dropdown is populated correctly, but handle anyway
31
+ df = pd.DataFrame(columns=['Name', 'Title', 'Params'])
32
+ status = f"Error: File '{selected_file}' not found in '{DATA_DIR}'."
33
+ return df, status
34
+ else:
35
+ try:
36
+ # Handle empty file case
37
+ if os.path.getsize(file_path) == 0:
38
+ df = pd.DataFrame(columns=['Name', 'Title', 'Params'])
39
+ status = f"'{selected_file}' is empty. Displaying empty table. You can add rows and save."
40
+ return df, status
41
+
42
+ # Try reading JSON
43
+ df = pd.read_json(file_path, orient='records', dtype=str) # Read all as string initially
44
+ # Ensure required columns exist, fill missing with empty strings
45
+ df = df.reindex(columns=['Name', 'Title', 'Params'], fill_value='')
46
+ # Fill any remaining NaN/None values just in case
47
+ df = df.fillna('')
48
+ status = f"Data loaded successfully from '{selected_file}'."
49
+ except ValueError as e: # Handles JSON decoding errors or incorrect format
50
+ print(f"Error loading JSON from {selected_file}: {e}")
51
+ df = pd.DataFrame(columns=['Name', 'Title', 'Params'])
52
+ status = f"Error loading '{selected_file}': Invalid JSON format or structure ({e}). Displaying empty table."
53
+ except Exception as e:
54
+ print(f"Unexpected error loading {selected_file}: {e}")
55
+ df = pd.DataFrame(columns=['Name', 'Title', 'Params'])
56
+ status = f"Unexpected error loading '{selected_file}': {e}. Displaying empty table."
57
+
58
+ # Ensure consistent string type for display
59
+ df['Name'] = df['Name'].astype(str)
60
+ df['Title'] = df['Title'].astype(str)
61
+ df['Params'] = df['Params'].astype(str)
62
+
63
+ return df, status
64
+
65
+ def save_data_internal(data_list, file_path):
66
+ """Writes a Python list to a specific JSON file path."""
67
+ try:
68
+ with open(file_path, 'w', encoding='utf-8') as f:
69
+ json.dump(data_list, f, indent=2, ensure_ascii=False)
70
+ return True, f"Data saved successfully to '{os.path.basename(file_path)}'."
71
+ except Exception as e:
72
+ print(f"Error saving JSON to {file_path}: {e}")
73
+ return False, f"Error saving data to '{os.path.basename(file_path)}': {e}"
74
+
75
+ def save_data(dataframe, selected_file):
76
+ """Converts DataFrame and saves it to the selected JSON file."""
77
+ if not selected_file:
78
+ return "Error: No file selected to save to. Please select a file first."
79
+ if dataframe is None:
80
+ return f"Error: No data loaded or present to save to '{selected_file}'."
81
+
82
+ file_path = os.path.join(DATA_DIR, selected_file)
83
+
84
+ try:
85
+ # Convert DataFrame to list of dictionaries
86
+ # Replace empty strings potentially introduced by editing back to None for cleaner JSON
87
+ # but keep actual 'Params' JSON strings even if empty {}
88
+ data_list = dataframe.to_dict(orient='records')
89
+
90
+ # Clean data: Remove None values, ensure required keys exist
91
+ cleaned_data = []
92
+ for item in data_list:
93
+ # Only keep key if value is not None, unless it's 'Params' which can be an empty string '{}' etc.
94
+ cleaned_item = {k: v for k, v in item.items() if v is not None or k == 'Params'} # Keep params even if empty string
95
+ # Ensure standard keys exist, defaulting to empty string if missing after None removal
96
+ cleaned_item.setdefault('Name', '')
97
+ cleaned_item.setdefault('Title', '')
98
+ cleaned_item.setdefault('Params', '')
99
+ cleaned_data.append(cleaned_item)
100
+
101
+
102
+ _, status = save_data_internal(cleaned_data, file_path)
103
+ return status
104
+ except Exception as e:
105
+ print(f"Error preparing data for saving to {selected_file}: {e}")
106
+ return f"Error preparing data for saving to '{selected_file}': {e}"
107
+
108
+ # --- Gradio Interface Definition ---
109
+
110
+ # Find available JSON files at startup
111
+ available_files = find_json_files(DATA_DIR)
112
+
113
+ with gr.Blocks() as app:
114
+ gr.Markdown(f"""
115
+ # Multi-JSON Data Editor
116
+ Select a JSON file from the dropdown to load, view, edit, and save data.
117
+ Files are scanned from the directory: `{os.path.abspath(DATA_DIR)}`
118
+ """)
119
+
120
+ # Status Textbox
121
+ status_text = gr.Textbox(label="Status", interactive=False, value="Select a file to begin.")
122
+
123
+ # File Selector Dropdown
124
+ file_selector = gr.Dropdown(
125
+ choices=available_files,
126
+ label="Select JSON File",
127
+ info="Choose the JSON file you want to edit.",
128
+ interactive=True
129
+ )
130
+
131
+ # DataFrame for Editing
132
+ data_df = gr.DataFrame(
133
+ headers=['Name', 'Title', 'Params'],
134
+ datatype=['str', 'str', 'str'],
135
+ label="Data Items",
136
+ interactive=True,
137
+ row_count=(10, "dynamic"),
138
+ col_count=(3, "fixed"),
139
+ )
140
+
141
+ # Action Buttons
142
+ with gr.Row():
143
+ # Load button might be redundant if dropdown change triggers load, but can be useful for refresh
144
+ load_button = gr.Button("🔄 Reload Selected File")
145
+ save_button = gr.Button("💾 Save Changes to Selected File")
146
+
147
+ # --- Event Handling ---
148
+
149
+ # When the dropdown selection changes, load the corresponding file
150
+ file_selector.change(
151
+ fn=load_data,
152
+ inputs=file_selector,
153
+ outputs=[data_df, status_text]
154
+ )
155
+
156
+ # Button click events - they use the currently selected file from the dropdown
157
+ load_button.click(
158
+ fn=load_data,
159
+ inputs=file_selector, # Pass the current dropdown value
160
+ outputs=[data_df, status_text]
161
+ )
162
+ save_button.click(
163
+ fn=save_data,
164
+ inputs=[data_df, file_selector], # Pass current DataFrame AND current dropdown value
165
+ outputs=status_text
166
+ )
167
+
168
+ # --- Launch the App ---
169
+ if __name__ == "__main__":
170
+ if not available_files:
171
+ print(f"Warning: No .json files found in the directory '{os.path.abspath(DATA_DIR)}'.")
172
+ print("Create some .json files in the directory and restart the application.")
173
+ app.launch()
data.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "Name": "VC_Test",
4
+ "Title": "VC_Test",
5
+ "Params": "{}"
6
+ },
7
+ {
8
+ "Name": "JS_V3ProductDetailViewController",
9
+ "Title": "NH2013506",
10
+ "Params": "{\"SPU\":\"NH2013506\"}"
11
+ },
12
+ {
13
+ "Name": "JS_V3ProductDetailViewController",
14
+ "Title": "NH2013508",
15
+ "Params": "{\"SPU\":\"NH2013508\"}"
16
+ },
17
+ {
18
+ "Name": "JS_V3ProductDetailViewController",
19
+ "Title": "NH2013633",
20
+ "Params": "{\"SPU\":\"NH2013633\"}"
21
+ }
22
+ ]