import os import gradio as gr import google.generativeai as genai from PIL import Image from dotenv import load_dotenv # 1. Setup & Configuration # --------------------------------------------------------- load_dotenv() # Fetch API Key from environment (HF Secrets or .env file) API_KEY = os.getenv("GEMINI_API_KEY") if not API_KEY: # Fallback for local testing if env var is missing print("⚠️ WARNING: GEMINI_API_KEY not found. Please set it in your environment.") # Configure Gemini genai.configure(api_key=API_KEY) # Use Gemini 1.5 Flash for speed and multimodal capabilities MODEL_NAME = "gemini-1.5-flash" generation_config = { "temperature": 0.4, # Lower temperature for more analytical/precise reasoning "top_p": 0.95, "top_k": 64, "max_output_tokens": 8192, } model = genai.GenerativeModel( model_name=MODEL_NAME, generation_config=generation_config, ) # 2. The "Signal Ghost" Logic (Bayesian Analysis) # --------------------------------------------------------- def signal_ghost_analysis(image, audio_path): """ Core function to process the multimodal inputs via Gemini. """ if not API_KEY: return "❌ Error: API Key is missing. Please configure GEMINI_API_KEY in Settings." if image is None or audio_path is None: return "⚠️ Please upload both a PCB Image and an Audio Signal file to begin the diagnostic." print("👻 Signal Ghost: Processing inputs...") # Upload audio file to Gemini File API (required for audio processing) # Note: In a production app, manage file deletion/lifecycle. # For Hackathon demo, simple upload is fine. try: audio_file = genai.upload_file(path=audio_path) except Exception as e: return f"❌ Error processing audio: {str(e)}" # The "Ghost" System Prompt # We instruct the model to act as a Bayesian Diagnostic Engine. prompt = """ You are 'Signal Ghost', an advanced AI diagnostic ecosystem for Electrical Engineering. **YOUR MISSION:** Perform a cross-domain analysis of the provided PCB IMAGE and the AUDIO SIGNAL (EMI noise/interference). Use Bayesian reasoning: Update your confidence in a fault based on the combined evidence of visual defects and auditory signal signatures. **INPUTS:** 1. Visual: A circuit board image (look for burnt components, bad traces, grounding issues). 2. Audio: A recording of electrical noise/interference (listen for 50/60Hz hum, high-pitch switching whine, arcing pops). **OUTPUT FORMAT:** You must generate a response with two distinct sections separated by a horizontal rule. --- ### 🏗️ SECTION 1: ENGINEER TECHNICAL REPORT (The "Raw Data") * **Tone:** Professional, precise, metric-driven (ISO/IEEE standard). * **Bayesian Confidence:** "Fault Probability: X%" (Explain the priors: Visual + Audio). * **Signal Analysis:** Estimate frequencies (e.g., "120Hz Ripple"), dB estimates, and wave shapes. * **Visual Analysis:** Component coordinates (e.g., "Top left capacitor"), specific damage type. * **Action Plan:** Bullet points of technical fixes (e.g., "Replace C4 with low-ESR variant", "Add ferrite bead"). --- ### 🎓 SECTION 2: STUDENT SUMMARY (The "Translation") * **Tone:** Socratic, encouraging, simplified. * **The Analogy:** Explain the technical fault using a real-world analogy (e.g., plumbing, traffic, music). * **Why it happened:** Simple cause-and-effect. * **Learning Moment:** One key concept to remember (e.g., "Why do capacitors explode?"). """ # Generate Content try: response = model.generate_content([prompt, image, audio_file]) return response.text except Exception as e: return f"❌ Analysis Failed: {str(e)}" # 3. User Interface (Gradio) # --------------------------------------------------------- # Custom CSS for that "Cyber/Ghost" Aesthetic ghost_css = """ body { background-color: #0b0f19; color: #e0e0e0; } gradio-app { background-color: #0b0f19 !important; } .header-text { text-align: center; font-family: 'Courier New', monospace; color: #00f3ff; text-shadow: 0px 0px 10px #00f3ff; } .sub-text { text-align: center; color: #8892b0; font-size: 1.1em; } button.primary { background: linear-gradient(90deg, #00f3ff 0%, #0077ff 100%); border: none; color: #000; font-weight: bold; transition: all 0.3s ease; } button.primary:hover { box-shadow: 0px 0px 15px #00f3ff; transform: scale(1.02); } .panel { border: 1px solid #1f2937; background-color: #111827; border-radius: 8px; } """ with gr.Blocks(theme=gr.themes.Soft(), css=ghost_css, title="Signal Ghost") as app: # --- Header --- with gr.Row(): with gr.Column(): gr.Markdown("# 👻 SIGNAL GHOST", elem_classes=["header-text"]) gr.Markdown("### Multimodal ECE Diagnostic Ecosystem", elem_classes=["sub-text"]) gr.Markdown("Upload a PCB Image and an Audio Recording of the circuit noise to detect EMI faults.", elem_classes=["sub-text"]) # --- Input Section --- with gr.Row(equal_height=True): with gr.Column(scale=1, min_width=300): gr.Markdown("### 👁️ Visual Input (PCB)") img_input = gr.Image(type="pil", label="Upload Circuit Board Image", sources=["upload", "clipboard"]) with gr.Column(scale=1, min_width=300): gr.Markdown("### 👂 Auditory Input (Signal Noise)") audio_input = gr.Audio(type="filepath", label="Upload Noise Signal (.wav, .mp3)", sources=["upload", "microphone"]) # --- Action Button --- with gr.Row(): analyze_btn = gr.Button("🔍 INITIATE DIAGNOSTIC SEQUENCE", variant="primary", size="lg") # --- Output Section --- with gr.Row(): with gr.Column(): gr.Markdown("### 📊 Diagnostic Output") output_text = gr.Markdown(value="Waiting for signal inputs...", label="Analysis Report") # --- Footer --- with gr.Row(): gr.Markdown("---") gr.Markdown("*Powered by Gemini 1.5 Flash • Bayesian Inference Engine v1.0*") # --- Event Binding --- analyze_btn.click( fn=signal_ghost_analysis, inputs=[img_input, audio_input], outputs=output_text ) # 4. Launch # --------------------------------------------------------- if __name__ == "__main__": app.launch(server_name="0.0.0.0", server_port=7860)