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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +279 -248
app.py CHANGED
@@ -9,7 +9,8 @@ import logging
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,25 +84,45 @@ try:
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,70 +473,66 @@ def build_maximum_likelihood_tree(f_gene_sequence):
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,7 +665,7 @@ def run_pipeline(dna_input, similarity_score=95.0, build_ml_tree=False):
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,256 +674,270 @@ def run_pipeline(dna_input, similarity_score=95.0, build_ml_tree=False):
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
- )
 
 
 
 
 
 
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
  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
  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
  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
  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
 
855
+ # Event handlers
856
+ def run_analysis(dna_seq, similarity, build_ml):
857
+ """Main analysis function"""
858
+ try:
859
+ if not dna_seq or not dna_seq.strip():
860
+ return ("❌ Please provide a DNA sequence", "", "", "", "", None, None, None, "No input provided")
861
+ results = run_pipeline(dna_seq, similarity, build_ml)
862
+ return results
 
 
 
 
 
863
 
864
+ except Exception as e:
865
+ error_msg = f"Analysis failed: {str(e)}"
866
+ logging.error(error_msg)
867
+ return (error_msg, "", "", "", "", None, None, None, "Analysis failed")
868
+
869
+ def clear_all():
870
+ """Clear all inputs and outputs"""
871
+ return (
872
+ "", # dna_sequence
873
+ 95, # similarity_threshold
874
+ False, # build_ml_tree_checkbox
875
+ "", # boundary_output
876
+ "", # keras_output
877
+ "", # ml_tree_output
878
+ "", # tree_analysis_output
879
+ "", # extracted_sequence
880
+ "", # tree_html
881
+ None, # tree_file
882
+ None, # html_tree_file
883
+ )
884
 
885
+ # Connect the analyze button
886
+ analyze_btn.click(
887
+ fn=run_analysis,
888
+ inputs=[
889
+ dna_sequence,
890
+ similarity_threshold,
891
+ build_ml_tree_checkbox
892
+ ],
893
  outputs=[
894
  boundary_output,
895
  keras_output,
896
  ml_tree_output,
897
+ tree_analysis_output,
898
+ extracted_sequence,
899
+ tree_file,
900
+ html_tree_file,
901
+ tree_html
 
902
  ]
903
  )
904
 
905
+ # Connect the clear button
906
+ clear_btn.click(
907
+ fn=clear_all,
908
  outputs=[
909
+ dna_sequence,
910
+ similarity_threshold,
911
+ build_ml_tree_checkbox,
912
  boundary_output,
913
  keras_output,
914
  ml_tree_output,
915
+ tree_analysis_output,
916
+ extracted_sequence,
917
+ tree_html,
918
+ tree_file,
919
+ html_tree_file
 
920
  ]
921
  )
922
+
923
+ return demo
924
 
925
+ # --- Main Application ---
926
  if __name__ == "__main__":
927
+ try:
928
+ # Initialize the Gradio interface
929
+ demo = create_gradio_interface()
930
+
931
+ # Launch the application
932
+ demo.queue(max_size=10) # Enable queuing for long-running tasks
933
+ demo.launch(
934
+ server_name="0.0.0.0", # Allow external connections
935
+ server_port=7860, # Default port
936
+ share=False, # Set to True to create public link
937
+ debug=True, # Enable debug mode
938
+ show_error=True # Show detailed error messages
939
+ )
940
+
941
+ except Exception as e:
942
+ logging.error(f"Failed to launch application: {e}")
943
+ print(f"❌ Application failed to start: {e}")