xslstoJSON / src /app.py
Kikulika's picture
Update src/app.py
58272c9 verified
Raw
History Blame Contribute Delete
15.5 kB
import streamlit as st
import pandas as pd
import json
import io
import os
from datetime import datetime
import numpy as np
import base64
# Configure page
st.set_page_config(
page_title="Excel to JSON Converter",
page_icon="📊",
layout="wide"
)
# Debug information
with st.expander("Directory Structure"):
st.code(f"Current working directory: {os.getcwd()}")
st.code(f"Directory contents: {os.listdir('.')}")
# Check tmp directory
if os.path.exists('tmp'):
st.code(f"tmp directory exists: {os.path.exists('tmp')}")
st.code(f"tmp directory permissions: {oct(os.stat('tmp').st_mode)[-3:]}")
st.code(f"tmp directory is writable: {os.access('tmp', os.W_OK)}")
try:
st.code(f"tmp directory contents: {os.listdir('tmp')}")
except Exception as e:
st.error(f"Error listing tmp directory: {str(e)}")
else:
st.error("tmp directory does not exist!")
st.title("Excel to JSON Converter")
st.markdown("""
Upload an Excel file and convert it to a standard JSON format matching your template.
The app will maintain all the original columns and convert values to the appropriate format.
""")
def handle_nan(obj):
"""Convert NaN values to 0.0 to match your JSON format"""
if isinstance(obj, float) and np.isnan(obj):
return 0.0
return obj
def process_excel_data(excel_data, filename, sheet_name=None):
"""Process Excel file data"""
try:
# Try to read the Excel file
if sheet_name:
df = pd.read_excel(excel_data, sheet_name=sheet_name)
else:
df = pd.read_excel(excel_data)
# Show dimensions of the dataframe
st.info(f"Successfully read {df.shape[0]} rows and {df.shape[1]} columns from the Excel file")
# Fill NaN values
df = df.fillna(0.0)
# Convert dataframe to list of dictionaries (records)
result = {"DateStamp": datetime.now().isoformat(), "PriceList": []}
for _, row in df.iterrows():
record = {}
for column in df.columns:
# Convert pandas Timestamp to ISO format string if needed
if isinstance(row[column], pd.Timestamp):
record[column] = row[column].isoformat()
# Convert float values to match the format in examples
elif isinstance(row[column], (float, np.float64, np.float32)):
record[column] = float(row[column])
else:
record[column] = row[column]
# Add filename if it doesn't exist in the record
if "FileName" not in record:
record["FileName"] = filename
result["PriceList"].append(record)
# Convert to JSON string with indentation
json_str = json.dumps(result, indent=2, default=handle_nan)
return json_str, result
except Exception as e:
st.error(f"Error: {str(e)}")
import traceback
st.code(traceback.format_exc())
return None, None
def get_download_link(json_str, filename="converted_data.json"):
"""Generate a download link for the JSON file"""
b64 = base64.b64encode(json_str.encode()).decode()
href = f'<a href="data:file/json;base64,{b64}" download="{filename}">Download JSON File</a>'
return href
# Create tabs for different approaches
tab1, tab2 = st.tabs(["File Upload", "Sample Data Demo"])
with tab1:
st.info("For large files (>5MB), you may need to split them into smaller Excel files first.")
# File uploader
uploaded_file = st.file_uploader("Upload Excel File (.xlsx, .xls)", type=["xlsx", "xls"])
if uploaded_file is not None:
# Display success message
st.success(f"File uploaded: {uploaded_file.name}")
st.write(f"File size: {uploaded_file.size / 1024:.2f} KB")
try:
# Read Excel file into memory
excel_data = io.BytesIO(uploaded_file.getvalue())
try:
# Try to get sheet names
xls = pd.ExcelFile(excel_data)
sheet_names = xls.sheet_names
st.success(f"Successfully read {len(sheet_names)} sheets")
# Display available sheets
if len(sheet_names) > 1:
selected_sheet = st.selectbox("Select Sheet", options=sheet_names)
else:
selected_sheet = sheet_names[0]
st.info(f"Using sheet: {selected_sheet}")
# Process button
if st.button("Convert to JSON", type="primary"):
# Reset the file pointer
excel_data = io.BytesIO(uploaded_file.getvalue())
# Process the file
with st.spinner("Converting..."):
json_str, json_data = process_excel_data(excel_data, uploaded_file.name, selected_sheet)
if json_str and json_data:
st.success("Conversion successful!")
# Create tabs for different views
json_tab, table_tab, download_tab = st.tabs(["JSON Preview", "Table Preview", "Download"])
with json_tab:
# For large JSON, show only the first part
if len(json_str) > 100000:
st.warning("JSON is too large to display fully. Showing first 100,000 characters.")
st.code(json_str[:100000] + "...", language="json")
else:
st.code(json_str, language="json")
with table_tab:
if "PriceList" in json_data:
preview_df = pd.DataFrame(json_data["PriceList"])
if len(preview_df) > 1000:
st.write(f"Showing first 1000 rows of {len(json_data['PriceList'])} total")
st.dataframe(preview_df.head(1000), use_container_width=True)
else:
st.dataframe(preview_df, use_container_width=True)
with download_tab:
st.markdown(get_download_link(json_str, f"{os.path.splitext(uploaded_file.name)[0]}.json"), unsafe_allow_html=True)
st.info("Click the link above to download the JSON file.")
except Exception as e:
st.error(f"Error reading Excel file: {str(e)}")
import traceback
st.code(traceback.format_exc())
# Fallback: try simple conversion without sheet selection
if st.button("Try Simple Conversion"):
try:
# Reset the pointer and try simple conversion
excel_data = io.BytesIO(uploaded_file.getvalue())
json_str, _ = process_excel_data(excel_data, uploaded_file.name)
if json_str:
st.success("Simple conversion successful!")
# For large JSON, show only the first part
if len(json_str) > 100000:
st.warning("JSON is too large to display fully. Showing first 100,000 characters.")
st.code(json_str[:100000] + "...", language="json")
else:
st.code(json_str, language="json")
st.markdown(get_download_link(json_str, f"{os.path.splitext(uploaded_file.name)[0]}.json"), unsafe_allow_html=True)
except Exception as e2:
st.error(f"Simple conversion failed: {str(e2)}")
st.code(traceback.format_exc())
except Exception as e:
st.error(f"Error processing file: {str(e)}")
import traceback
st.code(traceback.format_exc())
with tab2:
st.info("This demo uses sample data to show how the converter works.")
# Create sample data
st.write("### Sample Data")
# Generate sample data that matches your expected format
sample_data = {
"Supplier": ["TestCompany", "TestCompany", "TestCompany"],
"Manufacturer": ["AJA", "AJA", "GRASS VALLEY"],
"ModelCode": ["TEST-001", "TEST-002", "TEST-003"],
"ModelDescription": ["Test Product 1", "Test Product 2", "Test Product 3"],
"T1List": [0.0, 100.0, 200.0],
"T1Cost": [0.0, 80.0, 160.0],
"T2List": [150.0, 250.0, 350.0],
"T2Cost": [120.0, 200.0, 280.0],
"ISOCurrency": ["EUR", "EUR", "USD"],
"ValidityDate": ["2025-12-31", "2025-12-31", "2025-12-31"],
"T1orT2": ["T2", "T2", "T2"],
"MaterialID": ["MAT-001", "MAT-002", "MAT-003"],
"SAPNumber": ["SAP-001", "SAP-002", "SAP-003"],
"ModelDescriptionEnglish": ["Test Product 1 in English", "Test Product 2 in English", "Test Product 3 in English"],
"QuoteOrPriceList": ["Price List", "Price List", "Price List"],
"WeightKg": [1.5, 2.0, 3.5],
"HeightMm": [100.0, 150.0, 200.0],
"LengthMm": [200.0, 250.0, 300.0],
"WidthMm": [150.0, 175.0, 225.0],
"PowerWatts": [50.0, 75.0, 100.0],
"FileName": ["SampleData.xlsx", "SampleData.xlsx", "SampleData.xlsx"]
}
# Convert to DataFrame
sample_df = pd.DataFrame(sample_data)
# Display the sample data
st.dataframe(sample_df)
# Allow user to edit the sample data
st.write("### Edit Sample Data (Optional)")
# Let user add a row
with st.expander("Add or Edit Rows"):
# Add simple editing capabilities
new_row = {}
col1, col2 = st.columns(2)
with col1:
new_row["Supplier"] = st.text_input("Supplier", "YourCompany")
new_row["Manufacturer"] = st.text_input("Manufacturer", "YourBrand")
new_row["ModelCode"] = st.text_input("ModelCode", "CUSTOM-001")
new_row["ModelDescription"] = st.text_input("ModelDescription", "Custom Product")
with col2:
new_row["T2List"] = st.number_input("T2List", value=499.99)
new_row["T2Cost"] = st.number_input("T2Cost", value=399.99)
new_row["ISOCurrency"] = st.selectbox("ISOCurrency", ["EUR", "USD", "GBP"])
new_row["ValidityDate"] = st.date_input("ValidityDate")
if st.button("Add Row to Sample Data"):
# Fill in missing fields with defaults
for col in sample_df.columns:
if col not in new_row:
if col == "FileName":
new_row[col] = "SampleData.xlsx"
elif "Date" in col:
new_row[col] = "2025-12-31"
elif sample_df[col].dtype == float:
new_row[col] = 0.0
else:
new_row[col] = ""
# Append the new row
sample_df = pd.concat([sample_df, pd.DataFrame([new_row])], ignore_index=True)
st.success("Row added!")
st.dataframe(sample_df)
# Convert button
if st.button("Convert Sample Data to JSON", key="convert2"):
json_str, json_data = process_excel_data(sample_df, "SampleData.xlsx")
if json_str and json_data:
st.success("Conversion successful!")
# Create tabs for different views
json_tab, table_tab, download_tab = st.tabs(["JSON", "Table", "Download"])
with json_tab:
st.code(json_str, language="json")
with table_tab:
if "PriceList" in json_data:
preview_df = pd.DataFrame(json_data["PriceList"])
st.dataframe(preview_df)
with download_tab:
st.markdown(get_download_link(json_str, "sample_data.json"), unsafe_allow_html=True)
st.info("Click the link above to download the JSON file.")
# Information about expected format
with st.expander("Expected Excel Format"):
st.markdown("""
Your Excel file should contain columns such as:
- Supplier
- Manufacturer
- ModelCode
- ModelDescription
- T1List
- T1Cost
- T2List
- T2Cost
- ISOCurrency
- ValidityDate
- T1orT2
- MaterialID
- SAPNumber
- ModelDescriptionEnglish
- ModelDescriptionLanguage2
- ModelDescriptionLanguage3
- ModelDescriptionLanguage4
- QuoteOrPriceList
- WeightKg
- HeightMm
- LengthMm
- WidthMm
- PowerWatts
- FileName
But the app will work with any Excel format, preserving your column structure.
""")
st.markdown("---")
# Add instructions for local usage
with st.expander("Run This App Locally"):
st.markdown("""
### Instructions for Running Locally
If you're encountering upload issues, you can run this app on your own computer:
1. Install Python if you don't have it already
2. Install the required packages:
```bash
pip install streamlit pandas openpyxl
```
3. Save this app code to a file named `app.py`
4. Run the app with:
```bash
streamlit run app.py
```
5. Access the app in your browser and upload your Excel files locally
### Alternative: Direct Excel to JSON Conversion Script
You can also use this simple Python script to convert Excel to JSON directly:
```python
import pandas as pd
import json
from datetime import datetime
# Replace with your Excel file path
excel_file = "your_file.xlsx"
# Read the Excel file
df = pd.read_excel(excel_file)
# Fill NaN values
df = df.fillna(0.0)
# Convert dataframe to list of dictionaries
result = {"DateStamp": datetime.now().isoformat(), "PriceList": []}
for _, row in df.iterrows():
record = {}
for column in df.columns:
# Convert pandas Timestamp to ISO format string
if isinstance(row[column], pd.Timestamp):
record[column] = row[column].isoformat()
# Convert float values
elif isinstance(row[column], float):
record[column] = float(row[column])
else:
record[column] = row[column]
# Add filename if it doesn't exist
if "FileName" not in record:
record["FileName"] = excel_file
result["PriceList"].append(record)
# Save to JSON file
with open("output.json", "w") as f:
json.dump(result, f, indent=2)
print(f"Conversion complete! JSON saved to output.json")
```
""")
# Add footer
st.markdown("---")
st.markdown("Excel to JSON Converter | Created with Streamlit")