shivrajkarewar commited on
Commit
a2f1c6d
·
verified ·
1 Parent(s): 9e17c71

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -324
app.py CHANGED
@@ -1,339 +1,50 @@
1
  import os
2
- import json
3
- import gradio as gr
4
- import groq
5
- import numpy as np
6
- import matplotlib.pyplot as plt
7
- import py3Dmol
8
- from pymatgen.core.structure import Structure
9
- from pymatgen.io.cif import CifWriter
10
- from pymatgen.io.xyz import XYZ
11
- from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
12
  import requests
13
- from dotenv import load_dotenv
14
- import tempfile
15
- import base64
16
-
17
- # Load environment variables
18
- load_dotenv()
19
 
20
  # Retrieve the API key from the environment variable
21
  groq_api_key = os.getenv("GROQ_API_KEY")
22
- if not groq_api_key:
23
- raise ValueError("GROQ_API_KEY environment variable not set")
24
-
25
- # Initialize Groq client
26
- client = groq.Groq(api_key=groq_api_key)
27
 
28
- # Function to generate crystal structures
29
- def generate_crystal_structure(material_name):
30
- """Generate a crystal structure for a given material."""
31
- # This is a simplified version - in a real application, you would use a database or API
32
- # to get real crystal structure data for materials
33
-
34
- # Dictionary of common materials and their crystal structures
35
- material_structures = {
36
- "Silicon": {
37
- "spacegroup": "Fd-3m",
38
- "lattice": [[0, 5.431/2, 5.431/2], [5.431/2, 0, 5.431/2], [5.431/2, 5.431/2, 0]],
39
- "species": ["Si"],
40
- "coords": [[0, 0, 0]]
41
- },
42
- "Titanium Dioxide": {
43
- "spacegroup": "P42/mnm",
44
- "lattice": [[4.594, 0, 0], [0, 4.594, 0], [0, 0, 2.959]],
45
- "species": ["Ti", "O", "O"],
46
- "coords": [[0, 0, 0], [0.3053, 0.3053, 0], [0.3053, 0.6947, 0.5]]
47
- },
48
- "Graphene": {
49
- "spacegroup": "P6/mmm",
50
- "lattice": [[2.46, 0, 0], [-2.46/2, 2.46*np.sqrt(3)/2, 0], [0, 0, 15]],
51
- "species": ["C", "C"],
52
- "coords": [[0, 0, 0], [1/3, 2/3, 0]]
53
- },
54
- "Copper": {
55
- "spacegroup": "Fm-3m",
56
- "lattice": [[3.615, 0, 0], [0, 3.615, 0], [0, 0, 3.615]],
57
- "species": ["Cu"],
58
- "coords": [[0, 0, 0]]
59
- },
60
- "Aluminum": {
61
- "spacegroup": "Fm-3m",
62
- "lattice": [[4.05, 0, 0], [0, 4.05, 0], [0, 0, 4.05]],
63
- "species": ["Al"],
64
- "coords": [[0, 0, 0]]
65
- },
66
- "Gold": {
67
- "spacegroup": "Fm-3m",
68
- "lattice": [[4.078, 0, 0], [0, 4.078, 0], [0, 0, 4.078]],
69
- "species": ["Au"],
70
- "coords": [[0, 0, 0]]
71
- },
72
- "Diamond": {
73
- "spacegroup": "Fd-3m",
74
- "lattice": [[0, 3.567/2, 3.567/2], [3.567/2, 0, 3.567/2], [3.567/2, 3.567/2, 0]],
75
- "species": ["C"],
76
- "coords": [[0, 0, 0]]
77
- },
78
- "Graphite": {
79
- "spacegroup": "P63/mmc",
80
- "lattice": [[2.46, 0, 0], [-1.23, 2.13, 0], [0, 0, 6.71]],
81
- "species": ["C", "C", "C", "C"],
82
- "coords": [[0, 0, 0], [0, 0, 0.5], [1/3, 2/3, 0], [2/3, 1/3, 0.5]]
83
- }
84
- }
85
-
86
- # Try to match the material name with our database (case insensitive)
87
- for known_material, structure_data in material_structures.items():
88
- if material_name.lower() in known_material.lower():
89
- structure = Structure.from_spacegroup(
90
- structure_data["spacegroup"],
91
- lattice=structure_data["lattice"],
92
- species=structure_data["species"],
93
- coords=structure_data["coords"]
94
- )
95
- return structure
96
-
97
- # If material not found, create a generic structure
98
- return Structure.from_spacegroup(
99
- "Pm-3m",
100
- lattice=[[4.0, 0, 0], [0, 4.0, 0], [0, 0, 4.0]],
101
- species=["X"],
102
- coords=[[0, 0, 0]]
103
  )
104
-
105
- # Function to get material recommendations from LLM
106
- def get_material_recommendations(query):
107
- """Get material recommendations from the LLM based on user query."""
108
- system_prompt = """You are a materials science expert. Your task is to recommend the 3 best materials for a specific application or with certain properties based on the user's query.
109
-
110
- For each material, provide:
111
- 1. Material name
112
- 2. Chemical formula
113
- 3. Key properties relevant to the application
114
- 4. Why it's suitable for the application
115
- 5. Any limitations or considerations
116
 
117
- Format your response as a JSON object with the following structure:
118
- {
119
- "materials": [
120
- {
121
- "name": "Material Name",
122
- "formula": "Chemical Formula",
123
- "properties": "Key properties relevant to the application",
124
- "suitability": "Why it's suitable for the application",
125
- "limitations": "Any limitations or considerations"
126
- },
127
- // Second material
128
- // Third material
129
  ]
130
  }
131
 
132
- Ensure your response is strictly in this JSON format with no additional text."""
133
 
134
- try:
135
- completion = client.chat.completions.create(
136
- model="deepseek-r1",
137
- messages=[
138
- {"role": "system", "content": system_prompt},
139
- {"role": "user", "content": query}
140
- ],
141
- temperature=0.2,
142
- max_tokens=1000
143
- )
144
-
145
- response_text = completion.choices[0].message.content
146
-
147
- # Extract JSON from the response
148
- try:
149
- # Try to parse the entire response as JSON
150
- recommendations = json.loads(response_text)
151
- except json.JSONDecodeError:
152
- # If that fails, try to extract JSON using string manipulation
153
- json_start = response_text.find('{')
154
- json_end = response_text.rfind('}') + 1
155
- if json_start >= 0 and json_end > json_start:
156
- json_str = response_text[json_start:json_end]
157
- recommendations = json.loads(json_str)
158
- else:
159
- raise ValueError("Could not extract valid JSON from LLM response")
160
-
161
- return recommendations
162
- except Exception as e:
163
- return {"error": str(e)}
164
-
165
- # Function to get crystal structure information
166
- def get_crystal_structure_info(material_name):
167
- """Get crystal structure information for a given material."""
168
- try:
169
- # Generate the crystal structure
170
- structure = generate_crystal_structure(material_name)
171
-
172
- # Create a CIF file
173
- cif_writer = CifWriter(structure)
174
- with tempfile.NamedTemporaryFile(suffix='.cif', delete=False) as temp_cif:
175
- cif_writer.write_file(temp_cif.name)
176
- cif_path = temp_cif.name
177
-
178
- with open(cif_path, 'r') as f:
179
- cif_content = f.read()
180
-
181
- # Create an XYZ file
182
- with tempfile.NamedTemporaryFile(suffix='.xyz', delete=False) as temp_xyz:
183
- xyz_path = temp_xyz.name
184
-
185
- # Convert structure to XYZ format
186
- ase_atoms = structure.to_ase()
187
- from ase.io import write as ase_write
188
- ase_write(xyz_path, ase_atoms, format='xyz')
189
-
190
- with open(xyz_path, 'r') as f:
191
- xyz_content = f.read()
192
-
193
- # Get space group information
194
- analyzer = SpacegroupAnalyzer(structure)
195
- spacegroup = analyzer.get_space_group_symbol()
196
-
197
- # Generate 3D visualization
198
- view = py3Dmol.view(width=500, height=400)
199
- view.addModel(xyz_content, 'xyz')
200
- view.setStyle({'sphere': {'colorscheme': 'Jmol', 'scale': 0.3},
201
- 'stick': {'radius': 0.2}})
202
- view.zoomTo()
203
- view.spin(True)
204
- view.setBackgroundColor('white')
205
- view.render()
206
-
207
- # Convert the view to HTML
208
- html_str = view._make_html()
209
-
210
- # Clean up temporary files
211
- os.unlink(cif_path)
212
- os.unlink(xyz_path)
213
-
214
- return {
215
- "material_name": material_name,
216
- "formula": structure.composition.reduced_formula,
217
- "space_group": spacegroup,
218
- "num_atoms": len(structure),
219
- "lattice_parameters": {
220
- "a": structure.lattice.a,
221
- "b": structure.lattice.b,
222
- "c": structure.lattice.c,
223
- "alpha": structure.lattice.alpha,
224
- "beta": structure.lattice.beta,
225
- "gamma": structure.lattice.gamma
226
- },
227
- "cif_content": cif_content,
228
- "xyz_content": xyz_content,
229
- "visualization_html": html_str
230
- }
231
- except Exception as e:
232
- return {"error": str(e)}
233
-
234
- # Function to create a downloadable file
235
- def create_downloadable_file(content, filename):
236
- """Create a downloadable file with the given content."""
237
- with open(filename, 'w') as f:
238
- f.write(content)
239
- return filename
240
-
241
- # Gradio interface
242
- def process_query(query):
243
- """Process the user query and return material recommendations and crystal structure visualization."""
244
- try:
245
- # Get material recommendations from LLM
246
- recommendations = get_material_recommendations(query)
247
-
248
- if "error" in recommendations:
249
- return f"Error getting recommendations: {recommendations['error']}", None, None, None
250
-
251
- # Format the recommendations as text
252
- recommendation_text = "# Material Recommendations\n\n"
253
-
254
- for i, material in enumerate(recommendations.get("materials", [])):
255
- recommendation_text += f"## {i+1}. {material.get('name', 'Unknown')}\n"
256
- recommendation_text += f"**Formula:** {material.get('formula', 'N/A')}\n\n"
257
- recommendation_text += f"**Properties:** {material.get('properties', 'N/A')}\n\n"
258
- recommendation_text += f"**Suitability:** {material.get('suitability', 'N/A')}\n\n"
259
- recommendation_text += f"**Limitations:** {material.get('limitations', 'N/A')}\n\n"
260
-
261
- # Get crystal structure information for the first recommended material
262
- cif_file = None
263
- xyz_file = None
264
-
265
- if recommendations.get("materials") and len(recommendations.get("materials")) > 0:
266
- first_material = recommendations["materials"][0]["name"]
267
- structure_info = get_crystal_structure_info(first_material)
268
-
269
- if "error" in structure_info:
270
- structure_html = f"<p>Error getting crystal structure: {structure_info['error']}</p>"
271
- else:
272
- # Add crystal structure information to the recommendation text
273
- recommendation_text += f"# Crystal Structure of {structure_info['material_name']}\n\n"
274
- recommendation_text += f"**Formula:** {structure_info['formula']}\n\n"
275
- recommendation_text += f"**Space Group:** {structure_info['space_group']}\n\n"
276
- recommendation_text += f"**Number of Atoms:** {structure_info['num_atoms']}\n\n"
277
- recommendation_text += "**Lattice Parameters:**\n"
278
- recommendation_text += f"a = {structure_info['lattice_parameters']['a']:.4f} Å, "
279
- recommendation_text += f"b = {structure_info['lattice_parameters']['b']:.4f} Å, "
280
- recommendation_text += f"c = {structure_info['lattice_parameters']['c']:.4f} Å\n"
281
- recommendation_text += f"α = {structure_info['lattice_parameters']['alpha']:.2f}°, "
282
- recommendation_text += f"β = {structure_info['lattice_parameters']['beta']:.2f}°, "
283
- recommendation_text += f"γ = {structure_info['lattice_parameters']['gamma']:.2f}°\n\n"
284
-
285
- # Create HTML for the 3D visualization
286
- structure_html = structure_info['visualization_html']
287
-
288
- # Create downloadable files
289
- cif_file = create_downloadable_file(structure_info['cif_content'], f"{structure_info['material_name'].replace(' ', '_')}.cif")
290
- xyz_file = create_downloadable_file(structure_info['xyz_content'], f"{structure_info['material_name'].replace(' ', '_')}.xyz")
291
- else:
292
- structure_html = "<p>No materials recommended to visualize.</p>"
293
-
294
- return recommendation_text, structure_html, cif_file, xyz_file
295
- except Exception as e:
296
- return f"Error processing query: {str(e)}", None, None, None
297
 
298
- # Create the Gradio interface
299
- with gr.Blocks(title="Material Science Expert") as demo:
300
- gr.Markdown("# Material Science Expert")
301
- gr.Markdown("Ask for a material for a specific application or with certain properties.")
302
-
303
- with gr.Row():
304
- with gr.Column():
305
- query_input = gr.Textbox(
306
- label="Your Query",
307
- placeholder="I need a material with high thermal conductivity for electronics cooling.",
308
- lines=3
309
- )
310
- submit_btn = gr.Button("Get Recommendations")
311
-
312
- with gr.Row():
313
- with gr.Column(scale=1):
314
- recommendations_output = gr.Markdown(label="Material Recommendations")
315
- with gr.Column(scale=1):
316
- structure_output = gr.HTML(label="Crystal Structure Visualization")
317
-
318
- with gr.Row():
319
- with gr.Column():
320
- cif_file_output = gr.File(label="Download CIF File")
321
- xyz_file_output = gr.File(label="Download XYZ File")
322
-
323
- submit_btn.click(
324
- fn=process_query,
325
- inputs=[query_input],
326
- outputs=[recommendations_output, structure_output, cif_file_output, xyz_file_output]
327
- )
328
-
329
- gr.Markdown("""
330
- ## Example Queries:
331
- - I need a material with high thermal conductivity for electronics cooling.
332
- - What are the best materials for solar cell applications?
333
- - Recommend materials with high strength-to-weight ratio for aerospace applications.
334
- - I need a transparent conductive material for touchscreens.
335
- """)
336
 
337
- # Launch the app
338
  if __name__ == "__main__":
339
- demo.launch(server_name="0.0.0.0")
 
1
  import os
 
 
 
 
 
 
 
 
 
 
2
  import requests
3
+ import gradio as gr
 
 
 
 
 
4
 
5
  # Retrieve the API key from the environment variable
6
  groq_api_key = os.getenv("GROQ_API_KEY")
 
 
 
 
 
7
 
8
+ if not groq_api_key:
9
+ raise ValueError("GROQ_API_KEY is missing! Set it in the Hugging Face Spaces 'Secrets'.")
10
+
11
+ # Define the API endpoint and headers
12
+ url = "https://api.groq.com/openai/v1/chat/completions"
13
+ headers = {"Authorization": f"Bearer {groq_api_key}"}
14
+
15
+ # Function to interact with Groq API
16
+ def chat_with_groq(user_input):
17
+ system_prompt = (
18
+ "You are an expert materials scientist. When a user asks about the best materials for a specific application, "
19
+ "provide the top 3 material choices. For each, include a brief justification with their relevant mechanical, "
20
+ "thermal, and chemical properties. First list the key properties required for that application, then present a comparison "
21
+ "table of the top 3 materials highlighting those properties. Format the response in markdown."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  )
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ body = {
25
+ "model": "llama-3.1-8b-instant",
26
+ "messages": [
27
+ {"role": "system", "content": system_prompt},
28
+ {"role": "user", "content": user_input}
 
 
 
 
 
 
 
29
  ]
30
  }
31
 
32
+ response = requests.post(url, headers=headers, json=body)
33
 
34
+ if response.status_code == 200:
35
+ return response.json()['choices'][0]['message']['content']
36
+ else:
37
+ return f"Error: {response.json()}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ # Create Gradio interface
40
+ interface = gr.Interface(
41
+ fn=chat_with_groq,
42
+ inputs=gr.Textbox(lines=2, placeholder="Ask about materials for a specific application..."),
43
+ outputs=gr.Markdown(),
44
+ title="Materials Science Expert Chatbot",
45
+ description="Ask about the best materials for a given application. Get the top 3 candidates with detailed comparison of their properties."
46
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ # Launch Gradio app
49
  if __name__ == "__main__":
50
+ interface.launch()