File size: 7,072 Bytes
dbbc9f9
 
0b7abd6
d7b7032
 
 
 
dbbc9f9
 
 
 
 
 
 
 
 
 
30b0367
d7b7032
3aeec2f
ce80c98
d7b7032
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ce80c98
d7b7032
3aeec2f
 
 
 
 
 
 
 
 
 
 
dbbc9f9
 
d7b7032
dbbc9f9
d7b7032
dbbc9f9
d7b7032
9a08316
d7b7032
 
 
 
9a08316
 
 
d7b7032
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6b77134
d7b7032
 
 
 
 
 
 
 
 
 
9a08316
dbbc9f9
d7b7032
 
 
 
 
0b7abd6
 
d7b7032
0b7abd6
d7b7032
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import os
import requests
import gradio as gr
import json  # For handling JSON responses
from pymatgen.core import Structure, Lattice
from pymatgen.io.cif import CifWriter
from pymatgen.io.xyz import XYZ

# Retrieve the API key from the environment variable
groq_api_key = os.getenv("GROQ_API_KEY")
if not groq_api_key:
    raise ValueError("GROQ_API_KEY is missing! Set it in the Hugging Face Spaces 'Secrets'.")

# Define the API endpoint and headers
url = "https://api.groq.com/openai/v1/chat/completions"
headers = {"Authorization": f"Bearer {groq_api_key}"}

# Function to interact with Groq API
def get_material_info(user_input):
    json_format = """
    ```json
    {
      "materials": [
        {
          "Material Name": "...",
          "Key Properties": {
            "Property 1": "value unit",
            "Property 2": "value unit",
            "...": "..."
          },
          "Suitability Explanation": "...",
          "Atomic Structure": "..."
        },
        {
          "Material Name": "...",
          "Key Properties": {
            "Property 1": "value unit",
            "Property 2": "value unit",
            "...": "..."
          },
          "Suitability Explanation": "...",
          "Atomic Structure": "..."
        },
        {
          "Material Name": "...",
          "Key Properties": {
            "Property 1": "value unit",
            "Property 2": "value unit",
            "...": "..."
          },
          "Suitability Explanation": "...",
          "Atomic Structure": "..."
        }
      ]
    }
    ```
    """
    prompt = f"""You are a materials science expert. A user is asking for applications of materials.
    Based on the user's request: "{user_input}", identify the 3 best materials for this application.
    For each material, provide:
    - Material Name:
    - Key Properties relevant to the application: (e.g., strength, conductivity, melting point) with values if possible.
    - A brief explanation of why this material is suitable for the application.
    - A simplified representation of its atomic structure (if readily available and can be described textually, e.g., "FCC lattice", "HCP lattice", or a simple chemical formula with a basic structural description).

    Format your response as a JSON object with the following structure:
    {json_format}
    """
    body = {
        "model": "llama-3.1-8b-instant",
        "messages": [{"role": "user", "content": prompt}]
    }

    response = requests.post(url, headers=headers, json=body)

    if response.status_code == 200:
        try:
            return json.loads(response.json()['choices'][0]['message']['content'])
        except json.JSONDecodeError:
            return f"Error decoding JSON: {response.text}"
    else:
        return f"Error: {response.json()}"

def create_structure_file(material_info, file_format="xyz"):
    if not isinstance(material_info, dict) or "materials" not in material_info or not material_info["materials"]:
        return "No material information found to create structure file.", None

    # Choose the first material for structure generation (can be modified to let user choose)
    first_material = material_info["materials"][0]
    structure_description = first_material.get("Atomic Structure", "")
    material_name = first_material.get("Material Name", "unknown")

    if not structure_description:
        return f"No atomic structure information available for {material_name}.", None

    # Attempt to create a basic structure based on the description
    try:
        if "FCC lattice" in structure_description.lower():
            lattice = Lattice.cubic(4.0)  # Example lattice parameter
            structure = Structure(lattice, ["A", "A", "A", "A"], [[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]])
        elif "HCP lattice" in structure_description.lower():
            lattice = Lattice.hexagonal(3.0, 5.0) # Example lattice parameters
            structure = Structure(lattice, ["A", "A"], [[0, 0, 0], [1/3, 2/3, 1/2]])
        elif structure_description and len(structure_description.split()) == 2: # Attempt simple diatomic
            formula, struct = structure_description.split()
            if len(formula) == 2 and len(struct.lower()) == 3 and "unit" in struct.lower():
                lattice = Lattice.cubic(3.5) # Another example
                structure = Structure(lattice, [formula[0], formula[1]], [[0, 0, 0], [0.5, 0.5, 0.5]])
        else:
            return f"Could not interpret the atomic structure description for {material_name}.", None

        # Limit to 20 atoms if the generated structure has more
        if structure.num_sites > 20:
            structure = structure[:20]

        if file_format == "xyz":
            filepath = f"{material_name.replace(' ', '_')}_20atoms.xyz"
            XYZ(structure).write_file(filepath)
        elif file_format == "cif":
            filepath = f"{material_name.replace(' ', '_')}_20atoms.cif"
            CifWriter(structure, symprec=1e-5).write_file(filepath)
        else:
            return f"Unsupported file format: {file_format}", None

        with open(filepath, 'r') as f:
            file_content = f.read()
        os.remove(filepath) # Clean up the temporary file
        return f"Successfully created {file_format} file for {material_name} (first 20 atoms).", file_content

    except Exception as e:
        return f"Error creating structure file for {material_name}: {e}", None

def chat_and_generate(user_input, file_format):
    material_info = get_material_info(user_input)
    structure_message, file_content = create_structure_file(material_info, file_format)

    output_text = ""
    if isinstance(material_info, dict) and "materials" in material_info:
        for i, material in enumerate(material_info["materials"]):
            output_text += f"**Material {i+1}: {material['Material Name']}**\n"
            output_text += f"Key Properties: {', '.join([f'{k}: {v}' for k, v in material['Key Properties'].items()])}\n"
            output_text += f"Suitability: {material['Suitability Explanation']}\n"
            output_text += f"Atomic Structure: {material['Atomic Structure']}\n\n"
    else:
        output_text = str(material_info)

    return output_text, structure_message, file_content

# Create Gradio interface
inputs = [
    gr.Textbox(lines=2, placeholder="Ask for material applications (e.g., 'materials for high-temperature superconductors')."),
    gr.Radio(["xyz", "cif"], label="Generate Structure File (first material)", value="xyz")
]
outputs = [
    gr.Markdown(),
    gr.Textbox(label="Structure Generation Status"),
    gr.Code(label="Generated Structure File Content")
]

interface = gr.Interface(
    fn=chat_and_generate,
    inputs=inputs,
    outputs=outputs,
    title="Materials Science Expert AI",
    description="Ask about applications of materials and get information on the top 3 candidates with their properties and a generated atomic structure file (first 20 atoms).",
)

# Launch Gradio app
if __name__ == "__main__":
    interface.launch()