AkshitShubham commited on
Commit
0359c99
·
verified ·
1 Parent(s): ec414a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +138 -15
app.py CHANGED
@@ -1,17 +1,24 @@
1
  from flask import Flask, request, jsonify
2
  from STOUT import translate_forward, translate_reverse
3
  import logging
 
 
4
 
5
  app = Flask(__name__)
6
  logging.basicConfig(level=logging.INFO)
7
 
 
 
 
8
  @app.route('/')
9
  def home():
10
  return jsonify({
11
  "message": "STOUT V2 API - SMILES to IUPAC Translator",
12
  "endpoints": {
13
- "/smiles_to_iupac": "GET - Convert SMILES to IUPAC name (param: smiles)",
14
- "/iupac_to_smiles": "GET - Convert IUPAC name to SMILES (param: iupac)",
 
 
15
  "/health": "GET - Health check"
16
  }
17
  })
@@ -20,34 +27,150 @@ def home():
20
  def health():
21
  return jsonify({"status": "healthy"})
22
 
23
- @app.route('/smiles_to_iupac', methods=['GET'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def smiles_to_iupac():
25
  try:
26
- smiles = request.args.get('smiles')
 
 
 
 
 
27
  if not smiles:
28
  return jsonify({"error": "Missing 'smiles' parameter"}), 400
29
 
30
- iupac_name = translate_forward(smiles)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  return jsonify({
32
- "smiles": smiles,
33
- "iupac": iupac_name
 
 
 
34
  })
 
35
  except Exception as e:
36
- app.logger.error(f"Error translating SMILES: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  return jsonify({"error": str(e)}), 500
38
 
39
- @app.route('/iupac_to_smiles', methods=['GET'])
40
  def iupac_to_smiles():
41
  try:
42
- iupac = request.args.get('iupac')
 
 
 
 
 
43
  if not iupac:
44
  return jsonify({"error": "Missing 'iupac' parameter"}), 400
45
 
46
- smiles = translate_reverse(iupac)
47
- return jsonify({
48
- "iupac": iupac,
49
- "smiles": smiles
50
- })
 
51
  except Exception as e:
52
  app.logger.error(f"Error translating IUPAC: {str(e)}")
53
  return jsonify({"error": str(e)}), 500
 
1
  from flask import Flask, request, jsonify
2
  from STOUT import translate_forward, translate_reverse
3
  import logging
4
+ from concurrent.futures import ThreadPoolExecutor, as_completed
5
+ import time
6
 
7
  app = Flask(__name__)
8
  logging.basicConfig(level=logging.INFO)
9
 
10
+ # Thread pool for parallel processing
11
+ executor = ThreadPoolExecutor(max_workers=4)
12
+
13
  @app.route('/')
14
  def home():
15
  return jsonify({
16
  "message": "STOUT V2 API - SMILES to IUPAC Translator",
17
  "endpoints": {
18
+ "/smiles_to_iupac": "GET/POST - Convert SMILES to IUPAC name",
19
+ "/iupac_to_smiles": "GET/POST - Convert IUPAC name to SMILES",
20
+ "/batch/smiles_to_iupac": "POST - Convert multiple SMILES to IUPAC names",
21
+ "/batch/iupac_to_smiles": "POST - Convert multiple IUPAC names to SMILES",
22
  "/health": "GET - Health check"
23
  }
24
  })
 
27
  def health():
28
  return jsonify({"status": "healthy"})
29
 
30
+ def process_single_smiles(smiles):
31
+ """Process a single SMILES string"""
32
+ try:
33
+ iupac_name = translate_forward(smiles)
34
+ return {"smiles": smiles, "iupac": iupac_name, "success": True}
35
+ except Exception as e:
36
+ return {"smiles": smiles, "error": str(e), "success": False}
37
+
38
+ def process_single_iupac(iupac):
39
+ """Process a single IUPAC name"""
40
+ try:
41
+ smiles = translate_reverse(iupac)
42
+ return {"iupac": iupac, "smiles": smiles, "success": True}
43
+ except Exception as e:
44
+ return {"iupac": iupac, "error": str(e), "success": False}
45
+
46
+ @app.route('/smiles_to_iupac', methods=['GET', 'POST'])
47
  def smiles_to_iupac():
48
  try:
49
+ if request.method == 'GET':
50
+ smiles = request.args.get('smiles')
51
+ else: # POST
52
+ data = request.get_json()
53
+ smiles = data.get('smiles') if data else None
54
+
55
  if not smiles:
56
  return jsonify({"error": "Missing 'smiles' parameter"}), 400
57
 
58
+ result = process_single_smiles(smiles)
59
+ if result['success']:
60
+ return jsonify(result)
61
+ else:
62
+ return jsonify(result), 500
63
+
64
+ except Exception as e:
65
+ app.logger.error(f"Error translating SMILES: {str(e)}")
66
+ return jsonify({"error": str(e)}), 500
67
+
68
+ @app.route('/batch/smiles_to_iupac', methods=['POST'])
69
+ def batch_smiles_to_iupac():
70
+ """Process multiple SMILES strings in parallel"""
71
+ try:
72
+ start_time = time.time()
73
+ data = request.get_json()
74
+
75
+ if not data or 'smiles_list' not in data:
76
+ return jsonify({"error": "Missing 'smiles_list' in request body"}), 400
77
+
78
+ smiles_list = data['smiles_list']
79
+ if not isinstance(smiles_list, list):
80
+ return jsonify({"error": "'smiles_list' must be an array"}), 400
81
+
82
+ # Limit batch size to prevent abuse
83
+ if len(smiles_list) > 100:
84
+ return jsonify({"error": "Maximum batch size is 100"}), 400
85
+
86
+ # Process in parallel using thread pool
87
+ futures = [executor.submit(process_single_smiles, smiles) for smiles in smiles_list]
88
+ results = []
89
+
90
+ for future in as_completed(futures):
91
+ results.append(future.result())
92
+
93
+ # Sort results to maintain input order
94
+ results_dict = {r['smiles']: r for r in results}
95
+ ordered_results = [results_dict.get(smiles, {"smiles": smiles, "error": "Not processed", "success": False})
96
+ for smiles in smiles_list]
97
+
98
+ processing_time = time.time() - start_time
99
+
100
  return jsonify({
101
+ "results": ordered_results,
102
+ "total": len(smiles_list),
103
+ "successful": sum(1 for r in ordered_results if r.get('success', False)),
104
+ "failed": sum(1 for r in ordered_results if not r.get('success', False)),
105
+ "processing_time_seconds": round(processing_time, 3)
106
  })
107
+
108
  except Exception as e:
109
+ app.logger.error(f"Error in batch processing: {str(e)}")
110
+ return jsonify({"error": str(e)}), 500
111
+
112
+ @app.route('/batch/iupac_to_smiles', methods=['POST'])
113
+ def batch_iupac_to_smiles():
114
+ """Process multiple IUPAC names in parallel"""
115
+ try:
116
+ start_time = time.time()
117
+ data = request.get_json()
118
+
119
+ if not data or 'iupac_list' not in data:
120
+ return jsonify({"error": "Missing 'iupac_list' in request body"}), 400
121
+
122
+ iupac_list = data['iupac_list']
123
+ if not isinstance(iupac_list, list):
124
+ return jsonify({"error": "'iupac_list' must be an array"}), 400
125
+
126
+ # Limit batch size to prevent abuse
127
+ if len(iupac_list) > 100:
128
+ return jsonify({"error": "Maximum batch size is 100"}), 400
129
+
130
+ # Process in parallel using thread pool
131
+ futures = [executor.submit(process_single_iupac, iupac) for iupac in iupac_list]
132
+ results = []
133
+
134
+ for future in as_completed(futures):
135
+ results.append(future.result())
136
+
137
+ # Sort results to maintain input order
138
+ results_dict = {r['iupac']: r for r in results}
139
+ ordered_results = [results_dict.get(iupac, {"iupac": iupac, "error": "Not processed", "success": False})
140
+ for iupac in iupac_list]
141
+
142
+ processing_time = time.time() - start_time
143
+
144
+ return jsonify({
145
+ "results": ordered_results,
146
+ "total": len(iupac_list),
147
+ "successful": sum(1 for r in ordered_results if r.get('success', False)),
148
+ "failed": sum(1 for r in ordered_results if not r.get('success', False)),
149
+ "processing_time_seconds": round(processing_time, 3)
150
+ })
151
+
152
+ except Exception as e:
153
+ app.logger.error(f"Error in batch processing: {str(e)}")
154
  return jsonify({"error": str(e)}), 500
155
 
156
+ @app.route('/iupac_to_smiles', methods=['GET', 'POST'])
157
  def iupac_to_smiles():
158
  try:
159
+ if request.method == 'GET':
160
+ iupac = request.args.get('iupac')
161
+ else: # POST
162
+ data = request.get_json()
163
+ iupac = data.get('iupac') if data else None
164
+
165
  if not iupac:
166
  return jsonify({"error": "Missing 'iupac' parameter"}), 400
167
 
168
+ result = process_single_iupac(iupac)
169
+ if result['success']:
170
+ return jsonify(result)
171
+ else:
172
+ return jsonify(result), 500
173
+
174
  except Exception as e:
175
  app.logger.error(f"Error translating IUPAC: {str(e)}")
176
  return jsonify({"error": str(e)}), 500