import gradio as gr import pandas as pd from io import BytesIO def convert_file(input_file, conversion_type): # 파일이 업로드되었는지 확인 if input_file is None: return None, "파일을 업로드해 주세요." # 파일 내용 읽기 try: # 파일 객체에서 읽기 시도 file_bytes = input_file.read() file_name = input_file.name except AttributeError: # AttributeError가 발생하면 input_file을 파일 경로로 처리 file_name = input_file with open(file_name, "rb") as f: file_bytes = f.read() file_extension = file_name.lower().split('.')[-1] df = None output_file = None converted_format = None try: # 변환: CSV에서 Parquet으로 if conversion_type == "CSV to Parquet": if file_extension != "csv": return None, "CSV에서 Parquet으로 변환하려면 CSV 파일을 업로드해 주세요." # 다양한 인코딩을 시도 (chardet 없이) encodings_to_try = ['utf-8', 'latin1', 'iso-8859-1', 'cp1252'] encoding = None for enc in encodings_to_try: try: df = pd.read_csv(BytesIO(file_bytes), encoding=enc) encoding = enc break except UnicodeDecodeError: continue except Exception as e: return None, f"CSV 읽기 오류: {str(e)}" if df is None: return None, "일반적인 인코딩으로 CSV를 읽지 못했습니다. 파일이 특이한 인코딩을 사용할 수 있습니다." output_file = "output.parquet" df.to_parquet(output_file, index=False) converted_format = "Parquet" # 변환: Parquet에서 CSV로 elif conversion_type == "Parquet to CSV": if file_extension != "parquet": return None, "Parquet에서 CSV로 변환하려면 Parquet 파일을 업로드해 주세요." df = pd.read_parquet(BytesIO(file_bytes)) output_file = "output.csv" df.to_csv(output_file, index=False, encoding='utf-8') converted_format = "CSV" else: return None, "잘못된 변환 유형이 선택되었습니다." # 상위 10개 행의 미리보기 생성 preview = df.head(10).to_string(index=False) info_message = ( f"입력 파일: {file_name}\n" f"변환된 파일 형식: {converted_format}\n" ) if conversion_type == "CSV to Parquet" and encoding: info_message += f"사용된 인코딩: {encoding}\n" info_message += f"\n미리보기 (상위 10개 행):\n{preview}" return output_file, info_message except Exception as e: return None, f"변환 중 오류 발생: {str(e)}" # 모던하고 세련된 스타일을 위한 사용자 정의 CSS custom_css = """ body { background-color: #f4f4f4; font-family: 'Helvetica Neue', Arial, sans-serif; } .gradio-container { max-width: 900px; margin: 40px auto; padding: 20px; background-color: #ffffff; border-radius: 12px; box-shadow: 0 8px 16px rgba(0,0,0,0.1); } h1, h2 { color: #333333; } .gradio-input, .gradio-output { margin-bottom: 20px; } .gradio-button { background-color: #4CAF50 !important; color: white !important; border: none !important; padding: 10px 20px !important; font-size: 16px !important; border-radius: 6px !important; cursor: pointer; } .gradio-button:hover { background-color: #45a049 !important; } """ with gr.Blocks(css=custom_css, title="CSV <-> Parquet 변환기") as demo: gr.Markdown("# CSV <-> Parquet 변환기") gr.Markdown("CSV 또는 Parquet 파일을 업로드하고 변환 유형을 선택하세요. 앱은 파일을 반대 형식으로 변환하고 상위 10개 행의 미리보기를 표시합니다.") with gr.Row(): with gr.Column(scale=1): input_file = gr.File(label="CSV 또는 Parquet 파일 업로드") with gr.Column(scale=1): conversion_type = gr.Radio( choices=["CSV to Parquet", "Parquet to CSV"], label="변환 유형", value="CSV to Parquet" # 기본값 설정 ) convert_button = gr.Button("변환", elem_classes=["gradio-button"]) with gr.Row(): output_file = gr.File(label="변환된 파일") preview = gr.Textbox(label="미리보기 (상위 10개 행)", lines=15) convert_button.click(fn=convert_file, inputs=[input_file, conversion_type], outputs=[output_file, preview]) gr.Markdown(""" ### 참고: - 이 변환기는 일반적인 CSV 인코딩(UTF-8, Latin-1, ISO-8859-1, CP1252)을 시도합니다 - Parquet 파일은 CSV보다 데이터 타입을 더 잘 보존합니다 - 미리보기는 데이터의 처음 10행만 표시합니다 """) if __name__ == "__main__": demo.launch()