re-type commited on
Commit
05119bd
·
verified ·
1 Parent(s): 4cfbe93

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -278
app.py CHANGED
@@ -9,8 +9,7 @@ import logging
9
  import numpy as np
10
  from predictor import GenePredictor
11
  from tensorflow.keras.models import load_model
12
- # Import the new analyzer
13
- from analyzer import PhylogeneticTreeAnalyzer
14
  import tempfile
15
  import shutil
16
  import sys
@@ -84,45 +83,25 @@ try:
84
  except Exception as e:
85
  logging.error(f"Failed to load Keras model from HF Hub: {e}")
86
 
87
- # --- Initialize New Tree Analyzer ---
88
  analyzer = None
89
  try:
90
- analyzer = PhylogeneticTreeAnalyzer()
91
-
92
- # Try multiple potential locations for the CSV file
93
- csv_candidates = [
94
- csv_path,
95
- os.path.join(BASE_DIR, csv_path),
96
- os.path.join(BASE_DIR, "app", csv_path),
97
- os.path.join(os.path.dirname(__file__), csv_path),
98
- "f_cleaned.csv", # Alternative naming
99
- os.path.join(BASE_DIR, "f_cleaned.csv")
100
- ]
101
-
102
- csv_loaded = False
103
- for csv_candidate in csv_candidates:
104
- if os.path.exists(csv_candidate):
105
- if analyzer.load_data(csv_candidate):
106
- logging.info(f"Tree analyzer data loaded from: {csv_candidate}")
107
- csv_loaded = True
108
- csv_path = csv_candidate # Update path for consistency
109
- break
110
- else:
111
- logging.warning(f"Failed to load data from: {csv_candidate}")
112
-
113
- if not csv_loaded:
114
- logging.error("Failed to load CSV data from any candidate location")
115
- analyzer = None
116
  else:
117
- # Try to train AI model (optional)
118
- try:
119
- if analyzer.train_ai_model():
120
- logging.info("AI model training completed successfully")
121
- else:
122
- logging.warning("AI model training failed; proceeding with basic analysis.")
123
- except Exception as e:
124
- logging.warning(f"AI model training failed: {e}")
125
-
126
  except Exception as e:
127
  logging.error(f"Failed to initialize tree analyzer: {e}")
128
  analyzer = None
@@ -473,66 +452,70 @@ def build_maximum_likelihood_tree(f_gene_sequence):
473
  logging.error(f"ML tree construction failed: {e}")
474
  return False, f"ML tree construction failed: {str(e)}", None, None
475
 
476
- # --- NEW Tree Analysis Function (Using the new analyzer API) ---
477
- def analyze_sequence_for_tree(sequence: str, matching_percentage: float) -> tuple:
478
  """
479
- Analyze sequence and create phylogenetic tree using the new analyzer API
480
-
481
- Args:
482
- sequence (str): DNA sequence to analyze
483
- matching_percentage (float): Similarity threshold percentage
484
-
485
- Returns:
486
- tuple: (status_message, html_file_path)
487
  """
488
  try:
489
  if not analyzer:
490
- return "❌ Error: Tree analyzer not initialized. Please check if the CSV data file is available.", None
491
 
492
  if not sequence:
493
- return "❌ Error: Please provide a sequence.", None
494
 
495
  if not (1 <= matching_percentage <= 99):
496
- return "❌ Error: Matching percentage must be between 1 and 99.", None
497
-
498
- # Validate inputs
499
- sequence = sequence.strip()
500
- if len(sequence) < 10:
501
- return "❌ Error: Invalid or missing sequence. Must be ≥10 nucleotides.", None
502
 
503
  # Find query sequence
504
  if not analyzer.find_query_sequence(sequence):
505
- return "❌ Error: Sequence not accepted.", None
 
 
 
506
 
507
  # Find similar sequences
508
  matched_ids, actual_percentage = analyzer.find_similar_sequences(matching_percentage)
509
 
510
  if not matched_ids:
511
- return f"❌ Error: No similar sequences found at {matching_percentage}% similarity threshold.", None
512
 
513
- logging.info(f"Found {len(matched_ids)} similar sequences at {actual_percentage:.2f}% similarity")
514
 
515
  # Build tree structure
516
- analyzer.build_tree_structure_with_ml_safe(matched_ids)
 
 
517
 
518
  # Create interactive tree
519
  fig = analyzer.create_interactive_tree(matched_ids, actual_percentage)
 
 
 
 
 
520
 
521
- # Save to temporary file that Gradio can access
522
- temp_dir = tempfile.gettempdir()
523
- output_path = os.path.join(temp_dir, 'phylogenetic_tree_interactive.html')
524
- fig.write_html(output_path)
525
 
526
- success_msg = f"✅ Analysis complete! Found {len(matched_ids)} similar sequences with {actual_percentage:.2f}% average similarity."
 
 
527
 
528
- return success_msg, output_path
 
 
 
 
 
529
 
530
  except Exception as e:
531
- error_msg = f"❌ Error during analysis: {str(e)}"
532
  logging.error(error_msg)
533
  import traceback
534
  logging.error(f"Full traceback: {traceback.format_exc()}")
535
- return error_msg, None
536
 
537
  # --- Keras Prediction ---
538
  def predict_with_keras(sequence):
@@ -665,7 +648,7 @@ def run_pipeline(dna_input, similarity_score=95.0, build_ml_tree=False):
665
  else:
666
  ml_tree_output = "Phylogenetic placement skipped (not requested)"
667
 
668
- # Step 4: NEW Simplified Tree Analysis (using the new analyzer API)
669
  html_file = None
670
  tree_html_content = "No tree generated"
671
  simplified_ml_output = ""
@@ -674,269 +657,256 @@ def run_pipeline(dna_input, similarity_score=95.0, build_ml_tree=False):
674
  try:
675
  logging.info(f"Starting simplified ML tree analysis with F gene sequence length: {len(processed_sequence)}")
676
 
677
- # Use the new analyze_sequence_for_tree function
678
- tree_result, html_path = analyze_sequence_for_tree(processed_sequence, similarity_score)
679
 
680
- if html_path and os.path.exists(html_path):
681
- # Success - copy the HTML file to a location Gradio can serve
682
- output_dir = "output"
683
- os.makedirs(output_dir, exist_ok=True)
684
-
685
- # Create a safe filename
686
- safe_seq_name = re.sub(r'[^a-zA-Z0-9]', '_', processed_sequence[:20])
687
- html_filename = os.path.join(output_dir, f"tree_{safe_seq_name}_{uuid.uuid4().hex[:8]}.html")
688
 
689
- # Copy the HTML file
690
- shutil.copy2(html_path, html_filename)
691
- html_file = html_filename
 
 
 
 
 
 
 
692
 
693
- # Read HTML content for display
694
- with open(html_filename, 'r', encoding='utf-8') as f:
695
- tree_html_content = f.read()
 
 
696
 
697
- simplified_ml_output = tree_result
698
- logging.info(f"Tree analysis completed successfully. HTML saved to: {html_filename}")
699
  else:
700
- simplified_ml_output = tree_result or "❌ Failed to generate tree visualization"
701
- logging.warning("Tree analysis failed or no HTML output generated")
702
 
703
  except Exception as e:
704
- simplified_ml_output = f"❌ Simplified ML tree analysis failed: {str(e)}"
705
- logging.error(f"Simplified ML tree analysis failed: {e}")
706
- elif not analyzer:
707
- simplified_ml_output = "❌ Tree analyzer not available (CSV data not loaded)"
708
- elif len(processed_sequence) < 10:
709
- simplified_ml_output = "❌ Sequence too short for tree analysis (minimum 10 bp)"
710
  else:
711
- simplified_ml_output = "Tree analysis skipped"
 
 
 
712
 
713
  # Prepare final outputs
714
- final_boundary_output = f"F gene sequence ({len(processed_sequence)} bp):\n{boundary_output}"
715
- final_keras_output = f"F gene validation: {keras_output}"
716
-
 
 
 
 
 
 
 
 
 
 
 
 
717
  logging.info("Pipeline completed successfully")
718
-
719
  return (
720
- final_boundary_output, # Boundary prediction output
721
- final_keras_output, # Keras prediction output
722
- ml_tree_output, # ML tree output
723
- simplified_ml_output, # Simplified tree output
724
- processed_sequence, # The extracted F gene sequence
725
- aligned_file, # Alignment file path
726
- phy_file, # Tree file path
727
- html_file, # HTML tree file path
728
- tree_html_content # HTML content for display
729
  )
730
 
731
  except Exception as e:
732
- error_msg = f"Pipeline error: {str(e)}"
733
  logging.error(error_msg)
734
- return error_msg, "", "", "", "", None, None, None, "Pipeline failed"
 
 
735
 
736
  # --- Gradio Interface ---
737
  def create_gradio_interface():
738
- """Create and configure the Gradio interface"""
739
-
740
- with gr.Blocks(
741
- title="F Gene Analysis Pipeline",
742
- theme=gr.themes.Soft(),
743
- css="""
744
- .gradio-container {
745
- max-width: 1200px !important;
746
- }
747
- .output-html {
748
- height: 600px;
749
- overflow: auto;
750
- }
751
- """
752
- ) as demo:
753
-
754
  gr.Markdown("""
755
  # 🧬 F Gene Analysis Pipeline
756
 
757
- This tool performs comprehensive analysis of F gene sequences including:
758
- - **Gene Boundary Prediction**: Identifies and extracts F gene regions from input sequences
759
- - **F Gene Validation**: Validates sequences using ML models
760
- - **Phylogenetic Analysis**: Builds phylogenetic trees and performs sequence placement
 
761
  """)
762
 
763
- with gr.Tab("Sequence Analysis"):
764
  with gr.Row():
765
- with gr.Column(scale=1):
766
- gr.Markdown("### Input")
767
-
768
- # Input options (simplified to Text Input only)
769
- dna_sequence = gr.Textbox(
770
  label="DNA Sequence",
771
- placeholder="Enter your DNA sequence here (raw sequence)",
772
  lines=8,
773
- visible=True
774
  )
775
 
776
- # Parameters
777
- gr.Markdown("### Parameters")
778
- similarity_threshold = gr.Slider(
779
- minimum=50,
780
- maximum=99,
781
  value=95,
782
  step=1,
783
- label="Similarity Threshold (%)",
784
- info="For phylogenetic tree analysis"
785
  )
786
 
787
- build_ml_tree_checkbox = gr.Checkbox(
788
- label="Build Maximum Likelihood Tree",
789
- value=False,
790
- info="Requires MAFFT and IQ-TREE (slower but more comprehensive)"
791
  )
792
 
793
- # Action buttons
794
- analyze_btn = gr.Button("🚀 Run Analysis", variant="primary", size="lg")
795
- clear_btn = gr.Button("🗑️ Clear", variant="secondary")
796
-
797
  with gr.Column(scale=2):
798
- gr.Markdown("### Results")
 
 
 
 
 
 
 
 
 
 
 
 
 
799
 
800
- # Output tabs
801
- with gr.Tabs():
802
- with gr.Tab("Gene Prediction"):
803
- boundary_output = gr.Textbox(
804
- label="F Gene Boundary Prediction",
805
- lines=8,
806
- interactive=False
807
- )
808
-
809
- keras_output = gr.Textbox(
810
- label="F Gene Validation",
811
- lines=3,
812
- interactive=False
813
- )
814
-
815
- with gr.Tab("Phylogenetic Tree"):
816
- ml_tree_output = gr.Textbox(
817
- label="Maximum Likelihood Tree Status",
818
- lines=8,
819
- interactive=False
820
- )
821
-
822
- tree_analysis_output = gr.Textbox(
823
- label="Tree Analysis Status",
824
- lines=4,
825
- interactive=False
826
- )
827
-
828
- # Tree visualization
829
- tree_html = gr.HTML(
830
- label="Interactive Phylogenetic Tree",
831
- elem_classes=["output-html"]
832
- )
833
-
834
- with gr.Tab("Sequence Output"):
835
- extracted_sequence = gr.Textbox(
836
- label="Extracted F Gene Sequence",
837
- lines=10,
838
- interactive=False,
839
- info="The F gene sequence extracted by the boundary model"
840
- )
841
-
842
- with gr.Tab("Download Files"):
843
- tree_file = gr.File(
844
- label="Tree File",
845
- interactive=False
846
- )
847
-
848
- html_tree_file = gr.File(
849
- label="Interactive Tree (HTML)",
850
- interactive=False
851
- )
852
 
 
 
853
 
854
- # Event handlers
855
- def run_analysis(dna_seq, similarity, build_ml):
856
- """Main analysis function"""
857
- try:
858
- if not dna_seq or not dna_seq.strip():
859
- return ("❌ Please provide a DNA sequence", "", "", "", "", None, None, None, "No input provided")
860
- results = run_pipeline(dna_seq, similarity, build_ml)
861
- return results
862
 
863
- except Exception as e:
864
- error_msg = f"Analysis failed: {str(e)}"
865
- logging.error(error_msg)
866
- return (error_msg, "", "", "", "", None, None, None, "Analysis failed")
867
-
868
- def clear_all():
869
- """Clear all inputs and outputs"""
870
- return (
871
- "", # dna_sequence
872
- 95, # similarity_threshold
873
- False, # build_ml_tree_checkbox
874
- "", # boundary_output
875
- "", # keras_output
876
- "", # ml_tree_output
877
- "", # tree_analysis_output
878
- "", # extracted_sequence
879
- "", # tree_html
880
- None, # tree_file
881
- None, # html_tree_file
 
 
 
 
 
 
882
  )
883
 
884
- # Connect the analyze button
885
- analyze_btn.click(
886
- fn=run_analysis,
887
- inputs=[
888
- dna_sequence,
889
- similarity_threshold,
890
- build_ml_tree_checkbox
891
- ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  outputs=[
893
  boundary_output,
894
  keras_output,
895
  ml_tree_output,
896
- tree_analysis_output,
897
- extracted_sequence,
898
- tree_file,
899
- html_tree_file,
900
- tree_html
 
901
  ]
902
  )
903
 
904
- # Connect the clear button
905
- clear_btn.click(
906
- fn=clear_all,
907
  outputs=[
908
- dna_sequence,
909
- similarity_threshold,
910
- build_ml_tree_checkbox,
911
  boundary_output,
912
  keras_output,
913
  ml_tree_output,
914
- tree_analysis_output,
915
- extracted_sequence,
916
- tree_html,
917
- tree_file,
918
- html_tree_file
 
919
  ]
920
  )
921
-
922
- return demo
923
 
924
- # --- Main Application ---
925
  if __name__ == "__main__":
926
- try:
927
- # Initialize the Gradio interface
928
- demo = create_gradio_interface()
929
-
930
- # Launch the application
931
- demo.queue(max_size=10) # Enable queuing for long-running tasks
932
- demo.launch(
933
- server_name="0.0.0.0", # Allow external connections
934
- server_port=7860, # Default port
935
- share=False, # Set to True to create public link
936
- debug=True, # Enable debug mode
937
- show_error=True # Show detailed error messages
938
- )
939
-
940
- except Exception as e:
941
- logging.error(f"Failed to launch application: {e}")
942
- print(f"❌ Application failed to start: {e}")
 
9
  import numpy as np
10
  from predictor import GenePredictor
11
  from tensorflow.keras.models import load_model
12
+ import ml_simplified_tree
 
13
  import tempfile
14
  import shutil
15
  import sys
 
83
  except Exception as e:
84
  logging.error(f"Failed to load Keras model from HF Hub: {e}")
85
 
86
+ # --- Initialize Tree Analyzer ---
87
  analyzer = None
88
  try:
89
+ analyzer = ml_simplified_tree.PhylogeneticTreeAnalyzer()
90
+ if os.path.exists(csv_path):
91
+ if analyzer.load_data(csv_path):
92
+ logging.info("Tree analyzer initialized successfully")
93
+ # Try to train AI model (optional)
94
+ try:
95
+ if not analyzer.train_ai_model():
96
+ logging.warning("AI model training failed; proceeding with basic analysis.")
97
+ except Exception as e:
98
+ logging.warning(f"AI model training failed: {e}")
99
+ else:
100
+ logging.error("Failed to load CSV data for tree analyzer")
101
+ analyzer = None
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  else:
103
+ logging.error(f"CSV file not found: {csv_path}")
104
+ analyzer = None
 
 
 
 
 
 
 
105
  except Exception as e:
106
  logging.error(f"Failed to initialize tree analyzer: {e}")
107
  analyzer = None
 
452
  logging.error(f"ML tree construction failed: {e}")
453
  return False, f"ML tree construction failed: {str(e)}", None, None
454
 
455
+ # --- Tree Analysis Function (Based on old Gradio API) ---
456
+ def analyze_sequence_for_tree(sequence: str, matching_percentage: float) -> str:
457
  """
458
+ Analyze sequence and create phylogenetic tree using the working Gradio API pattern
 
 
 
 
 
 
 
459
  """
460
  try:
461
  if not analyzer:
462
+ return "Error: Tree analyzer not initialized. Please check if the CSV data file is available."
463
 
464
  if not sequence:
465
+ return "Error: Please provide a sequence."
466
 
467
  if not (1 <= matching_percentage <= 99):
468
+ return "Error: Matching percentage must be between 1 and 99."
 
 
 
 
 
469
 
470
  # Find query sequence
471
  if not analyzer.find_query_sequence(sequence):
472
+ return "Error: Invalid query sequence or sequence not found in dataset."
473
+
474
+ # Set matching percentage
475
+ analyzer.matching_percentage = matching_percentage
476
 
477
  # Find similar sequences
478
  matched_ids, actual_percentage = analyzer.find_similar_sequences(matching_percentage)
479
 
480
  if not matched_ids:
481
+ return f"No similar sequences found at {matching_percentage}% similarity. Try lowering the threshold."
482
 
483
+ logging.info(f"Found {len(matched_ids)} similar sequences at {actual_percentage:.1f}% similarity")
484
 
485
  # Build tree structure
486
+ tree_structure = analyzer.build_tree_structure(matched_ids)
487
+ if not tree_structure:
488
+ return "Error: Failed to build tree structure."
489
 
490
  # Create interactive tree
491
  fig = analyzer.create_interactive_tree(matched_ids, actual_percentage)
492
+ if not fig:
493
+ return "Error: Failed to create tree visualization."
494
+
495
+ # Generate HTML content
496
+ html_content = fig.to_html(full_html=True, include_plotlyjs='cdn')
497
 
498
+ # Save to output folder
499
+ output_dir = "output"
500
+ os.makedirs(output_dir, exist_ok=True)
 
501
 
502
+ # Create a safe filename
503
+ safe_seq_name = re.sub(r'[^a-zA-Z0-9]', '_', sequence[:20])
504
+ html_filename = os.path.join(output_dir, f"tree_{safe_seq_name}_{matching_percentage}.html")
505
 
506
+ with open(html_filename, "w", encoding='utf-8') as f:
507
+ f.write(html_content)
508
+
509
+ logging.info(f"Tree HTML saved to {html_filename}")
510
+
511
+ return html_content
512
 
513
  except Exception as e:
514
+ error_msg = f"Tree analysis error: {str(e)}"
515
  logging.error(error_msg)
516
  import traceback
517
  logging.error(f"Full traceback: {traceback.format_exc()}")
518
+ return error_msg
519
 
520
  # --- Keras Prediction ---
521
  def predict_with_keras(sequence):
 
648
  else:
649
  ml_tree_output = "Phylogenetic placement skipped (not requested)"
650
 
651
+ # Step 4: ML Simplified Tree (using the existing approach)
652
  html_file = None
653
  tree_html_content = "No tree generated"
654
  simplified_ml_output = ""
 
657
  try:
658
  logging.info(f"Starting simplified ML tree analysis with F gene sequence length: {len(processed_sequence)}")
659
 
660
+ # Use the existing tree analysis function with user-specified similarity
661
+ tree_result = analyze_sequence_for_tree(processed_sequence, matching_percentage=similarity_score)
662
 
663
+ if tree_result and not tree_result.startswith("Error:"):
664
+ # Success - find and read the generated HTML file
665
+ simplified_ml_output = "✅ Simplified phylogenetic tree generated successfully!"
 
 
 
 
 
666
 
667
+ # Check if HTML file was created
668
+ output_dir = "output"
669
+ if os.path.exists(output_dir):
670
+ html_files = [f for f in os.listdir(output_dir) if f.endswith('.html')]
671
+ if html_files:
672
+ html_file = os.path.join(output_dir, html_files[-1]) # Get the latest
673
+ simplified_ml_output += f"\n- Tree file: {html_files[-1]}"
674
+ # Read the HTML file content for display
675
+ with open(html_file, "r", encoding='utf-8') as f:
676
+ tree_html_content = f.read()
677
 
678
+ # Count sequences analyzed
679
+
680
+ if analyzer.find_query_sequence(processed_sequence):
681
+ matched_ids, actual_percentage = analyzer.find_similar_sequences(similarity_score)
682
+ simplified_ml_output += f"\n- Found {len(matched_ids)} similar sequences at {actual_percentage:.1f}% similarity"
683
 
 
 
684
  else:
685
+ # Error case
686
+ simplified_ml_output = f"❌ Simplified ML tree failed: {tree_result}"
687
 
688
  except Exception as e:
689
+ simplified_ml_output = f"❌ Simplified ML tree error: {str(e)}"
690
+ logging.error(f"Simplified ML tree failed: {e}")
 
 
 
 
691
  else:
692
+ if not analyzer:
693
+ simplified_ml_output = "❌ Tree analyzer not available (missing CSV data)"
694
+ else:
695
+ simplified_ml_output = "❌ F gene sequence too short for tree analysis (minimum 10 bp)"
696
 
697
  # Prepare final outputs
698
+ final_boundary = boundary_output if boundary_output else "No boundary prediction"
699
+ final_keras = keras_output if keras_output else "No F gene validation"
700
+ final_ml_tree = ml_tree_output if ml_tree_output else "No phylogenetic placement"
701
+ final_simplified_ml = simplified_ml_output if simplified_ml_output else "No simplified tree"
702
+
703
+ # Summary
704
+ summary = f"""
705
+ 🧬 PIPELINE SUMMARY:
706
+ - Input sequence: {len(dna_input)} bp
707
+ - F gene extracted: {len(processed_sequence)} bp
708
+ - F gene validation: {final_keras}
709
+ - Phylogenetic placement: {'Completed' if 'successfully' in final_ml_tree else 'Failed/Skipped'}
710
+ - Simplified tree: {'Generated' if 'successfully' in final_simplified_ml else 'Failed/Skipped'}
711
+ """
712
+
713
  logging.info("Pipeline completed successfully")
 
714
  return (
715
+ final_boundary,
716
+ final_keras,
717
+ final_ml_tree,
718
+ final_simplified_ml,
719
+ summary,
720
+ aligned_file,
721
+ phy_file,
722
+ html_file,
723
+ tree_html_content
724
  )
725
 
726
  except Exception as e:
727
+ error_msg = f"Pipeline failed: {str(e)}"
728
  logging.error(error_msg)
729
+ import traceback
730
+ logging.error(f"Full traceback: {traceback.format_exc()}")
731
+ return error_msg, "", "", "", error_msg, None, None, None, "Pipeline error occurred"
732
 
733
  # --- Gradio Interface ---
734
  def create_gradio_interface():
735
+ with gr.Blocks(title="F Gene Analysis Pipeline", theme=gr.themes.Soft()) as iface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
736
  gr.Markdown("""
737
  # 🧬 F Gene Analysis Pipeline
738
 
739
+ This pipeline performs comprehensive F gene analysis including:
740
+ - **Boundary Detection**: Extract F gene regions from input sequences
741
+ - **F Gene Validation**: Validate extracted sequences using deep learning
742
+ - **Phylogenetic Placement**: Place sequences in reference phylogenetic trees
743
+ - **Simplified Tree Analysis**: Generate interactive phylogenetic trees
744
  """)
745
 
746
+ with gr.Tab("📝 Text Input"):
747
  with gr.Row():
748
+ with gr.Column(scale=2):
749
+ dna_input = gr.Textbox(
 
 
 
750
  label="DNA Sequence",
751
+ placeholder="Enter your DNA sequence here (FASTA format or raw sequence)...",
752
  lines=8,
753
+ max_lines=20
754
  )
755
 
756
+ with gr.Column(scale=1):
757
+ similarity_score = gr.Slider(
758
+ minimum=30,
759
+ maximum=100,
 
760
  value=95,
761
  step=1,
762
+ label="Similarity Score (%)",
763
+ info="Minimum similarity for tree analysis"
764
  )
765
 
766
+ build_ml_tree = gr.Checkbox(
767
+ label="Build ML Tree",
768
+ value=True,
769
+ info="Perform phylogenetic placement (requires MAFFT + IQ-TREE)"
770
  )
771
 
772
+ run_btn = gr.Button("🚀 Run Analysis", variant="primary", size="lg")
773
+
774
+ with gr.Tab("📁 File Input"):
775
+ with gr.Row():
776
  with gr.Column(scale=2):
777
+ fasta_file = gr.File(
778
+ label="Upload FASTA File",
779
+ file_types=[".fasta", ".fa", ".fas", ".txt"]
780
+ )
781
+
782
+ with gr.Column(scale=1):
783
+ similarity_score_file = gr.Slider(
784
+ minimum=70,
785
+ maximum=99,
786
+ value=95,
787
+ step=1,
788
+ label="Similarity Score (%)",
789
+ info="Minimum similarity for tree analysis"
790
+ )
791
 
792
+ build_ml_tree_file = gr.Checkbox(
793
+ label="Build ML Tree",
794
+ value=True,
795
+ info="Perform phylogenetic placement (requires MAFFT + IQ-TREE)"
796
+ )
797
+
798
+ run_file_btn = gr.Button("🚀 Run Analysis", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
 
800
+ # Results Section
801
+ gr.Markdown("## 📊 Results")
802
 
803
+ with gr.Row():
804
+ with gr.Column():
805
+ boundary_output = gr.Textbox(
806
+ label="🎯 F Gene Extraction",
807
+ lines=5,
808
+ info="Extracted F gene sequence and boundary predictions"
809
+ )
 
810
 
811
+ keras_output = gr.Textbox(
812
+ label="🔍 F Gene Validation",
813
+ lines=2,
814
+ info="Deep learning validation of F gene authenticity"
815
+ )
816
+
817
+ with gr.Column():
818
+ ml_tree_output = gr.Textbox(
819
+ label="🌳 Phylogenetic Placement",
820
+ lines=5,
821
+ info="Maximum likelihood phylogenetic placement results"
822
+ )
823
+
824
+ simplified_ml_output = gr.Textbox(
825
+ label="🌲 Simplified Tree Analysis",
826
+ lines=5,
827
+ info="Interactive phylogenetic tree generation"
828
+ )
829
+
830
+ # Summary and Downloads
831
+ with gr.Row():
832
+ summary_output = gr.Textbox(
833
+ label="📋 Analysis Summary",
834
+ lines=8,
835
+ info="Overview of all analysis steps and results"
836
  )
837
 
838
+ # File Downloads
839
+ with gr.Row():
840
+ with gr.Column():
841
+ aligned_file_output = gr.File(
842
+ label="📄 Alignment File",
843
+ visible=True
844
+ )
845
+
846
+ with gr.Column():
847
+ phy_file_output = gr.File(
848
+ label="🌳 Tree File",
849
+ visible=True
850
+ )
851
+
852
+ with gr.Column():
853
+ html_file_output = gr.File(
854
+ label="🎨 Interactive Tree",
855
+ visible=True
856
+ )
857
+
858
+ # Interactive Tree Viewer
859
+ tree_viewer = gr.HTML(
860
+ label="🎨 Interactive Tree Visualization",
861
+ visible=True
862
+ )
863
+
864
+ # Event handlers
865
+ run_btn.click(
866
+ fn=run_pipeline,
867
+ inputs=[dna_input, similarity_score, build_ml_tree],
868
  outputs=[
869
  boundary_output,
870
  keras_output,
871
  ml_tree_output,
872
+ simplified_ml_output,
873
+ summary_output,
874
+ aligned_file_output,
875
+ phy_file_output,
876
+ html_file_output,
877
+ tree_viewer
878
  ]
879
  )
880
 
881
+ run_file_btn.click(
882
+ fn=run_pipeline_from_file,
883
+ inputs=[fasta_file, similarity_score_file, build_ml_tree_file],
884
  outputs=[
 
 
 
885
  boundary_output,
886
  keras_output,
887
  ml_tree_output,
888
+ simplified_ml_output,
889
+ summary_output,
890
+ aligned_file_output,
891
+ phy_file_output,
892
+ html_file_output,
893
+ tree_viewer
894
  ]
895
  )
896
+
897
+ return iface
898
 
899
+ # --- Main Execution ---
900
  if __name__ == "__main__":
901
+ # Initialize the interface
902
+ interface = create_gradio_interface()
903
+
904
+ # Launch with appropriate settings
905
+ interface.launch(
906
+ server_name="0.0.0.0", # Allow external access
907
+ server_port=7860, # Default Gradio port
908
+ share=False, # Set to True for public sharing
909
+ debug=True, # Enable debug mode for development
910
+ show_error=True, # Show detailed error messages
911
+ max_threads=4 # Limit concurrent threads
912
+ )