re-type commited on
Commit
3b2b697
·
verified ·
1 Parent(s): fec4802

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -155
app.py CHANGED
@@ -1,177 +1,120 @@
1
- # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import torch
4
  import pickle
5
  import subprocess
6
  import pandas as pd
7
- from predictor import GenePredictor
8
- from tensorflow.keras.models import load_model
9
- import ml_simplified_tree # Import the module
10
- import logging
11
  import os
12
  import re
 
 
 
 
13
 
14
- # Configure logging
15
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
 
17
- # --------- Load Models (Optional) ---------
 
 
 
 
 
 
 
18
  boundary_model = None
19
  keras_model = None
20
  kmer_to_index = None
21
- model_dir = "models/" # Adjust this if the models are in a different subdirectory
22
- try:
23
- boundary_path = os.path.join(model_dir, "best_boundary_aware_model.pth")
24
- if os.path.exists(boundary_path):
25
- boundary_model = GenePredictor(boundary_path)
26
- logging.info(f"Boundary model loaded successfully from {boundary_path}")
27
- else:
28
- logging.warning(f"Boundary model not found at {boundary_path}. Skipping Boundary-Aware step.")
29
- except Exception as e:
30
- logging.error(f"Error loading Boundary model from {boundary_path}: {e}. Skipping Boundary-Aware step.")
31
- try:
32
- keras_path = os.path.join(model_dir, "best_model.keras")
33
- kmer_path = os.path.join(model_dir, "kmer_to_index.pkl")
34
- if os.path.exists(keras_path) and os.path.exists(kmer_path):
35
- keras_model = load_model(keras_path)
36
- with open(kmer_path, "rb") as f:
37
- kmer_to_index = pickle.load(f)
38
- logging.info(f"Keras model and kmer_to_index loaded successfully from {keras_path} and {kmer_path}")
39
- else:
40
- logging.warning(f"Keras model or kmer_to_index not found at {keras_path} or {kmer_path}. Skipping Keras step.")
41
- except Exception as e:
42
- logging.error(f"Error loading Keras model or kmer_to_index from {keras_path} or {kmer_path}: {e}. Skipping Keras step.")
43
 
44
- # --------- Utilities ---------
 
 
 
 
 
 
 
 
 
45
  def predict_with_keras(sequence):
46
- global keras_model, kmer_to_index
47
- if keras_model is None or kmer_to_index is None:
48
- return f"Skipped (Models not loaded): {sequence}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  try:
50
- kmers = [sequence[i:i+6] for i in range(len(sequence)-5)]
51
- indices = [kmer_to_index.get(kmer, 0) for kmer in kmers]
52
- input_arr = torch.tensor([indices])
53
- prediction = keras_model.predict(input_arr, verbose=0)[0]
54
- return "".join(str(round(p, 3)) for p in prediction)
55
  except Exception as e:
56
- logging.error(f"Error in Keras prediction: {e}")
57
- return f"Error in Keras prediction: {e}"
58
 
59
- def run_full_pipeline(dna_input):
 
60
  try:
61
- # Validate input
62
- dna_input = dna_input.upper()
63
- if not re.match('^[ACTGN]+$', dna_input):
64
- logging.warning("Invalid DNA sequence. Replacing non-[ACTGN] with 'N'.")
65
- dna_input = ''.join(c if c in 'ACTGN' else 'N' for c in dna_input)
66
-
67
- # Step 1: Boundary-Aware Prediction (Optional)
68
- step1_out = dna_input # Fallback to input if model missing
69
- if boundary_model:
70
- try:
71
- predictions, probs, confidence = boundary_model.predict(dna_input)
72
- gene_regions = boundary_model.extract_gene_regions(predictions, dna_input)
73
- step1_out = gene_regions[0]["sequence"] if gene_regions else dna_input
74
- logging.info(f"Boundary model output: {step1_out[:50]}... (truncated)")
75
- except Exception as e:
76
- logging.error(f"Boundary model prediction failed: {e}")
77
- step1_out = dna_input
78
- else:
79
- logging.info("Boundary model skipped due to missing or failed load")
80
-
81
- # Step 2: Keras Prediction (Optional)
82
- step2_out = step1_out # Fallback to step1_out if model missing
83
- if keras_model and kmer_to_index:
84
- try:
85
- step2_out = predict_with_keras(step1_out)
86
- logging.info(f"Keras model output: {step2_out[:50]}... (truncated)")
87
- except Exception as e:
88
- logging.error(f"Keras prediction failed: {e}")
89
- step2_out = step1_out
90
- else:
91
- logging.info("Keras model skipped due to missing or failed load")
92
 
93
- # Step 3: Run ML Simplified Tree using PhylogeneticTreeAnalyzer with existing CSV
 
 
 
94
  analyzer = ml_simplified_tree.PhylogeneticTreeAnalyzer()
95
- csv_path = "f gene clean dataset.csv"
96
- if not os.path.exists(csv_path):
97
- ml_output = f"Error: Expected CSV file '{csv_path}' not found"
98
- logging.error(ml_output)
 
 
 
99
  else:
100
- try:
101
- if not analyzer.load_data(csv_path):
102
- ml_output = "Error: Failed to load data from existing CSV"
103
- logging.error(f"Load data failed: Check CSV content. Head: {pd.read_csv(csv_path).head()}")
104
- else:
105
- if not analyzer.find_query_sequence(step2_out):
106
- ml_output = "Error: Invalid query sequence"
107
- logging.error(f"Query sequence invalid: {step2_out[:50]}... (truncated)")
108
- else:
109
- matched_ids, actual_percentage = analyzer.find_similar_sequences(analyzer.matching_percentage)
110
- if not matched_ids:
111
- ml_output = "Error: No similar sequences found"
112
- logging.error(f"No matches for sequence: {step2_out[:50]}... (truncated)")
113
- else:
114
- analyzer.create_interactive_tree(matched_ids, actual_percentage)
115
- ml_output = f"Tree generated and saved as phylogenetic_tree_normalized_horizontal.html"
116
- if not os.path.exists("phylogenetic_tree_normalized_horizontal.html"):
117
- ml_output += " (File not found after generation)"
118
- logging.error("HTML file not generated")
119
- else:
120
- logging.info("HTML file generated successfully")
121
- except Exception as e:
122
- ml_output = f"Error in ML tree generation: {e}"
123
- logging.error(f"ML tree generation failed: {e}")
124
-
125
- html_file = "phylogenetic_tree_normalized_horizontal.html" if os.path.exists("phylogenetic_tree_normalized_horizontal.html") else None
126
-
127
- return {
128
- "Boundary Model Output": step1_out if boundary_model else "Skipped (Model not loaded)",
129
- "Keras Model Output": step2_out if keras_model and kmer_to_index else "Skipped (Model not loaded)",
130
- "CSV Save Status": "Using existing 'f gene clean.csv'",
131
- "Maximum Likelihood Tree Output": ml_output,
132
- "Tree HTML File": html_file
133
- }
134
- except Exception as e:
135
- logging.error(f"Pipeline failed: {e}")
136
- return {
137
- "Boundary Model Output": f"Error: {e}",
138
- "Keras Model Output": "N/A",
139
- "CSV Save Status": "N/A",
140
- "Maximum Likelihood Tree Output": "N/A",
141
- "Tree HTML File": None
142
- }
143
-
144
- # --------- Gradio Interface and API ---------
145
- with gr.Blocks() as gr_interface:
146
- gr.Markdown("# Sequential Phylogenetic Inference Pipeline")
147
- gr.Markdown("This pipeline generates a phylogenetic tree using the existing 'f gene clean.csv'. Model files are expected in the 'models/' subdirectory and are optional.")
148
-
149
- dna_input = gr.Textbox(label="Input DNA Sequence", placeholder="Enter DNA sequence (e.g., ATGCGTAACTAGCTAGCTAA)")
150
- submit_button = gr.Button("Generate Tree")
151
-
152
- boundary_output = gr.Textbox(label="Boundary Model Output")
153
- keras_output = gr.Textbox(label="Keras Model Output")
154
- csv_status = gr.Textbox(label="CSV Save Status")
155
- ml_output = gr.Textbox(label="Maximum Likelihood Tree Output")
156
- tree_download = gr.File(label="Download Tree (HTML)", file_types=[".html"])
157
-
158
- submit_button.click(
159
- fn=run_full_pipeline,
160
- inputs=dna_input,
161
- outputs=[
162
- boundary_output,
163
- keras_output,
164
- csv_status,
165
- ml_output,
166
- tree_download
167
- ]
168
- )
169
-
170
- # --------- Launch ---------
171
- if __name__ == "__main__":
172
- try:
173
- gr_interface.launch(server_name="0.0.0.0", server_port=7860)
174
- logging.info("Gradio interface launched successfully")
175
- except Exception as e:
176
- logging.error(f"Error launching Gradio interface: {e}")
177
- raise
 
1
+ # app.py
2
  import gradio as gr
3
  import torch
4
  import pickle
5
  import subprocess
6
  import pandas as pd
 
 
 
 
7
  import os
8
  import re
9
+ import logging
10
+ from predictor import GenePredictor
11
+ from tensorflow.keras.models import load_model
12
+ import ml_simplified_tree
13
 
14
+ # --- Logging ---
15
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
 
17
+ # --- Paths ---
18
+ model_dir = "models"
19
+ boundary_path = os.path.join(model_dir, "best_boundary_aware_model.pth")
20
+ keras_path = os.path.join(model_dir, "best_model.keras")
21
+ kmer_path = os.path.join(model_dir, "kmer_to_index.pkl")
22
+ csv_path = "f gene clean dataset.csv"
23
+
24
+ # --- Load Models ---
25
  boundary_model = None
26
  keras_model = None
27
  kmer_to_index = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ if os.path.exists(boundary_path):
30
+ boundary_model = GenePredictor(boundary_path)
31
+ logging.info("Boundary model loaded.")
32
+ if os.path.exists(keras_path) and os.path.exists(kmer_path):
33
+ keras_model = load_model(keras_path)
34
+ with open(kmer_path, "rb") as f:
35
+ kmer_to_index = pickle.load(f)
36
+ logging.info("Keras model and k-mer index loaded.")
37
+
38
+ # --- Keras Prediction ---
39
  def predict_with_keras(sequence):
40
+ kmers = [sequence[i:i+6] for i in range(len(sequence)-5)]
41
+ indices = [kmer_to_index.get(kmer, 0) for kmer in kmers]
42
+ input_arr = torch.tensor([indices])
43
+ prediction = keras_model.predict(input_arr, verbose=0)[0]
44
+ return ''.join(str(round(p, 3)) for p in prediction)
45
+
46
+ # --- Full Pipeline ---
47
+ def run_pipeline(dna_input):
48
+ dna_input = dna_input.upper()
49
+ if not re.match('^[ACTGN]+$', dna_input):
50
+ dna_input = ''.join(c if c in 'ACTGN' else 'N' for c in dna_input)
51
+
52
+ # Step 1: Boundary Prediction
53
+ if boundary_model:
54
+ predictions, probs, confidence = boundary_model.predict(dna_input)
55
+ regions = boundary_model.extract_gene_regions(predictions, dna_input)
56
+ step1_out = regions[0]["sequence"] if regions else dna_input
57
+ else:
58
+ step1_out = dna_input
59
+
60
+ # Step 2: Keras Prediction
61
+ step2_out = predict_with_keras(step1_out) if keras_model and kmer_to_index else step1_out
62
+
63
+ # Save to FASTA for MAFFT/IQTREE
64
+ fasta_file = "input_sequence.fasta"
65
+ with open(fasta_file, "w") as f:
66
+ f.write(">query\n" + step2_out + "\n")
67
+
68
+ # Run MAFFT
69
+ aligned_file = "aligned.fasta"
70
  try:
71
+ subprocess.run(["mafft", "--auto", fasta_file], stdout=open(aligned_file, "w"), check=True)
 
 
 
 
72
  except Exception as e:
73
+ aligned_file = None
74
+ logging.error(f"MAFFT failed: {e}")
75
 
76
+ # Run IQ-TREE
77
+ phy_file = "input_sequence.phy"
78
  try:
79
+ subprocess.run(["iqtree2", "-s", aligned_file, "-nt", "AUTO"], check=True)
80
+ except Exception as e:
81
+ logging.error(f"IQ-TREE failed: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ # Step 3: ML Simplified Tree
84
+ html_file = "phylogenetic_tree_normalized_horizontal.html"
85
+ ml_output = ""
86
+ if os.path.exists(csv_path):
87
  analyzer = ml_simplified_tree.PhylogeneticTreeAnalyzer()
88
+ if analyzer.load_data(csv_path):
89
+ if analyzer.find_query_sequence(step2_out):
90
+ matched_ids, perc = analyzer.find_similar_sequences(analyzer.matching_percentage)
91
+ analyzer.create_interactive_tree(matched_ids, perc)
92
+ ml_output = "Tree generated."
93
+ else:
94
+ ml_output = "Query sequence not found."
95
  else:
96
+ ml_output = "Failed to load CSV."
97
+ else:
98
+ ml_output = "CSV file missing."
99
+
100
+ return step1_out, step2_out, csv_path, ml_output, html_file, aligned_file, phy_file
101
+
102
+ # --- Gradio UI ---
103
+ with gr.Blocks() as demo:
104
+ gr.Markdown("# Viral Gene Phylogenetic Inference Pipeline")
105
+
106
+ inp = gr.Textbox(label="DNA Input")
107
+ btn = gr.Button("Run Pipeline")
108
+
109
+ out1 = gr.Textbox(label="Boundary Model Output")
110
+ out2 = gr.Textbox(label="Keras Model Output")
111
+ out3 = gr.Textbox(label="CSV File Used")
112
+ out4 = gr.Textbox(label="ML Tree Output")
113
+ html = gr.File(label="ML Tree (HTML)", file_types=['.html'])
114
+ fasta = gr.File(label="Aligned FASTA", file_types=['.fasta'])
115
+ phy = gr.File(label="IQ-TREE .phy File", file_types=['.phy'])
116
+
117
+ btn.click(fn=run_pipeline, inputs=inp, outputs=[out1, out2, out3, out4, html, fasta, phy])
118
+
119
+ if __name__ == '__main__':
120
+ demo.launch(server_name="0.0.0.0", server_port=7860)