rg321 commited on
Commit
14889d7
Β·
verified Β·
1 Parent(s): a87875a

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +232 -0
app.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Netra AI - Construction Material Classifier
3
+ MVP Demo using Gemini Vision API
4
+ """
5
+
6
+ import gradio as gr
7
+ import google.generativeai as genai
8
+ import os
9
+ from PIL import Image
10
+ import base64
11
+ from io import BytesIO
12
+
13
+ # Material classification prompt
14
+ CLASSIFICATION_PROMPT = """
15
+ You are a construction material classifier for Netra AI. Classify this image into ONE of these 4 classes:
16
+
17
+ 1. **Reet (Sand)**: All grades of sand - from fine powdery sand to coarse gritty sand. Shows smooth to granular texture.
18
+
19
+ 2. **12mm VSI**: Uniform, small, cubical "clean" stones. Very consistent size (~10-15mm). Manufactured aggregate with sharp edges.
20
+
21
+ 3. **Stone**: Large, irregular boulders. Significant size variation, deep voids between rocks. Raw, unprocessed appearance.
22
+
23
+ 4. **GSB (Graded Stone Base)**: Mixed-size material with rocks, gravel, grit AND fine dust/sand filling gaps. Key indicator is fine dust matrix.
24
+
25
+ Respond in this exact format:
26
+ CLASS: [class name]
27
+ CONFIDENCE: [High/Medium/Low]
28
+ REASONING: [One sentence explanation of visual features that led to this classification]
29
+ """
30
+
31
+
32
+ def classify_material(image):
33
+ """Classify construction material from image using Netra AI"""
34
+
35
+ if image is None:
36
+ return "Please upload an image", "", ""
37
+
38
+ # Get API key from environment
39
+ api_key = os.getenv("GOOGLE_API_KEY", "")
40
+ if not api_key:
41
+ return "❌ System Error", "", "AI service not configured. Please contact support."
42
+
43
+ try:
44
+ # Configure Gemini
45
+ genai.configure(api_key=api_key)
46
+ model = genai.GenerativeModel('gemini-2.5-flash')
47
+
48
+ # Convert to PIL Image if needed
49
+ if not isinstance(image, Image.Image):
50
+ image = Image.fromarray(image)
51
+
52
+ # Generate classification
53
+ response = model.generate_content([CLASSIFICATION_PROMPT, image])
54
+ result_text = response.text.strip()
55
+
56
+ # Parse response
57
+ lines = result_text.split('\n')
58
+ class_name = ""
59
+ confidence = ""
60
+ reasoning = ""
61
+
62
+ for line in lines:
63
+ if line.startswith("CLASS:"):
64
+ class_name = line.replace("CLASS:", "").strip()
65
+ elif line.startswith("CONFIDENCE:"):
66
+ confidence = line.replace("CONFIDENCE:", "").strip()
67
+ elif line.startswith("REASONING:"):
68
+ reasoning = line.replace("REASONING:", "").strip()
69
+
70
+ # Format output
71
+ if class_name:
72
+ result = f"βœ… RESULT:\n\n{class_name}"
73
+ else:
74
+ result = "⏳ AWAITING CLASSIFICATION"
75
+
76
+ confidence_display = f"Confidence: {confidence}" if confidence else ""
77
+ reasoning_display = f"πŸ’‘ **Analysis:** {reasoning}" if reasoning else result_text
78
+
79
+ return result, confidence_display, reasoning_display
80
+
81
+ except Exception as e:
82
+ error_msg = str(e)
83
+ if "API_KEY_INVALID" in error_msg or "401" in error_msg:
84
+ return "❌ Invalid API Key", "", "Please check your Gemini API key"
85
+ elif "quota" in error_msg.lower():
86
+ return "❌ API Quota Exceeded", "", "Your API key has exceeded its quota"
87
+ else:
88
+ return f"❌ Error: {error_msg[:100]}", "", "Please try again"
89
+
90
+
91
+ # Custom CSS
92
+ custom_css = """
93
+ #header {
94
+ text-align: center;
95
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
96
+ padding: 20px;
97
+ border-radius: 10px;
98
+ color: white;
99
+ }
100
+ #result {
101
+ font-size: 72px;
102
+ font-weight: 900;
103
+ text-align: center;
104
+ padding: 50px 30px;
105
+ border-radius: 20px;
106
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
107
+ color: white;
108
+ margin-bottom: 25px;
109
+ box-shadow: 0 8px 16px rgba(0,0,0,0.2);
110
+ text-transform: uppercase;
111
+ letter-spacing: 2px;
112
+ line-height: 1.2;
113
+ }
114
+ #confidence {
115
+ font-size: 24px;
116
+ font-weight: 600;
117
+ text-align: center;
118
+ padding: 15px;
119
+ background: #f0f9ff;
120
+ border-radius: 10px;
121
+ margin-bottom: 20px;
122
+ }
123
+ #reasoning {
124
+ font-size: 14px;
125
+ text-align: left;
126
+ padding: 15px;
127
+ background: #f9fafb;
128
+ border-radius: 8px;
129
+ margin-bottom: 20px;
130
+ color: #4b5563;
131
+ }
132
+ #about {
133
+ font-size: 13px;
134
+ color: #6b7280;
135
+ padding-top: 20px;
136
+ border-top: 1px solid #e5e7eb;
137
+ }
138
+ """
139
+
140
+ # Build Gradio interface
141
+ with gr.Blocks(css=custom_css, title="Netra AI - Material Classifier") as demo:
142
+
143
+ gr.Markdown(
144
+ """
145
+ <div id="header">
146
+ <h1>πŸ—οΈ Netra AI - Construction Material Classifier</h1>
147
+ <p>AI-powered material identification for construction sites</p>
148
+ </div>
149
+ """,
150
+ elem_id="header"
151
+ )
152
+
153
+ with gr.Row():
154
+ with gr.Column(scale=1):
155
+ gr.Markdown("### πŸ“Έ Upload Material Image")
156
+ image_input = gr.Image(
157
+ type="pil",
158
+ label="Construction Material Photo",
159
+ height=400
160
+ )
161
+
162
+ classify_btn = gr.Button("πŸš€ Classify Material", variant="primary", size="lg")
163
+
164
+ gr.Markdown(
165
+ """
166
+ **Supported Materials:**
167
+ - πŸ–οΈ Reet (Sand)
168
+ - πŸ”· 12mm VSI (Uniform Aggregate)
169
+ - πŸͺ¨ Stone (Large Boulders)
170
+ - πŸ—οΈ GSB (Mixed Graded Base)
171
+ """
172
+ )
173
+
174
+ with gr.Column(scale=1):
175
+ result_output = gr.Markdown("", elem_id="result")
176
+ confidence_output = gr.Markdown("", elem_id="confidence")
177
+ reasoning_output = gr.Markdown("", elem_id="reasoning")
178
+
179
+ gr.Markdown(
180
+ """
181
+ <div id="about">
182
+
183
+ ### πŸ“Š About This Demo
184
+
185
+ This is a proof-of-concept for **Netra AI's** automated material classification system.
186
+
187
+ **Technology:**
188
+ - Vision AI for real-time material identification
189
+ - Prevents grade fraud at construction sites
190
+ - Automates dispatch logging
191
+
192
+ **Use Cases:**
193
+ - Gate monitoring at crusher plants
194
+ - Dispatch verification
195
+ - Quality control
196
+
197
+ ---
198
+ **Netra AI** - *Making every tonne count.*
199
+
200
+ For commercial inquiries: [Contact Us](mailto:contact@netraai.com)
201
+
202
+ </div>
203
+ """
204
+ )
205
+
206
+ # Example images
207
+ gr.Markdown("### πŸ“· Try These Sample Images")
208
+ gr.Examples(
209
+ examples=[
210
+ ["sanity_test_dataset/12mm_VSI_01.jpeg"],
211
+ ["sanity_test_dataset/Reet_01_fine.jpeg"],
212
+ ["sanity_test_dataset/Stone_01.jpeg"],
213
+ ["sanity_test_dataset/GSB_01.jpeg"],
214
+ ],
215
+ inputs=image_input,
216
+ label="Sample Materials"
217
+ )
218
+
219
+ # Connect button
220
+ classify_btn.click(
221
+ fn=classify_material,
222
+ inputs=[image_input],
223
+ outputs=[result_output, confidence_output, reasoning_output]
224
+ )
225
+
226
+ # Launch
227
+ if __name__ == "__main__":
228
+ demo.launch(
229
+ server_name="0.0.0.0",
230
+ server_port=7860,
231
+ share=True
232
+ )