| """ |
| Netra AI - Construction Material Classifier |
| MVP Demo using Claude Vision API |
| """ |
|
|
| import gradio as gr |
| import anthropic |
| import os |
| from PIL import Image |
| import base64 |
| from io import BytesIO |
|
|
| |
| CLASSIFICATION_PROMPT = """ |
| You are a construction material classifier for Netra AI. Classify this image into ONE of these 4 classes: |
| |
| 1. **Reet (Sand)**: All grades of sand - from fine powdery sand to coarse gritty sand. Shows smooth to granular texture. |
| |
| 2. **12mm VSI**: Uniform, small, cubical "clean" stones. Very consistent size (~10-15mm). Manufactured aggregate with sharp edges. |
| |
| 3. **Stone**: Large, irregular boulders. Significant size variation, deep voids between rocks. Raw, unprocessed appearance. |
| |
| 4. **GSB (Graded Stone Base)**: Mixed-size material with rocks, gravel, grit AND fine dust/sand filling gaps. Key indicator is fine dust matrix. |
| |
| Respond in this exact format: |
| CLASS: [class name] |
| CONFIDENCE: [High/Medium/Low] |
| REASONING: [One sentence explanation of visual features that led to this classification] |
| """ |
|
|
|
|
| def classify_material(image): |
| """Classify construction material from image using Netra AI""" |
|
|
| if image is None: |
| return "Please upload an image", "", "" |
|
|
| |
| api_key = os.getenv("ANTHROPIC_API_KEY", "") |
| if not api_key: |
| return "β System Error", "", "AI service not configured. Please contact support." |
|
|
| try: |
| |
| client = anthropic.Anthropic(api_key=api_key) |
|
|
| |
| if not isinstance(image, Image.Image): |
| image = Image.fromarray(image) |
|
|
| |
| buffered = BytesIO() |
| image.save(buffered, format="JPEG") |
| image_data = base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
| |
| response = client.messages.create( |
| model="claude-opus-4-6", |
| max_tokens=150, |
| messages=[ |
| { |
| "role": "user", |
| "content": [ |
| { |
| "type": "image", |
| "source": { |
| "type": "base64", |
| "media_type": "image/jpeg", |
| "data": image_data, |
| }, |
| }, |
| {"type": "text", "text": CLASSIFICATION_PROMPT} |
| ], |
| } |
| ], |
| ) |
| result_text = response.content[0].text.strip() |
|
|
| |
| lines = result_text.split('\n') |
| class_name = "" |
| confidence = "" |
| reasoning = "" |
|
|
| for line in lines: |
| if line.startswith("CLASS:"): |
| class_name = line.replace("CLASS:", "").strip() |
| elif line.startswith("CONFIDENCE:"): |
| confidence = line.replace("CONFIDENCE:", "").strip() |
| elif line.startswith("REASONING:"): |
| reasoning = line.replace("REASONING:", "").strip() |
|
|
| |
| if class_name: |
| result = f"β
RESULT:\n\n{class_name}" |
| else: |
| result = "β³ AWAITING CLASSIFICATION" |
|
|
| confidence_display = f"Confidence: {confidence}" if confidence else "" |
| reasoning_display = f"π‘ **Analysis:** {reasoning}" if reasoning else result_text |
|
|
| return result, confidence_display, reasoning_display |
|
|
| except Exception as e: |
| error_msg = str(e) |
| if "API_KEY_INVALID" in error_msg or "401" in error_msg: |
| return "β Invalid API Key", "", "Please check your Gemini API key" |
| elif "quota" in error_msg.lower(): |
| return "β API Quota Exceeded", "", "Your API key has exceeded its quota" |
| else: |
| return f"β Error: {error_msg[:100]}", "", "Please try again" |
|
|
|
|
| |
| custom_css = """ |
| #header { |
| text-align: center; |
| background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); |
| padding: 20px; |
| border-radius: 10px; |
| color: white; |
| } |
| #result { |
| font-size: 72px; |
| font-weight: 900; |
| text-align: center; |
| padding: 50px 30px; |
| border-radius: 20px; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| color: white; |
| margin-bottom: 25px; |
| box-shadow: 0 8px 16px rgba(0,0,0,0.2); |
| text-transform: uppercase; |
| letter-spacing: 2px; |
| line-height: 1.2; |
| } |
| #confidence { |
| font-size: 24px; |
| font-weight: 600; |
| text-align: center; |
| padding: 15px; |
| background: #f0f9ff; |
| border-radius: 10px; |
| margin-bottom: 20px; |
| } |
| #reasoning { |
| font-size: 14px; |
| text-align: left; |
| padding: 15px; |
| background: #f9fafb; |
| border-radius: 8px; |
| margin-bottom: 20px; |
| color: #4b5563; |
| } |
| #about { |
| font-size: 13px; |
| color: #6b7280; |
| padding-top: 20px; |
| border-top: 1px solid #e5e7eb; |
| } |
| """ |
|
|
| |
| with gr.Blocks(css=custom_css, title="Netra AI - Material Classifier") as demo: |
|
|
| gr.Markdown( |
| """ |
| <div id="header"> |
| <h1>ποΈ Netra AI - Construction Material Classifier</h1> |
| <p>AI-powered material identification for construction sites</p> |
| </div> |
| """, |
| elem_id="header" |
| ) |
|
|
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.Markdown("### πΈ Upload Material Image") |
| image_input = gr.Image( |
| type="pil", |
| label="Construction Material Photo", |
| height=400 |
| ) |
|
|
| classify_btn = gr.Button("π Classify Material", variant="primary", size="lg") |
|
|
| gr.Markdown( |
| """ |
| **Supported Materials:** |
| - ποΈ Reet (Sand) |
| - π· 12mm VSI (Uniform Aggregate) |
| - πͺ¨ Stone (Large Boulders) |
| - ποΈ GSB (Mixed Graded Base) |
| """ |
| ) |
|
|
| gr.Markdown("### π· Try Sample Images") |
| gr.Examples( |
| examples=[ |
| ["sanity_test_dataset/12mm_VSI_01.jpeg"], |
| ["sanity_test_dataset/Reet_01_fine.jpeg"], |
| ["sanity_test_dataset/Stone_01.jpeg"], |
| ["sanity_test_dataset/GSB_01.jpeg"], |
| ], |
| inputs=image_input, |
| label="" |
| ) |
|
|
| with gr.Column(scale=1): |
| result_output = gr.Markdown("", elem_id="result") |
| confidence_output = gr.Markdown("", elem_id="confidence") |
| reasoning_output = gr.Markdown("", elem_id="reasoning") |
|
|
| gr.Markdown( |
| """ |
| <div id="about"> |
| |
| ### π About This Demo |
| |
| This is a proof-of-concept for **Netra AI's** automated material classification system. |
| |
| **Technology:** |
| - Vision AI for real-time material identification |
| - Prevents grade fraud at construction sites |
| - Automates dispatch logging |
| |
| **Use Cases:** |
| - Gate monitoring at crusher plants |
| - Dispatch verification |
| - Quality control |
| |
| --- |
| **Netra AI** - *Making every tonne count.* |
| |
| For commercial inquiries: [Contact Us](mailto:guptaraghu321@gmail.com) |
| |
| </div> |
| """ |
| ) |
|
|
|
|
| |
| classify_btn.click( |
| fn=classify_material, |
| inputs=[image_input], |
| outputs=[result_output, confidence_output, reasoning_output] |
| ) |
|
|
| |
| if __name__ == "__main__": |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=True |
| ) |
|
|