Spaces:
No application file
No application file
Update app.py
Browse files
app.py
CHANGED
|
@@ -31,13 +31,23 @@ keras_model = None
|
|
| 31 |
kmer_to_index = None
|
| 32 |
|
| 33 |
if os.path.exists(boundary_path):
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
if os.path.exists(keras_path) and os.path.exists(kmer_path):
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
# --- Keras Prediction ---
|
| 43 |
def predict_with_keras(sequence):
|
|
@@ -65,19 +75,35 @@ def run_pipeline(dna_input):
|
|
| 65 |
dna_input = dna_input.upper()
|
| 66 |
if not re.match('^[ACTGN]+$', dna_input):
|
| 67 |
dna_input = ''.join(c if c in 'ACTGN' else 'N' for c in dna_input)
|
|
|
|
| 68 |
|
| 69 |
# Step 1: Boundary Prediction
|
| 70 |
if boundary_model:
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
else:
|
| 75 |
step1_out = dna_input
|
|
|
|
| 76 |
|
| 77 |
# Step 2: Keras Prediction
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
-
# Save to FASTA for MAFFT/IQTREE
|
| 81 |
fasta_file = "input_sequence.fasta"
|
| 82 |
with open(fasta_file, "w") as f:
|
| 83 |
f.write(">query\n" + step2_out + "\n")
|
|
@@ -91,37 +117,46 @@ def run_pipeline(dna_input):
|
|
| 91 |
aligned_file = None
|
| 92 |
logging.error(f"MAFFT failed: {e}")
|
| 93 |
|
| 94 |
-
# Run IQ-TREE
|
| 95 |
phy_file = "input_sequence.phy"
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
-
# Step 3: ML Simplified Tree
|
| 102 |
html_file = "phylogenetic_tree_normalized_horizontal.html"
|
| 103 |
ml_output = ""
|
|
|
|
| 104 |
if os.path.exists(csv_path):
|
| 105 |
analyzer = ml_simplified_tree.PhylogeneticTreeAnalyzer()
|
| 106 |
if analyzer.load_data(csv_path):
|
| 107 |
if analyzer.find_query_sequence(step2_out):
|
| 108 |
matched_ids, perc = analyzer.find_similar_sequences(analyzer.matching_percentage)
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
else:
|
| 117 |
-
ml_output = "Query sequence not found."
|
| 118 |
-
|
| 119 |
else:
|
| 120 |
ml_output = "Failed to load CSV."
|
| 121 |
-
|
| 122 |
else:
|
| 123 |
ml_output = "CSV file missing."
|
| 124 |
-
|
| 125 |
|
| 126 |
return step1_out, step2_out, csv_path, ml_output, html_file, aligned_file, phy_file, tree_html_content
|
| 127 |
|
|
|
|
| 31 |
kmer_to_index = None
|
| 32 |
|
| 33 |
if os.path.exists(boundary_path):
|
| 34 |
+
try:
|
| 35 |
+
boundary_model = GenePredictor(boundary_path)
|
| 36 |
+
logging.info(f"Boundary model loaded successfully from {boundary_path}")
|
| 37 |
+
except Exception as e:
|
| 38 |
+
logging.error(f"Failed to load Boundary model from {boundary_path}: {e}")
|
| 39 |
+
else:
|
| 40 |
+
logging.error(f"Boundary model file not found at {boundary_path}")
|
| 41 |
if os.path.exists(keras_path) and os.path.exists(kmer_path):
|
| 42 |
+
try:
|
| 43 |
+
keras_model = load_model(keras_path)
|
| 44 |
+
with open(kmer_path, "rb") as f:
|
| 45 |
+
kmer_to_index = pickle.load(f)
|
| 46 |
+
logging.info(f"Keras model and k-mer index loaded successfully from {keras_path} and {kmer_path}")
|
| 47 |
+
except Exception as e:
|
| 48 |
+
logging.error(f"Failed to load Keras model or kmer_to_index from {keras_path} or {kmer_path}: {e}")
|
| 49 |
+
else:
|
| 50 |
+
logging.error(f"Keras model or kmer_to_index file not found at {keras_path} or {kmer_path}")
|
| 51 |
|
| 52 |
# --- Keras Prediction ---
|
| 53 |
def predict_with_keras(sequence):
|
|
|
|
| 75 |
dna_input = dna_input.upper()
|
| 76 |
if not re.match('^[ACTGN]+$', dna_input):
|
| 77 |
dna_input = ''.join(c if c in 'ACTGN' else 'N' for c in dna_input)
|
| 78 |
+
logging.warning("Invalid DNA sequence characters replaced with 'N'.")
|
| 79 |
|
| 80 |
# Step 1: Boundary Prediction
|
| 81 |
if boundary_model:
|
| 82 |
+
try:
|
| 83 |
+
predictions, probs, confidence = boundary_model.predict(dna_input)
|
| 84 |
+
regions = boundary_model.extract_gene_regions(predictions, dna_input)
|
| 85 |
+
step1_out = regions[0]["sequence"] if regions else dna_input
|
| 86 |
+
logging.info(f"Boundary model output: {step1_out[:50]}... (truncated)")
|
| 87 |
+
except Exception as e:
|
| 88 |
+
logging.error(f"Boundary model prediction failed: {e}")
|
| 89 |
+
step1_out = dna_input
|
| 90 |
else:
|
| 91 |
step1_out = dna_input
|
| 92 |
+
logging.info("Boundary model skipped due to loading failure or missing file")
|
| 93 |
|
| 94 |
# Step 2: Keras Prediction
|
| 95 |
+
if keras_model and kmer_to_index:
|
| 96 |
+
try:
|
| 97 |
+
step2_out = predict_with_keras(step1_out)
|
| 98 |
+
logging.info(f"Keras model output: {step2_out[:50]}... (truncated)")
|
| 99 |
+
except Exception as e:
|
| 100 |
+
logging.error(f"Keras prediction failed: {e}")
|
| 101 |
+
step2_out = step1_out
|
| 102 |
+
else:
|
| 103 |
+
step2_out = step1_out
|
| 104 |
+
logging.info("Keras model skipped due to loading failure or missing file")
|
| 105 |
|
| 106 |
+
# Save to FASTA for MAFFT/IQTREE (optional, can be skipped if ML tree is independent)
|
| 107 |
fasta_file = "input_sequence.fasta"
|
| 108 |
with open(fasta_file, "w") as f:
|
| 109 |
f.write(">query\n" + step2_out + "\n")
|
|
|
|
| 117 |
aligned_file = None
|
| 118 |
logging.error(f"MAFFT failed: {e}")
|
| 119 |
|
| 120 |
+
# Run IQ-TREE (only if alignment exists)
|
| 121 |
phy_file = "input_sequence.phy"
|
| 122 |
+
if aligned_file is not None:
|
| 123 |
+
try:
|
| 124 |
+
subprocess.run(["iqtree2", "-s", aligned_file, "-nt", "AUTO"], check=True)
|
| 125 |
+
except Exception as e:
|
| 126 |
+
logging.error(f"IQ-TREE failed: {e}")
|
| 127 |
+
else:
|
| 128 |
+
logging.warning("Skipping IQ-TREE due to missing alignment file")
|
| 129 |
|
| 130 |
+
# Step 3: ML Simplified Tree (independent of MAFFT/IQ-TREE)
|
| 131 |
html_file = "phylogenetic_tree_normalized_horizontal.html"
|
| 132 |
ml_output = ""
|
| 133 |
+
tree_html_content = "No tree generated."
|
| 134 |
if os.path.exists(csv_path):
|
| 135 |
analyzer = ml_simplified_tree.PhylogeneticTreeAnalyzer()
|
| 136 |
if analyzer.load_data(csv_path):
|
| 137 |
if analyzer.find_query_sequence(step2_out):
|
| 138 |
matched_ids, perc = analyzer.find_similar_sequences(analyzer.matching_percentage)
|
| 139 |
+
try:
|
| 140 |
+
analyzer.create_interactive_tree(matched_ids, perc)
|
| 141 |
+
ml_output = "Tree generated."
|
| 142 |
+
if os.path.exists(html_file):
|
| 143 |
+
with open(html_file, "r") as f:
|
| 144 |
+
tree_html_content = f.read()
|
| 145 |
+
else:
|
| 146 |
+
ml_output += " (HTML file not generated)"
|
| 147 |
+
logging.error("HTML file not created after tree generation")
|
| 148 |
+
except Exception as e:
|
| 149 |
+
ml_output = f"Error creating tree: {e}"
|
| 150 |
+
logging.error(f"Tree creation failed: {e}")
|
| 151 |
else:
|
| 152 |
+
ml_output = "Query sequence not found in CSV."
|
| 153 |
+
logging.warning(f"Query sequence {step2_out[:50]}... not found")
|
| 154 |
else:
|
| 155 |
ml_output = "Failed to load CSV."
|
| 156 |
+
logging.error("CSV loading failed")
|
| 157 |
else:
|
| 158 |
ml_output = "CSV file missing."
|
| 159 |
+
logging.error(f"CSV file not found at {csv_path}")
|
| 160 |
|
| 161 |
return step1_out, step2_out, csv_path, ml_output, html_file, aligned_file, phy_file, tree_html_content
|
| 162 |
|