amacruz commited on
Commit
ce150af
·
verified ·
1 Parent(s): 97df926

Create vision_analysis.py

Browse files
Files changed (1) hide show
  1. vision_analysis.py +670 -0
vision_analysis.py ADDED
@@ -0,0 +1,670 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ TinkerIQ Advanced Vision Analysis Module
3
+ Circuit and schematic analysis using SambaNova and OpenAI vision models
4
+ """
5
+
6
+ import os
7
+ import requests
8
+ import base64
9
+ import time
10
+ from PIL import Image
11
+ import io
12
+ import re
13
+ from datetime import datetime
14
+
15
+ class AdvancedVisionAnalysis:
16
+ """Advanced computer vision for electronic circuits and schematics"""
17
+
18
+ def __init__(self):
19
+ # API credentials
20
+ self.sambanova_api_key = os.getenv("SAMBANOVA_API_KEY")
21
+ self.openai_api_key = os.getenv("OPENAI_API_KEY")
22
+ self.anthropic_api_key = os.getenv("ANTHROPIC_API_KEY")
23
+
24
+ # API endpoints
25
+ self.sambanova_url = "https://api.sambanova.ai/v1/chat/completions"
26
+ self.openai_vision_url = "https://api.openai.com/v1/chat/completions"
27
+ self.anthropic_url = "https://api.anthropic.com/v1/messages"
28
+
29
+ # Analysis templates for different circuit types
30
+ self.analysis_prompts = {
31
+ "detailed": """You are an expert electronics engineer analyzing a circuit image. Provide a comprehensive technical analysis:
32
+
33
+ ## COMPONENT IDENTIFICATION
34
+ - List ALL visible electronic components with specific part numbers where readable
35
+ - Include passive components (resistors, capacitors, inductors) with values if visible
36
+ - Identify active components (ICs, transistors, diodes) with part numbers
37
+ - Note any development boards (Arduino, ESP32, Raspberry Pi, etc.)
38
+ - Identify connectors, switches, and mechanical components
39
+
40
+ ## CIRCUIT TOPOLOGY ANALYSIS
41
+ - Describe the overall circuit architecture and design pattern
42
+ - Explain the signal flow and data paths through the circuit
43
+ - Identify power supply connections and voltage levels
44
+ - Note ground connections and power distribution
45
+ - Describe any special circuit configurations or topologies
46
+
47
+ ## FUNCTIONAL ANALYSIS
48
+ - Explain what this circuit is designed to accomplish
49
+ - Describe the main functional blocks and their purposes
50
+ - Identify input/output connections and interfaces
51
+ - Explain any control or feedback mechanisms
52
+ - Note any protection circuits or safety features
53
+
54
+ ## TECHNICAL ASSESSMENT
55
+ - Evaluate if connections appear correct for the intended function
56
+ - Identify any obvious wiring errors or missing connections
57
+ - Check for proper component orientations (especially polarized components)
58
+ - Assess power supply adequacy and current handling
59
+ - Note any potential signal integrity or noise issues
60
+
61
+ ## IMPROVEMENT RECOMMENDATIONS
62
+ - Suggest specific component upgrades or alternatives
63
+ - Recommend additional protection or filtering components
64
+ - Propose layout improvements for better performance
65
+ - Suggest debugging aids or test points
66
+ - Recommend documentation or labeling improvements
67
+
68
+ ## SAFETY AND COMPLIANCE
69
+ - Identify any safety concerns or hazardous conditions
70
+ - Note compliance with standard practices and conventions
71
+ - Suggest safety improvements or protective measures
72
+ - Check for proper isolation and grounding
73
+
74
+ Be extremely specific and technical. Include part numbers, values, and precise technical terminology.""",
75
+
76
+ "troubleshooting": """Analyze this circuit image for troubleshooting purposes. Focus on identifying potential problems:
77
+
78
+ ## VISUAL INSPECTION
79
+ - Check all solder joints for cold solder, bridges, or dry joints
80
+ - Verify component orientations (LEDs, electrolytic capacitors, ICs, diodes)
81
+ - Look for damaged components (burned, cracked, or discolored)
82
+ - Check for loose connections or disconnected wires
83
+ - Identify any short circuits or unwanted connections
84
+
85
+ ## WIRING VERIFICATION
86
+ - Trace power connections (VCC, VDD, +5V, +3.3V, etc.)
87
+ - Verify ground connections and ground loops
88
+ - Check data/signal line connections
89
+ - Validate pin assignments match intended design
90
+ - Look for crossed or swapped connections
91
+
92
+ ## COMPONENT ANALYSIS
93
+ - Verify component values match circuit requirements
94
+ - Check component ratings (voltage, current, power)
95
+ - Identify any substituted or incorrect components
96
+ - Note missing components or empty footprints
97
+ - Check for counterfeit or suspect components
98
+
99
+ ## COMMON FAILURE MODES
100
+ - Identify typical failure points for this circuit type
101
+ - Look for stress indicators (heat damage, corrosion)
102
+ - Check for mechanical damage or wear
103
+ - Note any signs of overcurrent or overvoltage damage
104
+ - Identify environmental damage (moisture, contamination)
105
+
106
+ ## DEBUGGING RECOMMENDATIONS
107
+ - Suggest specific measurement points for multimeter testing
108
+ - Recommend signal tracing procedures
109
+ - Propose component substitution tests
110
+ - Suggest isolation techniques for fault finding
111
+ - Recommend tools or equipment for further diagnosis
112
+
113
+ Focus on actionable troubleshooting steps and specific technical guidance.""",
114
+
115
+ "educational": """Analyze this circuit from an educational perspective for learning purposes:
116
+
117
+ ## CIRCUIT FUNDAMENTALS
118
+ - Explain the basic operating principles in clear terms
119
+ - Identify key concepts demonstrated by this circuit
120
+ - Describe the role of each major component type
121
+ - Explain power flow and signal paths
122
+ - Connect theory to practical implementation
123
+
124
+ ## LEARNING OBJECTIVES
125
+ - What skills does building this circuit teach?
126
+ - What theoretical concepts are demonstrated?
127
+ - How does this relate to broader electronics knowledge?
128
+ - What prerequisites should learners have?
129
+ - What follow-up projects would build on this knowledge?
130
+
131
+ ## COMPONENT EDUCATION
132
+ - Explain why each component was chosen
133
+ - Describe component specifications and ratings
134
+ - Suggest alternatives and their trade-offs
135
+ - Explain how to read component markings and datasheets
136
+ - Discuss component sourcing and selection criteria
137
+
138
+ ## CONSTRUCTION GUIDANCE
139
+ - Provide step-by-step assembly recommendations
140
+ - Highlight critical construction points
141
+ - Suggest testing procedures at each stage
142
+ - Recommend tools and techniques
143
+ - Identify common beginner mistakes to avoid
144
+
145
+ ## EXPERIMENTATION IDEAS
146
+ - Suggest modifications to explore different behaviors
147
+ - Propose parameter variations for learning
148
+ - Recommend additional measurements or observations
149
+ - Suggest related experiments or variations
150
+ - Provide ideas for extending the project
151
+
152
+ Make the analysis accessible but technically accurate, perfect for STEM education."""
153
+ }
154
+
155
+ # Response validation patterns
156
+ self.validation_patterns = {
157
+ "generic_responses": [
158
+ "i'm unable to view",
159
+ "i cannot see",
160
+ "i can't see the image",
161
+ "i don't have the ability to view",
162
+ "i cannot analyze images",
163
+ "without seeing the actual",
164
+ "based on the description",
165
+ "typical circuit",
166
+ "common configuration",
167
+ "standard setup"
168
+ ],
169
+ "hallucination_indicators": [
170
+ "appears to be",
171
+ "seems to be",
172
+ "looks like it might be",
173
+ "could be",
174
+ "possibly",
175
+ "probably"
176
+ ]
177
+ }
178
+
179
+ print(f"🔧 Vision Analysis initialized")
180
+ print(f" SambaNova API: {'✅' if self.sambanova_api_key else '❌'}")
181
+ print(f" OpenAI API: {'✅' if self.openai_api_key else '❌'}")
182
+ print(f" Anthropic API: {'✅' if self.anthropic_api_key else '❌'}")
183
+
184
+ def encode_image_safely(self, image_path, max_size=1024, quality=85):
185
+ """
186
+ Convert image to base64 with optimization for vision APIs
187
+
188
+ Args:
189
+ image_path: Path to image file or file-like object
190
+ max_size: Maximum dimension for resizing
191
+ quality: JPEG quality (1-100)
192
+
193
+ Returns:
194
+ tuple: (base64_string, error_message)
195
+ """
196
+ try:
197
+ if image_path is None:
198
+ return None, "No image provided"
199
+
200
+ # Handle different input types
201
+ if hasattr(image_path, 'name') and image_path.name:
202
+ # Gradio file upload
203
+ image_file_path = image_path.name
204
+ print(f"📁 Processing Gradio file: {image_file_path}")
205
+ elif isinstance(image_path, str):
206
+ # File path string
207
+ image_file_path = image_path
208
+ print(f"📁 Processing file path: {image_file_path}")
209
+ else:
210
+ return None, "Unsupported image format"
211
+
212
+ # Open and process image
213
+ with Image.open(image_file_path) as img:
214
+ # Get original dimensions
215
+ original_size = img.size
216
+ print(f"📐 Original image size: {original_size[0]}x{original_size[1]}")
217
+
218
+ # Convert to RGB if necessary
219
+ if img.mode in ('RGBA', 'LA', 'P'):
220
+ print(f"🔄 Converting from {img.mode} to RGB")
221
+ img = img.convert('RGB')
222
+
223
+ # Resize if too large
224
+ if img.width > max_size or img.height > max_size:
225
+ print(f"📏 Resizing to max dimension: {max_size}")
226
+ img.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
227
+ print(f"📐 New size: {img.width}x{img.height}")
228
+
229
+ # Convert to bytes with optimization
230
+ buffer = io.BytesIO()
231
+
232
+ # Use PNG for line drawings/schematics, JPEG for photos
233
+ if self._is_schematic_like(img):
234
+ img.save(buffer, format='PNG', optimize=True)
235
+ format_used = "PNG"
236
+ else:
237
+ img.save(buffer, format='JPEG', quality=quality, optimize=True)
238
+ format_used = "JPEG"
239
+
240
+ image_data = buffer.getvalue()
241
+ file_size = len(image_data)
242
+
243
+ print(f"✅ Image processed: {file_size} bytes ({format_used})")
244
+
245
+ # Check size limits (most APIs have ~20MB limit)
246
+ if file_size > 15 * 1024 * 1024: # 15MB safety margin
247
+ return None, f"Image too large: {file_size/1024/1024:.1f}MB (max ~15MB)"
248
+
249
+ # Encode to base64
250
+ base64_string = base64.b64encode(image_data).decode('utf-8')
251
+
252
+ return base64_string, None
253
+
254
+ except FileNotFoundError:
255
+ return None, f"Image file not found: {image_path}"
256
+ except Exception as e:
257
+ error_msg = f"Image processing error: {str(e)}"
258
+ print(f"❌ {error_msg}")
259
+ return None, error_msg
260
+
261
+ def _is_schematic_like(self, img):
262
+ """Heuristic to determine if image is a schematic vs photo"""
263
+ # Convert to grayscale for analysis
264
+ gray = img.convert('L')
265
+
266
+ # Count unique colors (schematics typically have fewer)
267
+ colors = len(set(gray.getdata()))
268
+
269
+ # Schematics typically have high contrast and few colors
270
+ return colors < 50
271
+
272
+ def validate_analysis_response(self, response_text, analysis_type="detailed"):
273
+ """
274
+ Validate that the AI actually analyzed the image vs providing generic advice
275
+
276
+ Args:
277
+ response_text: AI response to validate
278
+ analysis_type: Type of analysis requested
279
+
280
+ Returns:
281
+ tuple: (is_valid, error_message)
282
+ """
283
+ response_lower = response_text.lower()
284
+
285
+ # Check for generic/inability responses
286
+ for pattern in self.validation_patterns["generic_responses"]:
287
+ if pattern in response_lower:
288
+ return False, f"Generic response detected: '{pattern}'"
289
+
290
+ # Check response length (too short suggests generic response)
291
+ if len(response_text.strip()) < 200:
292
+ return False, "Response too short/generic"
293
+
294
+ # Check for excessive uncertainty language
295
+ uncertainty_count = sum(1 for pattern in self.validation_patterns["hallucination_indicators"]
296
+ if pattern in response_lower)
297
+
298
+ if uncertainty_count > 5: # Too many uncertain statements
299
+ return False, f"Excessive uncertainty in response ({uncertainty_count} indicators)"
300
+
301
+ # Check for specific technical content based on analysis type
302
+ if analysis_type == "detailed":
303
+ required_sections = ["component", "circuit", "connection"]
304
+ found_sections = sum(1 for section in required_sections if section in response_lower)
305
+
306
+ if found_sections < 2:
307
+ return False, "Response lacks technical depth"
308
+
309
+ print("✅ Response validation passed")
310
+ return True, None
311
+
312
+ def analyze_with_sambanova(self, image_path, analysis_type="detailed", custom_prompt=None):
313
+ """
314
+ Analyze circuit image using SambaNova vision model
315
+
316
+ Args:
317
+ image_path: Path to image file
318
+ analysis_type: Type of analysis (detailed, troubleshooting, educational)
319
+ custom_prompt: Custom analysis prompt
320
+
321
+ Returns:
322
+ tuple: (result_dict, error_message)
323
+ """
324
+ print("🚀 Starting SambaNova vision analysis...")
325
+
326
+ if not self.sambanova_api_key:
327
+ return None, "SambaNova API key not configured"
328
+
329
+ # Encode image
330
+ base64_image, error = self.encode_image_safely(image_path)
331
+ if error:
332
+ return None, f"Image processing failed: {error}"
333
+
334
+ try:
335
+ # Select prompt
336
+ if custom_prompt:
337
+ prompt = custom_prompt
338
+ else:
339
+ prompt = self.analysis_prompts.get(analysis_type, self.analysis_prompts["detailed"])
340
+
341
+ # Prepare request
342
+ headers = {
343
+ "Authorization": f"Bearer {self.sambanova_api_key}",
344
+ "Content-Type": "application/json"
345
+ }
346
+
347
+ payload = {
348
+ "model": "Llama-3.2-90B-Vision-Instruct",
349
+ "messages": [
350
+ {
351
+ "role": "user",
352
+ "content": [
353
+ {"type": "text", "text": prompt},
354
+ {
355
+ "type": "image_url",
356
+ "image_url": {
357
+ "url": f"data:image/jpeg;base64,{base64_image}"
358
+ }
359
+ }
360
+ ]
361
+ }
362
+ ],
363
+ "max_tokens": 2000,
364
+ "temperature": 0.1, # Low temperature for technical accuracy
365
+ "top_p": 0.9
366
+ }
367
+
368
+ print("📡 Sending request to SambaNova...")
369
+ response = requests.post(
370
+ self.sambanova_url,
371
+ headers=headers,
372
+ json=payload,
373
+ timeout=120 # Longer timeout for vision processing
374
+ )
375
+
376
+ print(f"📊 SambaNova response: HTTP {response.status_code}")
377
+
378
+ if response.status_code == 200:
379
+ result = response.json()
380
+
381
+ if "choices" in result and len(result["choices"]) > 0:
382
+ analysis = result["choices"][0]["message"]["content"]
383
+
384
+ # Validate response quality
385
+ is_valid, validation_error = self.validate_analysis_response(analysis, analysis_type)
386
+
387
+ if is_valid:
388
+ print("✅ SambaNova analysis validated successfully")
389
+ return {
390
+ "success": True,
391
+ "analysis": analysis,
392
+ "provider": "SambaNova",
393
+ "model": "Llama-3.2-90B-Vision-Instruct",
394
+ "analysis_type": analysis_type,
395
+ "timestamp": datetime.now().isoformat()
396
+ }, None
397
+ else:
398
+ print(f"❌ SambaNova validation failed: {validation_error}")
399
+ return None, f"SambaNova analysis validation failed: {validation_error}"
400
+ else:
401
+ return None, "No analysis content in SambaNova response"
402
+ else:
403
+ error_text = response.text
404
+ print(f"❌ SambaNova API error: {error_text}")
405
+ return None, f"SambaNova API error {response.status_code}: {error_text}"
406
+
407
+ except requests.exceptions.Timeout:
408
+ return None, "SambaNova request timeout - try again"
409
+ except requests.exceptions.RequestException as e:
410
+ return None, f"SambaNova request failed: {str(e)}"
411
+ except Exception as e:
412
+ return None, f"SambaNova analysis error: {str(e)}"
413
+
414
+ def analyze_with_openai(self, image_path, analysis_type="detailed", custom_prompt=None):
415
+ """
416
+ Analyze circuit image using OpenAI vision model
417
+
418
+ Args:
419
+ image_path: Path to image file
420
+ analysis_type: Type of analysis
421
+ custom_prompt: Custom analysis prompt
422
+
423
+ Returns:
424
+ tuple: (result_dict, error_message)
425
+ """
426
+ print("🔄 Starting OpenAI vision analysis...")
427
+
428
+ if not self.openai_api_key:
429
+ return None, "OpenAI API key not configured"
430
+
431
+ # Encode image
432
+ base64_image, error = self.encode_image_safely(image_path)
433
+ if error:
434
+ return None, f"Image processing failed: {error}"
435
+
436
+ try:
437
+ # Select prompt
438
+ if custom_prompt:
439
+ prompt = custom_prompt
440
+ else:
441
+ prompt = self.analysis_prompts.get(analysis_type, self.analysis_prompts["detailed"])
442
+
443
+ headers = {
444
+ "Content-Type": "application/json",
445
+ "Authorization": f"Bearer {self.openai_api_key}"
446
+ }
447
+
448
+ payload = {
449
+ "model": "gpt-4o",
450
+ "messages": [
451
+ {
452
+ "role": "user",
453
+ "content": [
454
+ {"type": "text", "text": prompt},
455
+ {
456
+ "type": "image_url",
457
+ "image_url": {
458
+ "url": f"data:image/jpeg;base64,{base64_image}",
459
+ "detail": "high"
460
+ }
461
+ }
462
+ ]
463
+ }
464
+ ],
465
+ "max_tokens": 2000,
466
+ "temperature": 0.1
467
+ }
468
+
469
+ print("📡 Sending request to OpenAI...")
470
+ response = requests.post(self.openai_vision_url, headers=headers, json=payload, timeout=90)
471
+
472
+ print(f"📊 OpenAI response: HTTP {response.status_code}")
473
+
474
+ if response.status_code == 200:
475
+ result = response.json()
476
+ analysis = result["choices"][0]["message"]["content"]
477
+
478
+ # Validate response
479
+ is_valid, validation_error = self.validate_analysis_response(analysis, analysis_type)
480
+
481
+ if is_valid:
482
+ print("✅ OpenAI analysis validated successfully")
483
+ return {
484
+ "success": True,
485
+ "analysis": analysis,
486
+ "provider": "OpenAI",
487
+ "model": "GPT-4o",
488
+ "analysis_type": analysis_type,
489
+ "timestamp": datetime.now().isoformat()
490
+ }, None
491
+ else:
492
+ print(f"❌ OpenAI validation failed: {validation_error}")
493
+ return None, f"OpenAI analysis validation failed: {validation_error}"
494
+ else:
495
+ return None, f"OpenAI API error {response.status_code}: {response.text}"
496
+
497
+ except Exception as e:
498
+ return None, f"OpenAI analysis error: {str(e)}"
499
+
500
+ def analyze_image(self, image_path, analysis_type="detailed", custom_prompt=None, preferred_provider=None):
501
+ """
502
+ Main image analysis function with multiple provider fallback
503
+
504
+ Args:
505
+ image_path: Path to image file
506
+ analysis_type: Type of analysis to perform
507
+ custom_prompt: Custom analysis prompt
508
+ preferred_provider: Preferred AI provider
509
+
510
+ Returns:
511
+ dict: Analysis result with success/failure information
512
+ """
513
+ if not image_path:
514
+ return {
515
+ "success": False,
516
+ "error": "No image provided",
517
+ "analysis": "Please upload an image to analyze."
518
+ }
519
+
520
+ print(f"🎯 Starting {analysis_type} image analysis...")
521
+
522
+ # Define provider order
523
+ if preferred_provider == "openai":
524
+ providers = [
525
+ ("OpenAI", self.analyze_with_openai),
526
+ ("SambaNova", self.analyze_with_sambanova)
527
+ ]
528
+ else:
529
+ providers = [
530
+ ("SambaNova", self.analyze_with_sambanova),
531
+ ("OpenAI", self.analyze_with_openai)
532
+ ]
533
+
534
+ # Try each provider
535
+ for provider_name, provider_func in providers:
536
+ print(f"🔄 Trying {provider_name}...")
537
+
538
+ result, error = provider_func(image_path, analysis_type, custom_prompt)
539
+
540
+ if result and result.get("success"):
541
+ print(f"✅ {provider_name} analysis successful!")
542
+ return result
543
+ else:
544
+ print(f"❌ {provider_name} failed: {error}")
545
+
546
+ # All providers failed
547
+ return {
548
+ "success": False,
549
+ "error": "All vision providers failed",
550
+ "analysis": f"""🔍 **Vision Analysis Failed**
551
+
552
+ **Problem:** All available vision AI models failed to analyze your image.
553
+
554
+ **Possible Issues:**
555
+ - Image format or quality problems
556
+ - API service temporarily unavailable
557
+ - Image too large or unclear
558
+ - Network connectivity issues
559
+
560
+ **Solutions:**
561
+ 1. **Try Different Format:** Convert PNG ↔ JPG
562
+ 2. **Improve Image Quality:** Ensure good lighting and focus
563
+ 3. **Reduce File Size:** Compress image if very large
564
+ 4. **Manual Description:** Describe your circuit below
565
+
566
+ **Manual Analysis:**
567
+ Tell me about your circuit:
568
+ - What components do you see?
569
+ - What is the circuit supposed to do?
570
+ - What specific problems are you experiencing?
571
+ - What improvements are you looking for?
572
+
573
+ I can provide targeted advice based on your description! 🛠️
574
+
575
+ **Example:** "I have an Arduino connected to an L298N motor driver and two DC motors. The motors should move forward when I press a button, but nothing happens."
576
+ """,
577
+ "provider": "None",
578
+ "model": "Fallback",
579
+ "analysis_type": analysis_type,
580
+ "timestamp": datetime.now().isoformat()
581
+ }
582
+
583
+ def batch_analyze_images(self, image_paths, analysis_type="detailed"):
584
+ """
585
+ Analyze multiple images in batch
586
+
587
+ Args:
588
+ image_paths: List of image paths
589
+ analysis_type: Type of analysis
590
+
591
+ Returns:
592
+ list: List of analysis results
593
+ """
594
+ results = []
595
+
596
+ for i, image_path in enumerate(image_paths):
597
+ print(f"🔄 Analyzing image {i+1}/{len(image_paths)}")
598
+
599
+ result = self.analyze_image(image_path, analysis_type)
600
+ results.append(result)
601
+
602
+ # Rate limiting between requests
603
+ if i < len(image_paths) - 1:
604
+ time.sleep(1)
605
+
606
+ return results
607
+
608
+ def get_analysis_summary(self, analysis_result):
609
+ """
610
+ Extract key information from analysis result
611
+
612
+ Args:
613
+ analysis_result: Result from analyze_image()
614
+
615
+ Returns:
616
+ dict: Summarized information
617
+ """
618
+ if not analysis_result.get("success"):
619
+ return {
620
+ "circuit_type": "unknown",
621
+ "components": [],
622
+ "issues": [],
623
+ "recommendations": []
624
+ }
625
+
626
+ analysis_text = analysis_result["analysis"].lower()
627
+
628
+ # Extract circuit type
629
+ circuit_types = {
630
+ "h_bridge": ["h-bridge", "motor driver", "motor control"],
631
+ "power_supply": ["power supply", "regulator", "voltage"],
632
+ "amplifier": ["amplifier", "amp", "audio"],
633
+ "sensor": ["sensor", "temperature", "humidity", "distance"],
634
+ "microcontroller": ["arduino", "esp32", "microcontroller"]
635
+ }
636
+
637
+ detected_type = "general"
638
+ for circuit_type, keywords in circuit_types.items():
639
+ if any(keyword in analysis_text for keyword in keywords):
640
+ detected_type = circuit_type
641
+ break
642
+
643
+ # Extract components (simple keyword search)
644
+ common_components = [
645
+ "arduino", "esp32", "resistor", "capacitor", "led", "transistor",
646
+ "diode", "ic", "motor", "sensor", "display", "battery"
647
+ ]
648
+
649
+ found_components = [comp for comp in common_components if comp in analysis_text]
650
+
651
+ return {
652
+ "circuit_type": detected_type,
653
+ "components": found_components,
654
+ "provider": analysis_result.get("provider", "unknown"),
655
+ "model": analysis_result.get("model", "unknown"),
656
+ "confidence": "high" if analysis_result.get("provider") == "SambaNova" else "medium"
657
+ }
658
+
659
+ # Test function
660
+ if __name__ == "__main__":
661
+ analyzer = AdvancedVisionAnalysis()
662
+
663
+ # Test with a sample analysis
664
+ print("🧪 Testing vision analysis module...")
665
+
666
+ # This would normally test with an actual image file
667
+ # result = analyzer.analyze_image("test_circuit.jpg", "detailed")
668
+ # print(json.dumps(result, indent=2))
669
+
670
+ print("✅ Vision analysis module loaded successfully")