madzzey commited on
Commit
7644b0d
·
1 Parent(s): 25e328c

Add application file

Browse files
Files changed (3) hide show
  1. Dockerfile +34 -0
  2. app.py +281 -0
  3. requirements.txt +9 -0
Dockerfile ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # Set working directory
4
+ WORKDIR /app
5
+
6
+ # Install system dependencies
7
+ RUN apt-get update && apt-get install -y \
8
+ git \
9
+ build-essential \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy requirements first for better caching
13
+ COPY requirements.txt .
14
+
15
+ # Install Python dependencies
16
+ RUN pip install --no-cache-dir -r requirements.txt
17
+
18
+ # Copy application code
19
+ COPY . .
20
+
21
+ # Create cache directory for models
22
+ RUN mkdir -p /app/cache
23
+
24
+ # Set environment variables
25
+ ENV HF_HOME=/app/cache
26
+ ENV TRANSFORMERS_CACHE=/app/cache
27
+ ENV GRADIO_SERVER_NAME=0.0.0.0
28
+ ENV GRADIO_SERVER_PORT=7860
29
+
30
+ # Expose port
31
+ EXPOSE 7860
32
+
33
+ # Run the application
34
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import time
4
+ import pandas as pd
5
+ import plotly.express as px
6
+ import plotly.graph_objects as go
7
+ from plotly.subplots import make_subplots
8
+ import torch
9
+ from chemistry_llm import ChemistryReactionExtractor
10
+ import warnings
11
+ warnings.filterwarnings('ignore')
12
+
13
+ # Global variables
14
+ extractor = None
15
+ model_loading = False
16
+
17
+ def load_model():
18
+ """Load the RxNExtract model"""
19
+ global extractor, model_loading
20
+
21
+ if model_loading:
22
+ return "Model is currently loading, please wait..."
23
+
24
+ if extractor is not None:
25
+ return "Model already loaded!"
26
+
27
+ model_loading = True
28
+ try:
29
+ # Initialize the extractor
30
+ extractor = ChemistryReactionExtractor.from_pretrained(
31
+ "chemplusx/rxnextract-complete",
32
+ device="cuda" if torch.cuda.is_available() else "cpu",
33
+ load_in_4bit=True,
34
+ temperature=0.1,
35
+ max_length=512
36
+ )
37
+ model_loading = False
38
+ return "✅ RxNExtract model loaded successfully!"
39
+ except Exception as e:
40
+ model_loading = False
41
+ return f"❌ Error loading model: {str(e)}"
42
+
43
+ def analyze_procedure(procedure_text, include_confidence=True, temperature=0.1):
44
+ """Analyze a chemical procedure"""
45
+ global extractor
46
+
47
+ if extractor is None:
48
+ return "Please load the model first!", "", "", ""
49
+
50
+ if not procedure_text.strip():
51
+ return "Please enter a chemical procedure to analyze.", "", "", ""
52
+
53
+ try:
54
+ start_time = time.time()
55
+
56
+ # Analyze the procedure
57
+ results = extractor.analyze_procedure(
58
+ procedure_text,
59
+ return_raw=False,
60
+ temperature=temperature
61
+ )
62
+
63
+ processing_time = time.time() - start_time
64
+
65
+ # Format the results
66
+ formatted_output = format_extraction_results(results)
67
+
68
+ # Create visualizations
69
+ entity_plot = create_entity_visualization(results)
70
+ confidence_plot = create_confidence_visualization(results, processing_time)
71
+
72
+ # Create summary
73
+ summary = create_summary(results, processing_time)
74
+
75
+ return summary, formatted_output, entity_plot, confidence_plot
76
+
77
+ except Exception as e:
78
+ error_msg = f"❌ Error during analysis: {str(e)}"
79
+ return error_msg, "", "", ""
80
+
81
+ def format_extraction_results(results):
82
+ """Format extraction results for display"""
83
+ data = results['extracted_data']
84
+
85
+ output = []
86
+ output.append("## 📊 Extraction Results\n")
87
+ output.append(f"**🎯 Confidence:** {results['confidence']:.1%}")
88
+ output.append(f"**⏱️ Processing Time:** {results['processing_time']:.1f}s\n")
89
+
90
+ # Reactants
91
+ if data.get('reactants'):
92
+ output.append("### 🔵 Reactants")
93
+ for i, reactant in enumerate(data['reactants'], 1):
94
+ name = reactant.get('name', 'Unknown')
95
+ amount = reactant.get('amount', 'N/A')
96
+ output.append(f"{i}. **{name}** - Amount: {amount}")
97
+ output.append("")
98
+
99
+ # Reagents
100
+ if data.get('reagents'):
101
+ output.append("### 🟡 Reagents")
102
+ for i, reagent in enumerate(data['reagents'], 1):
103
+ name = reagent.get('name', 'Unknown')
104
+ amount = reagent.get('amount', 'N/A')
105
+ output.append(f"{i}. **{name}** - Amount: {amount}")
106
+ output.append("")
107
+
108
+ # Solvents
109
+ if data.get('solvents'):
110
+ output.append("### 🔵 Solvents")
111
+ for i, solvent in enumerate(data['solvents'], 1):
112
+ name = solvent.get('name', 'Unknown')
113
+ amount = solvent.get('amount', 'N/A')
114
+ output.append(f"{i}. **{name}** - Amount: {amount}")
115
+ output.append("")
116
+
117
+ # Products
118
+ if data.get('products'):
119
+ output.append("### 🟢 Products")
120
+ for i, product in enumerate(data['products'], 1):
121
+ name = product.get('name', 'Unknown')
122
+ amount = product.get('amount', 'N/A')
123
+ yield_val = product.get('yield', 'N/A')
124
+ output.append(f"{i}. **{name}** - Amount: {amount}, Yield: {yield_val}")
125
+ output.append("")
126
+
127
+ # Conditions
128
+ if data.get('conditions'):
129
+ output.append("### 🌡️ Reaction Conditions")
130
+ conditions = data['conditions']
131
+ for key, value in conditions.items():
132
+ if value:
133
+ output.append(f"- **{key.title()}:** {value}")
134
+ output.append("")
135
+
136
+ # Workup steps
137
+ if data.get('workup'):
138
+ output.append("### ⚗️ Workup Steps")
139
+ for i, step in enumerate(data['workup'], 1):
140
+ output.append(f"{i}. {step}")
141
+ output.append("")
142
+
143
+ return "\n".join(output)
144
+
145
+ def create_entity_visualization(results):
146
+ """Create entity count visualization"""
147
+ data = results['extracted_data']
148
+
149
+ # Count entities
150
+ entity_counts = {
151
+ 'Reactants': len(data.get('reactants', [])),
152
+ 'Reagents': len(data.get('reagents', [])),
153
+ 'Solvents': len(data.get('solvents', [])),
154
+ 'Products': len(data.get('products', [])),
155
+ 'Conditions': len([v for v in data.get('conditions', {}).values() if v]),
156
+ 'Workup Steps': len(data.get('workup', []))
157
+ }
158
+
159
+ # Remove zero counts
160
+ entity_counts = {k: v for k, v in entity_counts.items() if v > 0}
161
+
162
+ if not entity_counts:
163
+ return None
164
+
165
+ # Create bar chart
166
+ fig = px.bar(
167
+ x=list(entity_counts.keys()),
168
+ y=list(entity_counts.values()),
169
+ title="Extracted Chemical Entities",
170
+ labels={'x': 'Entity Type', 'y': 'Count'},
171
+ color=list(entity_counts.keys()),
172
+ color_discrete_sequence=px.colors.qualitative.Set3
173
+ )
174
+
175
+ fig.update_layout(
176
+ showlegend=False,
177
+ height=400,
178
+ title_x=0.5,
179
+ xaxis_tickangle=-45
180
+ )
181
+
182
+ return fig
183
+
184
+ def create_confidence_visualization(results, processing_time):
185
+ """Create confidence and timing visualization"""
186
+ confidence = results['confidence']
187
+
188
+ # Create gauge chart for confidence
189
+ fig = go.Figure(go.Indicator(
190
+ mode = "gauge+number+delta",
191
+ value = confidence * 100,
192
+ domain = {'x': [0, 1], 'y': [0, 1]},
193
+ title = {'text': "Confidence Score (%)"},
194
+ delta = {'reference': 80},
195
+ gauge = {
196
+ 'axis': {'range': [None, 100]},
197
+ 'bar': {'color': "darkblue"},
198
+ 'steps': [
199
+ {'range': [0, 50], 'color': "lightgray"},
200
+ {'range': [50, 80], 'color': "yellow"},
201
+ {'range': [80, 100], 'color': "green"}],
202
+ 'threshold': {
203
+ 'line': {'color': "red", 'width': 4},
204
+ 'thickness': 0.75,
205
+ 'value': 90}}))
206
+
207
+ fig.update_layout(
208
+ height=300,
209
+ title=f"Processing Time: {processing_time:.1f}s"
210
+ )
211
+
212
+ return fig
213
+
214
+ def create_summary(results, processing_time):
215
+ """Create a summary of the analysis"""
216
+ data = results['extracted_data']
217
+ confidence = results['confidence']
218
+
219
+ total_entities = sum([
220
+ len(data.get('reactants', [])),
221
+ len(data.get('reagents', [])),
222
+ len(data.get('solvents', [])),
223
+ len(data.get('products', []))
224
+ ])
225
+
226
+ confidence_level = "High" if confidence >= 0.8 else "Medium" if confidence >= 0.6 else "Low"
227
+
228
+ summary = f"""
229
+ ## 📈 Analysis Summary
230
+
231
+ **🎯 Overall Performance:**
232
+ - **Confidence Level:** {confidence_level} ({confidence:.1%})
233
+ - **Processing Speed:** {processing_time:.1f} seconds
234
+ - **Total Entities Extracted:** {total_entities}
235
+
236
+ **📊 Extraction Breakdown:**
237
+ - **Reactants:** {len(data.get('reactants', []))}
238
+ - **Products:** {len(data.get('products', []))}
239
+ - **Reagents:** {len(data.get('reagents', []))}
240
+ - **Solvents:** {len(data.get('solvents', []))}
241
+ - **Conditions:** {len([v for v in data.get('conditions', {}).values() if v])}
242
+ - **Workup Steps:** {len(data.get('workup', []))}
243
+
244
+ **💡 Quality Assessment:**
245
+ {get_quality_assessment(confidence, total_entities)}
246
+ """
247
+
248
+ return summary
249
+
250
+ def get_quality_assessment(confidence, total_entities):
251
+ """Get quality assessment based on confidence and entities"""
252
+ if confidence >= 0.8 and total_entities >= 3:
253
+ return "✅ Excellent extraction quality with high confidence and comprehensive entity recognition."
254
+ elif confidence >= 0.6 and total_entities >= 2:
255
+ return "✅ Good extraction quality with moderate confidence. Results are reliable."
256
+ elif confidence >= 0.4:
257
+ return "⚠️ Moderate extraction quality. Some information may be missing or uncertain."
258
+ else:
259
+ return "❌ Low extraction quality. Consider reviewing the procedure text for clarity."
260
+
261
+ def get_example_procedures():
262
+ """Get example procedures for the interface"""
263
+ examples = [
264
+ """Add 2.5 g of benzoic acid to 50 mL of ethanol in a round-bottom flask.
265
+ Heat the mixture to reflux for 4 hours while stirring.
266
+ Cool the solution to room temperature and filter the precipitate.
267
+ Wash the solid with cold ethanol and dry to obtain 2.1 g of product (84% yield).""",
268
+
269
+ """Dissolve 10.0 g of 4-nitroaniline in 200 mL of concentrated HCl.
270
+ Add 15.0 g of tin powder portionwise while maintaining temperature below 10°C.
271
+ Stir for 2 hours at room temperature, then heat to 60°C for 1 hour.
272
+ Neutralize with NaOH solution and extract with ethyl acetate (3 × 50 mL).
273
+ Dry over MgSO4 and concentrate to give 7.2 g of product (78% yield).""",
274
+
275
+ """In a round-bottom flask, combine 5.0 mmol of styrene, 6.0 mmol of phenylboronic acid,
276
+ and 0.1 mmol of Pd(PPh3)4 catalyst in 20 mL of DMF.
277
+ Add 15.0 mmol of K2CO3 and heat to 100°C under nitrogen atmosphere.
278
+ Stir for 12 hours, then cool and filter through celite.
279
+ Purify by column chromatography to obtain 0.85 g of biphenyl derivative (92% yield)."""
280
+ ]
281
+ return examples
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ torch>=1.9.0
3
+ transformers>=4.20.0
4
+ rxnextract>=1.2.0
5
+ pandas>=1.3.0
6
+ plotly>=5.0.0
7
+ numpy>=1.21.0
8
+ scikit-learn>=1.0.0
9
+ scipy>=1.7.0