# app.py - Ultra-reliable, simplified version import os import gradio as gr import time import traceback from openai import OpenAI # Check if API key is in environment variable DEFAULT_API_KEY = os.environ.get("OPENAI_API_KEY", "") # Create our material knowledge base (simplified version) MATERIAL_KNOWLEDGE = """ # Material Selection Guide for Chemical Processing ## Caustic Soda (NaOH) For concentrations up to 50% and temperatures up to 90°C: - Stainless Steel 316L: Excellent corrosion resistance, suitable for most applications - Nickel Alloy 400 (Monel): Superior for high-concentration applications - Alloy 20: Excellent for mixed acid/caustic environments - PTFE-lined carbon steel: Cost-effective option with excellent chemical resistance - FRP (Fiber Reinforced Plastic): Good for lower temperatures and pressures ## Sulfuric Acid (H2SO4) For concentrations up to 98%: - Alloy 20: Excellent for sulfuric acid up to 80°C - PTFE-lined carbon steel: Excellent chemical resistance across all concentrations - High-silicon cast iron (14%+ Si): Excellent for concentrations above 80% - FRP with vinyl ester resin: Good for concentrations below 70% at ambient temperature - Carpenter 20Cb-3: Good for concentrations below 80% up to 60°C ## Hydrochloric Acid (HCl) For concentrations up to 37%: - Hastelloy C-276: Excellent resistance across all temperatures and concentrations - Hastelloy B-3: Superior performance for HCl service - PVDF (Polyvinylidene fluoride): Excellent for room temperature applications - FRP with vinyl ester resin: Good for temperatures below 80°C - Zirconium: Excellent but expensive option for high-temperature service ## Seawater Applications For seawater and brackish water: - Super Duplex Stainless Steel (UNS S32750): Excellent resistance to seawater corrosion - Copper-Nickel Alloys (90/10 or 70/30): Traditional marine service materials - Titanium Grade 2: Superior performance but higher cost - 6% Molybdenum Stainless Steels: Excellent for critical seawater applications - FRP with vinyl ester resin: Good for low-pressure applications ## High-Temperature Service For temperatures above 200°C: - Inconel 625: Excellent for temperatures up to 980°C - Hastelloy X: Superior for high-temperature oxidizing environments - Stainless Steel 310/310S: Good for temperatures up to 1100°C - Monel 400: Good for reducing environments up to 540°C - Incoloy 800H/800HT: Designed for high-temperature strength and carburization resistance """ # Extremely simplified material recommendation function def get_material_recommendation(query, api_key): # Basic error checking try: log_message = f"[DEBUG] Processing query: {query[:50]}..." print(log_message) # Format the AI prompt messages = [ {"role": "system", "content": f"You are MatSelectAI, an expert materials engineer. Use this knowledge base:\n\n{MATERIAL_KNOWLEDGE}"}, {"role": "user", "content": f"Query: {query}\n\nProvide material recommendations with specific grades, properties, limitations, and alternatives."} ] # Simple OpenAI call with timeout try: # Initialize the client print("[DEBUG] Initializing OpenAI client...") client = OpenAI(api_key=api_key, timeout=60.0) # Call the API print("[DEBUG] Calling OpenAI API...") response = client.chat.completions.create( model="gpt-3.5-turbo", messages=messages, temperature=0.3, max_tokens=800 ) # Extract and return the response print("[DEBUG] Successfully received response from OpenAI") answer = response.choices[0].message.content return answer except Exception as e: # Get detailed error information error_trace = traceback.format_exc() print(f"[ERROR] OpenAI API error: {str(e)}\n{error_trace}") # Return a user-friendly error message return f"❌ Error communicating with OpenAI API: {str(e)}\n\nPlease try again or check your API key." except Exception as e: # Catch-all for any other errors error_trace = traceback.format_exc() print(f"[ERROR] Unexpected error: {str(e)}\n{error_trace}") return f"❌ Unexpected error: {str(e)}" # Simple Gradio interface with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown("# MatSelectAI - Material Selection Assistant") gr.Markdown("Get recommendations for piping and equipment materials based on fluid types") with gr.Row(): with gr.Column(): # API key input api_key_input = gr.Textbox( label="OpenAI API Key", placeholder="Enter your OpenAI API key (sk-...)", type="password", value=DEFAULT_API_KEY ) # Query input query_input = gr.Textbox( label="Material Selection Query", placeholder="e.g., What materials are suitable for piping carrying 50% NaOH at 80°C?", lines=3 ) # Buttons with gr.Row(): submit_btn = gr.Button("Get Recommendation", variant="primary") clear_btn = gr.Button("Clear") # Diagnostic info with gr.Accordion("Diagnostics", open=False): status_info = gr.Markdown("Status: Ready") # Output area output_area = gr.Markdown(label="Material Recommendation") # Example queries gr.Examples( examples=[ "What materials are suitable for piping carrying 50% NaOH at 80°C?", "Recommend materials for a heat exchanger with seawater", "Best corrosion-resistant materials for sulfuric acid storage tanks", "What piping material should I use for HCl at room temperature?", "Material options for a vessel containing caustic soda" ], inputs=query_input ) # Function to get recommendation def process_query(query, api_key): # Update status status = "Processing query..." # Validate API key if not api_key or not api_key.startswith("sk-"): return ( f"⚠️ Please enter a valid OpenAI API key (should start with 'sk-')", "Status: ❌ Missing or invalid API key" ) try: # Update status and get recommendation status = f"Sending request to OpenAI API..." result = get_material_recommendation(query, api_key) status = "Status: ✅ Response received" return result, status except Exception as e: error_trace = traceback.format_exc() print(f"[ERROR] Error in process_query: {str(e)}\n{error_trace}") return f"❌ Error: {str(e)}", f"Status: ❌ Error: {str(e)}" # Function to clear inputs def clear_inputs(): return "", "Status: Ready" # Connect the buttons submit_btn.click( process_query, inputs=[query_input, api_key_input], outputs=[output_area, status_info] ) clear_btn.click( clear_inputs, outputs=[query_input, status_info] ) # Launch the app if __name__ == "__main__": demo.launch()