Download app.py from netraai/Construction_Material_Classification: direct link, hf CLI and curl.
- Browser
- Download file 5.69 kB
-
https://huggingface.co/spaces/netraai/Construction_Material_Classification/resolve/main/app.py
- Command line
-
hf download hf://spaces/netraai/Construction_Material_Classification/app.py
-
curl -L -o app.py https://huggingface.co/spaces/netraai/Construction_Material_Classification/resolve/main/app.py
5.69 kB
| """ | |
| Netra AI - Public Interface | |
| Calls protected backend space for classification | |
| """ | |
| import gradio as gr | |
| from gradio_client import Client | |
| from huggingface_hub import login | |
| import os | |
| # Global backend client | |
| backend = None | |
| def get_backend(): | |
| """Lazy initialization of backend client""" | |
| global backend | |
| if backend is None: | |
| HF_TOKEN = os.getenv("HF_TOKEN") | |
| if HF_TOKEN: | |
| login(token=HF_TOKEN) | |
| backend = Client("rg321/Construction_Material_Classification") | |
| return backend | |
| def classify_material(image): | |
| """Proxy function that calls protected backend""" | |
| if image is None: | |
| return "Please upload an image", "", "" | |
| try: | |
| import tempfile | |
| from PIL import Image as PILImage | |
| from gradio_client import handle_file | |
| print(f"π€ Calling backend API with image type: {type(image)}") | |
| # Convert PIL Image to temp file for gradio_client | |
| if isinstance(image, PILImage.Image): | |
| with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg', mode='wb') as tmp: | |
| image.save(tmp, 'JPEG') | |
| image_path = tmp.name | |
| else: | |
| image_path = image | |
| print(f"π€ Sending file: {image_path}") | |
| # Call protected space API with properly formatted file | |
| client = get_backend() | |
| result = client.predict( | |
| image=handle_file(image_path), | |
| api_name="/classify_material" | |
| ) | |
| print(f"π₯ Backend response: {result}") | |
| # result is tuple: (classification, confidence, reasoning) | |
| return result[0], result[1], result[2] | |
| except Exception as e: | |
| import traceback | |
| error_msg = str(e) | |
| full_error = traceback.format_exc() | |
| print(f"β Error: {full_error}") | |
| return f"β Classification Error", "", f"Error: {error_msg}" | |
| # Custom CSS (same as original) | |
| 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; | |
| } | |
| """ | |
| # Build Gradio interface | |
| 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> | |
| """ | |
| ) | |
| # Connect button | |
| classify_btn.click( | |
| fn=classify_material, | |
| inputs=[image_input], | |
| outputs=[result_output, confidence_output, reasoning_output] | |
| ) | |
| # Launch | |
| if __name__ == "__main__": | |
| demo.launch(show_error=True) | |