File size: 6,444 Bytes
b68d8c4
 
 
 
 
 
 
 
 
 
 
6a43816
b68d8c4
 
 
 
 
 
9deac83
b68d8c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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)