hackstone/CSV-Parquet-Convertors
0
1import gradio as gr2import pandas as pd3from io import BytesIO4import chardet5 6def detect_encoding(file_bytes):7 """Detect the encoding of a file using chardet"""8 # Only use a sample of the file for detection to improve performance9 result = chardet.detect(file_bytes[:10000])10 return result['encoding']11 12def convert_file(input_file, conversion_type, encoding_option):13 try:14 # Check if a file was uploaded15 if input_file is None:16 return None, "Please upload a file."17 18 # Determine if input_file is a file-like object or a file path string19 try:20 # Try reading from file-like object21 file_bytes = input_file.read()22 file_name = input_file.name23 except AttributeError:24 # If there's an AttributeError, treat input_file as a file path25 file_name = input_file26 with open(file_name, "rb") as f:27 file_bytes = f.read()28 29 file_extension = file_name.lower().split('.')[-1]30 df = None31 output_file = None32 converted_format = None33 34 # Handle encoding for CSV files35 if encoding_option == "Auto-detect":36 encoding = detect_encoding(file_bytes)37 else:38 encoding = encoding_option39 40 # Conversion: CSV to Parquet41 if conversion_type == "CSV to Parquet":42 if file_extension != "csv":43 return None, "For CSV to Parquet conversion, please upload a CSV file."44 45 # Try with the selected/detected encoding46 try:47 df = pd.read_csv(BytesIO(file_bytes), encoding=encoding)48 except UnicodeDecodeError:49 # If auto-detection fails, try a few common encodings50 common_encodings = ['latin1', 'iso-8859-1', 'cp1252']51 for enc in common_encodings:52 try:53 df = pd.read_csv(BytesIO(file_bytes), encoding=enc)54 encoding = enc # Update the successful encoding55 break56 except UnicodeDecodeError:57 continue58 if df is None:59 return None, f"Failed to decode the CSV file. Auto-detected encoding was '{encoding}'. Please try selecting a specific encoding."60 61 output_file = "output.parquet"62 df.to_parquet(output_file, index=False)63 converted_format = "Parquet"64 65 # Conversion: Parquet to CSV66 elif conversion_type == "Parquet to CSV":67 if file_extension != "parquet":68 return None, "For Parquet to CSV conversion, please upload a Parquet file."69 70 df = pd.read_parquet(BytesIO(file_bytes))71 output_file = "output.csv"72 df.to_csv(output_file, index=False, encoding=encoding)73 converted_format = "CSV"74 else:75 return None, "Invalid conversion type selected."76 77 # Generate a preview of the top 10 rows78 preview = df.head(10).to_string(index=False)79 info_message = (80 f"Input file: {file_name}\n"81 f"Converted file format: {converted_format}\n"82 f"Encoding used: {encoding}\n"83 f"Total rows: {len(df)}\n"84 f"Total columns: {len(df.columns)}\n\n"85 f"Preview (Top 10 Rows):\n{preview}"86 )87 return output_file, info_message88 89 except Exception as e:90 return None, f"Error during conversion: {str(e)}"91 92# Enhanced custom CSS for a more visually appealing interface93custom_css = """94body {95 background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);96 font-family: 'Poppins', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;97}98 99.gradio-container {100 max-width: 950px;101 margin: 40px auto;102 padding: 30px;103 background-color: #ffffff;104 border-radius: 16px;105 box-shadow: 0 10px 25px rgba(0,0,0,0.1);106}107 108h1 {109 color: #3a4149;110 font-size: 2.5rem;111 text-align: center;112 margin-bottom: 5px;113 font-weight: 600;114}115 116h2 {117 color: #5a6570;118 font-size: 1.2rem;119 text-align: center;120 margin-bottom: 25px;121 font-weight: 400;122}123 124.header-icon {125 font-size: 3rem;126 text-align: center;127 margin-bottom: 10px;128 color: #4285f4;129}130 131.instruction-box {132 background-color: #f8f9fa;133 border-left: 4px solid #4285f4;134 padding: 15px;135 margin-bottom: 25px;136 border-radius: 6px;137}138 139.instruction-step {140 margin: 8px 0;141 padding-left: 10px;142}143 144.file-box {145 border: 2px dashed #ddd;146 border-radius: 12px;147 padding: 20px;148 transition: all 0.3s ease;149}150 151.file-box:hover {152 border-color: #4285f4;153 box-shadow: 0 5px 15px rgba(66, 133, 244, 0.15);154}155 156.conversion-radio label {157 padding: 10px 15px;158 margin: 5px;159 border-radius: 8px;160 border: 1px solid #eaeaea;161 transition: all 0.2s ease;162}163 164.conversion-radio input:checked + label {165 background-color: #e8f0fe;166 border-color: #4285f4;167 color: #4285f4;168}169 170.convert-button {171 background: linear-gradient(to right, #4285f4, #34a853) !important;172 color: white !important;173 border: none !important;174 padding: 12px 25px !important;175 font-size: 16px !important;176 font-weight: 500 !important;177 border-radius: 30px !important;178 cursor: pointer;179 margin: 20px auto !important;180 display: block !important;181 box-shadow: 0 4px 12px rgba(66, 133, 244, 0.25) !important;182}183 184.convert-button:hover {185 box-shadow: 0 6px 16px rgba(66, 133, 244, 0.4) !important;186 transform: translateY(-2px);187}188 189.footer {190 text-align: center;191 margin-top: 30px;192 color: #70757a;193 font-size: 0.9rem;194}195 196.preview-box {197 background-color: #f8f9fa;198 border-radius: 8px;199 padding: 15px;200 font-family: monospace;201 white-space: pre-wrap;202 max-height: 400px;203 overflow-y: auto;204}205 206.info-tag {207 display: inline-block;208 background-color: #e8f0fe;209 color: #4285f4;210 padding: 4px 10px;211 border-radius: 20px;212 font-size: 0.85rem;213 margin-right: 8px;214 margin-bottom: 8px;215}216 217.divider {218 height: 1px;219 background: linear-gradient(to right, transparent, #ddd, transparent);220 margin: 25px 0;221}222 223.error-message {224 color: #d93025;225 background-color: #fce8e6;226 padding: 10px;227 border-radius: 8px;228 margin-top: 10px;229 font-size: 0.9rem;230}231 232.success-message {233 color: #188038;234 background-color: #e6f4ea;235 padding: 10px;236 border-radius: 8px;237 margin-top: 10px;238 font-size: 0.9rem;239}240"""241 242with gr.Blocks(css=custom_css, title="DataFormat Converter") as demo:243 gr.HTML('<div class="header-icon">๐</div>')244 gr.Markdown("# DataFormat Converter")245 gr.Markdown("## Seamlessly convert between CSV and Parquet formats with just a few clicks")246 247 gr.HTML('<div class="divider"></div>')248 249 with gr.Row():250 with gr.Column():251 gr.HTML("""252 <div class="instruction-box">253 <h3>How It Works</h3>254 <div class="instruction-step">1. Upload your CSV or Parquet file</div>255 <div class="instruction-step">2. Select the conversion direction</div>256 <div class="instruction-step">3. Choose encoding (or leave as auto-detect)</div>257 <div class="instruction-step">4. Click "Convert" and download your transformed file</div>258 </div>259 260 <div class="info-section">261 <div class="info-tag">Fast Conversion</div>262 <div class="info-tag">Data Preview</div>263 <div class="info-tag">Multi-Encoding Support</div>264 <div class="info-tag">Maintains Structure</div>265 </div>266 """)267 268 gr.HTML("""269 <div style="margin-top: 25px;">270 <h3>Why Convert?</h3>271 <p>Parquet files offer significant advantages for data storage and analysis:</p>272 <ul>273 <li>Smaller file size (up to 87% reduction)</li>274 <li>Faster query performance</li>275 <li>Column-oriented storage</li>276 <li>Better compression</li>277 </ul>278 <p>CSV files are useful for:</p>279 <ul>280 <li>Universal compatibility</li>281 <li>Human readability</li>282 <li>Simple integration with many tools</li>283 </ul>284 </div>285 """)286 287 with gr.Column():288 # Replace gr.Box with a div using gr.HTML for the file-box styling289 gr.HTML('<div class="file-box">')290 input_file = gr.File(label="Upload Your File")291 conversion_type = gr.Radio(292 choices=["CSV to Parquet", "Parquet to CSV"], 293 label="Select Conversion Type",294 value="CSV to Parquet",295 elem_classes=["conversion-radio"]296 )297 encoding_option = gr.Dropdown(298 choices=["Auto-detect", "utf-8", "latin1", "iso-8859-1", "cp1252", "utf-16"],299 value="Auto-detect",300 label="Select CSV Encoding"301 )302 convert_button = gr.Button("Convert Now", elem_classes=["convert-button"])303 gr.HTML('</div>') # Close the file-box div304 305 with gr.Accordion("Conversion Results", open=False):306 output_file = gr.File(label="Download Converted File")307 308 with gr.Accordion("Data Preview", open=True):309 preview = gr.Textbox(310 label="File Information and Preview", 311 lines=15,312 elem_classes=["preview-box"]313 )314 315 gr.HTML('<div class="divider"></div>')316 317 gr.HTML("""318 <div class="footer">319 <p>DataFormat Converter ยฉ 2025 | Built with Gradio | An efficient tool for data professionals</p>320 </div>321 """)322 323 convert_button.click(324 fn=convert_file, 325 inputs=[input_file, conversion_type, encoding_option], 326 outputs=[output_file, preview]327 )328 329 # Add dependency handling to show/hide encoding options based on conversion type330 def update_encoding_visibility(conversion_type):331 if conversion_type == "CSV to Parquet":332 return gr.update(visible=True)333 else:334 return gr.update(visible=False)335 336 conversion_type.change(337 fn=update_encoding_visibility,338 inputs=conversion_type,339 outputs=encoding_option340 )341 342if __name__ == "__main__":343 demo.launch()