Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Notion to Excel Exporter - Hugging Face Gradio Application | |
| Exports data from Notion databases with multiple export modes. | |
| """ | |
| import os | |
| import gradio as gr | |
| from datetime import datetime | |
| from typing import Optional, Tuple | |
| import traceback | |
| # Import exporters | |
| from notion_exporter import NotionExcelExporter, load_notion_config_from_env | |
| from entry_milestone_exporter import EntryMilestoneExporter | |
| from mawb_milestone_exporter import MAWBMilestoneExporter | |
| from notion_integration import NotionIntegration | |
| # Load authentication credentials from environment | |
| HF_USERNAME = os.environ.get("HF_USERNAME", "admin") | |
| HF_PASSWORD = os.environ.get("HF_PASSWORD", "password") | |
| def export_notion_databases( | |
| db_mawb: bool, | |
| db_entry_records: bool, | |
| db_mawb_tasks: bool, | |
| db_mawb_milestones: bool, | |
| db_dwell_report: bool, | |
| start_date: Optional[str], | |
| end_date: Optional[str], | |
| slow_mode: bool, | |
| page_size: int | |
| ) -> Tuple[Optional[str], str]: | |
| """Export selected Notion databases to Excel.""" | |
| try: | |
| selected_databases = [] | |
| if db_mawb: | |
| selected_databases.append("mawb") | |
| if db_entry_records: | |
| selected_databases.append("entry_record") | |
| if db_mawb_tasks: | |
| selected_databases.append("mawb_task") | |
| if db_mawb_milestones: | |
| selected_databases.append("mawb_milestone") | |
| if db_dwell_report: | |
| selected_databases.append("dwell_report") | |
| if not selected_databases: | |
| return None, "ERROR: Please select at least one database to export." | |
| # Validate dates | |
| date_filter = None | |
| if start_date or end_date: | |
| date_filter = {} | |
| if start_date: | |
| try: | |
| datetime.strptime(start_date, '%Y-%m-%d') | |
| date_filter['start_date'] = start_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid start date format '{start_date}'. Use YYYY-MM-DD format." | |
| if end_date: | |
| try: | |
| datetime.strptime(end_date, '%Y-%m-%d') | |
| date_filter['end_date'] = end_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid end date format '{end_date}'. Use YYYY-MM-DD format." | |
| if start_date and end_date: | |
| start_dt = datetime.strptime(start_date, '%Y-%m-%d') | |
| end_dt = datetime.strptime(end_date, '%Y-%m-%d') | |
| if start_dt > end_dt: | |
| return None, f"ERROR: Start date must be before or equal to end date." | |
| # Export | |
| status_msg = f"Initializing Notion database export...\n" | |
| status_msg += f"Selected databases: {', '.join(selected_databases)}\n" | |
| if date_filter: | |
| status_msg += f"Date filter (created_time): {date_filter}\n" | |
| status_msg += f"Slow mode: {'Enabled' if slow_mode else 'Disabled'}\n" | |
| status_msg += f"Page size: {page_size}\n\n" | |
| exporter = NotionExcelExporter(slow_mode=slow_mode, page_size=page_size) | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| if len(selected_databases) == 1: | |
| output_file = f"notion_{selected_databases[0]}_{timestamp}.xlsx" | |
| else: | |
| output_file = f"notion_export_{timestamp}.xlsx" | |
| result_file = exporter.export_selected_databases( | |
| database_names=selected_databases, | |
| output_file=output_file, | |
| date_filter=date_filter | |
| ) | |
| status_msg += f"\nExport completed successfully!\n" | |
| status_msg += f"File: {result_file}\n" | |
| status_msg += f"Total API calls: {exporter.api_call_count}\n" | |
| status_msg += f"Databases exported: {len(selected_databases)}\n" | |
| return result_file, status_msg | |
| except Exception as e: | |
| error_msg = f"ERROR during export:\n{str(e)}\n\n" | |
| error_msg += f"Traceback:\n{traceback.format_exc()}" | |
| return None, error_msg | |
| def export_entry_milestones( | |
| mawb_input: Optional[str], | |
| start_date: Optional[str], | |
| end_date: Optional[str] | |
| ) -> Tuple[Optional[str], str]: | |
| """Export entry milestone data to Excel.""" | |
| try: | |
| # Validate dates | |
| date_filter = None | |
| if start_date or end_date: | |
| date_filter = {} | |
| if start_date: | |
| try: | |
| datetime.strptime(start_date, '%Y-%m-%d') | |
| date_filter['start_date'] = start_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid start date format '{start_date}'. Use YYYY-MM-DD format." | |
| if end_date: | |
| try: | |
| datetime.strptime(end_date, '%Y-%m-%d') | |
| date_filter['end_date'] = end_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid end date format '{end_date}'. Use YYYY-MM-DD format." | |
| if start_date and end_date: | |
| start_dt = datetime.strptime(start_date, '%Y-%m-%d') | |
| end_dt = datetime.strptime(end_date, '%Y-%m-%d') | |
| if start_dt > end_dt: | |
| return None, f"ERROR: Start date must be before or equal to end date." | |
| # Initialize Notion integration | |
| config = load_notion_config_from_env() | |
| notion = NotionIntegration(config['api_key'], config['database_ids']) | |
| exporter = EntryMilestoneExporter(notion) | |
| # Generate output filename | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| if mawb_input and mawb_input.strip(): | |
| output_file = f"entry_milestone_export_specific_{timestamp}.xlsx" | |
| else: | |
| output_file = f"entry_milestone_export_all_{timestamp}.xlsx" | |
| # Status message | |
| status_msg = f"Initializing entry milestone export...\n" | |
| if mawb_input and mawb_input.strip(): | |
| mawb_list = exporter.parse_mawb_input(mawb_input) | |
| status_msg += f"MAWBs specified: {len(mawb_list)} ({', '.join(mawb_list[:5])}{'...' if len(mawb_list) > 5 else ''})\n" | |
| else: | |
| status_msg += f"Exporting all entry records\n" | |
| if date_filter: | |
| status_msg += f"Date filter (created_time): {date_filter}\n" | |
| status_msg += "\n" | |
| # Export | |
| result_file = exporter.export_to_excel( | |
| mawb_input=mawb_input if mawb_input and mawb_input.strip() else None, | |
| output_file=output_file, | |
| date_filter=date_filter | |
| ) | |
| status_msg += f"\nEntry milestone export completed successfully!\n" | |
| status_msg += f"File: {result_file}\n" | |
| return result_file, status_msg | |
| except Exception as e: | |
| error_msg = f"ERROR during entry milestone export:\n{str(e)}\n\n" | |
| error_msg += f"Traceback:\n{traceback.format_exc()}" | |
| return None, error_msg | |
| def export_mawb_milestones( | |
| mawb_input: Optional[str], | |
| start_date: Optional[str], | |
| end_date: Optional[str] | |
| ) -> Tuple[Optional[str], str]: | |
| """Export SHEIN T01 MAWB milestone data to Excel.""" | |
| try: | |
| # Validate dates | |
| date_filter = None | |
| if start_date or end_date: | |
| date_filter = {} | |
| if start_date: | |
| try: | |
| datetime.strptime(start_date, '%Y-%m-%d') | |
| date_filter['start_date'] = start_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid start date format '{start_date}'. Use YYYY-MM-DD format." | |
| if end_date: | |
| try: | |
| datetime.strptime(end_date, '%Y-%m-%d') | |
| date_filter['end_date'] = end_date | |
| except ValueError: | |
| return None, f"ERROR: Invalid end date format '{end_date}'. Use YYYY-MM-DD format." | |
| if start_date and end_date: | |
| start_dt = datetime.strptime(start_date, '%Y-%m-%d') | |
| end_dt = datetime.strptime(end_date, '%Y-%m-%d') | |
| if start_dt > end_dt: | |
| return None, f"ERROR: Start date must be before or equal to end date." | |
| # Initialize Notion integration | |
| config = load_notion_config_from_env() | |
| notion = NotionIntegration(config['api_key'], config['database_ids']) | |
| exporter = MAWBMilestoneExporter(notion) | |
| # Generate output filename | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| if mawb_input and mawb_input.strip(): | |
| output_file = f"mawb_milestone_export_specific_{timestamp}.xlsx" | |
| else: | |
| output_file = f"mawb_milestone_export_all_{timestamp}.xlsx" | |
| # Status message | |
| status_msg = f"Initializing SHEIN T01 MAWB milestone export...\n" | |
| if mawb_input and mawb_input.strip(): | |
| mawb_list = exporter.parse_mawb_input(mawb_input) | |
| status_msg += f"MAWBs specified: {len(mawb_list)} ({', '.join(mawb_list[:5])}{'...' if len(mawb_list) > 5 else ''})\n" | |
| else: | |
| status_msg += f"Exporting all SHEIN T01 MAWBs\n" | |
| if date_filter: | |
| status_msg += f"Date filter (created_time): {date_filter}\n" | |
| status_msg += "\n" | |
| # Export | |
| result_file = exporter.export_to_excel( | |
| mawb_input=mawb_input if mawb_input and mawb_input.strip() else None, | |
| output_file=output_file, | |
| date_filter=date_filter | |
| ) | |
| status_msg += f"\nMAWB milestone export completed successfully!\n" | |
| status_msg += f"File: {result_file}\n" | |
| return result_file, status_msg | |
| except Exception as e: | |
| error_msg = f"ERROR during MAWB milestone export:\n{str(e)}\n\n" | |
| error_msg += f"Traceback:\n{traceback.format_exc()}" | |
| return None, error_msg | |
| # Create Gradio interface with tabs | |
| with gr.Blocks(title="Notion Excel Exporter") as demo: | |
| gr.Markdown("# Notion Data Exporter") | |
| gr.Markdown("Export data from Notion databases to Excel format with multiple export modes.") | |
| with gr.Tabs(): | |
| # TAB 1: Notion Database Export | |
| with gr.Tab("Notion Databases"): | |
| gr.Markdown("### Export Raw Notion Database Tables") | |
| gr.Markdown("Export one or more Notion databases with all properties automatically captured.") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("**Database Selection**") | |
| db1_mawb = gr.Checkbox(label="MAWB Database", value=False) | |
| db1_entry_records = gr.Checkbox(label="Entry Records Database", value=False) | |
| db1_mawb_tasks = gr.Checkbox(label="MAWB Tasks Database", value=False) | |
| db1_mawb_milestones = gr.Checkbox(label="MAWB Milestones Database", value=False) | |
| db1_dwell_report = gr.Checkbox(label="Dwell Report Database", value=False) | |
| with gr.Column(): | |
| gr.Markdown("**Export Options**") | |
| db1_start_date = gr.Textbox( | |
| label="Start Date (Optional - filters by created_time)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-01-01)" | |
| ) | |
| db1_end_date = gr.Textbox( | |
| label="End Date (Optional - filters by created_time)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-12-31)" | |
| ) | |
| db1_slow_mode = gr.Checkbox( | |
| label="Enable Slow Mode (for large exports)", | |
| value=False | |
| ) | |
| db1_page_size = gr.Slider( | |
| minimum=25, | |
| maximum=100, | |
| value=50, | |
| step=5, | |
| label="API Page Size" | |
| ) | |
| db1_export_btn = gr.Button("Export Notion Databases", variant="primary") | |
| db1_status = gr.Textbox(label="Status", lines=10, interactive=False) | |
| db1_download = gr.File(label="Download File") | |
| db1_export_btn.click( | |
| fn=export_notion_databases, | |
| inputs=[ | |
| db1_mawb, db1_entry_records, db1_mawb_tasks, | |
| db1_mawb_milestones, db1_dwell_report, | |
| db1_start_date, db1_end_date, db1_slow_mode, db1_page_size | |
| ], | |
| outputs=[db1_download, db1_status] | |
| ) | |
| gr.Markdown(""" | |
| **Instructions:** | |
| - Select one or more databases to export | |
| - Optionally filter by created_time using start/end dates | |
| - Multiple databases will be combined into a single Excel file with multiple sheets | |
| """) | |
| # TAB 2: Entry Milestone Export | |
| with gr.Tab("Entry Milestones"): | |
| gr.Markdown("### Export Entry Milestone Data") | |
| gr.Markdown("Export entry milestone tracking data with CBP and CPSC status information.") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("**Filter Options**") | |
| entry_mawb_input = gr.Textbox( | |
| label="MAWB Numbers (Optional)", | |
| placeholder="Enter MAWBs (one per line or comma-separated)\nExample: 369-95208794, 370-12345678", | |
| lines=5 | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("**Date Filter (created_time)**") | |
| entry_start_date = gr.Textbox( | |
| label="Start Date (Optional)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-01-01)" | |
| ) | |
| entry_end_date = gr.Textbox( | |
| label="End Date (Optional)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-12-31)" | |
| ) | |
| entry_export_btn = gr.Button("Export Entry Milestones", variant="primary") | |
| entry_status = gr.Textbox(label="Status", lines=10, interactive=False) | |
| entry_download = gr.File(label="Download File") | |
| entry_export_btn.click( | |
| fn=export_entry_milestones, | |
| inputs=[entry_mawb_input, entry_start_date, entry_end_date], | |
| outputs=[entry_download, entry_status] | |
| ) | |
| gr.Markdown(""" | |
| **Instructions:** | |
| - Leave MAWB field empty to export all entries | |
| - Or specify MAWBs (comma or newline separated) to export specific entries | |
| - Optionally filter by entry record created_time using start/end dates | |
| - Export includes: Entry, MAWB, POD, CBP status, CPSC status, release dates | |
| """) | |
| # TAB 3: MAWB Milestone Export | |
| with gr.Tab("MAWB Milestones (SHEIN T01)"): | |
| gr.Markdown("### Export SHEIN T01 MAWB Milestone Data") | |
| gr.Markdown("Export aggregated milestone data for SHEIN T01 MAWBs (one row per MAWB).") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("**Filter Options**") | |
| mawb_mawb_input = gr.Textbox( | |
| label="MAWB Numbers (Optional)", | |
| placeholder="Enter MAWBs (one per line or comma-separated)\nExample: 369-95208794, 370-12345678", | |
| lines=5 | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("**Date Filter (created_time)**") | |
| mawb_start_date = gr.Textbox( | |
| label="Start Date (Optional)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-01-01)" | |
| ) | |
| mawb_end_date = gr.Textbox( | |
| label="End Date (Optional)", | |
| placeholder="YYYY-MM-DD (e.g., 2024-12-31)" | |
| ) | |
| mawb_export_btn = gr.Button("Export MAWB Milestones", variant="primary") | |
| mawb_status = gr.Textbox(label="Status", lines=10, interactive=False) | |
| mawb_download = gr.File(label="Download File") | |
| mawb_export_btn.click( | |
| fn=export_mawb_milestones, | |
| inputs=[mawb_mawb_input, mawb_start_date, mawb_end_date], | |
| outputs=[mawb_download, mawb_status] | |
| ) | |
| gr.Markdown(""" | |
| **Instructions:** | |
| - Leave MAWB field empty to export all SHEIN T01 MAWBs | |
| - Or specify MAWBs (comma or newline separated) to export specific MAWBs | |
| - Optionally filter by MAWB record created_time using start/end dates | |
| - Export includes aggregated data: Entry submission, CBP exam, CPSC review, customs release, warehouse milestones | |
| - Data is aggregated across all related entries and milestone records per MAWB | |
| """) | |
| gr.Markdown("---") | |
| gr.Markdown(""" | |
| ### General Information | |
| - **Date Filters**: All date filters use the Notion `created_time` field (when the record was created) | |
| - **MAWB Input**: Accepts multiple formats - comma-separated, newline-separated, or tab-separated | |
| - **Export Output**: All exports generate Excel (.xlsx) files with proper formatting | |
| - **No Task Updates**: This tool is for export only - it does not modify any Notion records | |
| """) | |
| # Launch with authentication | |
| if __name__ == "__main__": | |
| demo.launch( | |
| auth=(HF_USERNAME, HF_PASSWORD), | |
| auth_message="Please enter your credentials to access the Notion Exporter", | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| ssr_mode=False | |
| ) | |