priyesh17 commited on
Commit
af2d5f9
·
verified ·
1 Parent(s): b9f5a6d

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +560 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import cv2
3
+ import requests
4
+ import tempfile
5
+ from ultralytics import YOLO
6
+ from PIL import Image
7
+ import numpy as np
8
+ import os
9
+
10
+ # Hugging Face API Key
11
+ HF_API_KEY = os.getenv("HF_API_KEY")
12
+ API_URL = "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2"
13
+ headers = {"Authorization": f"Bearer {HF_API_KEY}"}
14
+
15
+ final_birds = None
16
+
17
+ # Load YOLO Model
18
+ model = YOLO('best_v11-60epochs.pt')
19
+ bird_name = None
20
+ # Styling
21
+ st.markdown(
22
+ """
23
+ <style>
24
+ .stApp {
25
+ color: var(--text-color);
26
+ }
27
+
28
+ .title {
29
+ font-size: 36px;
30
+ font-weight: bold;
31
+ text-align: center;
32
+ color: #4B9FE1;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ gap: 10px;
37
+ margin-bottom: 5px;
38
+ }
39
+
40
+ .subtext {
41
+ font-size: 16px;
42
+ text-align: center;
43
+ opacity: 0.8;
44
+ margin-bottom: 10px;
45
+ }
46
+
47
+ .bird-count {
48
+ font-size: 22px;
49
+ font-weight: bold;
50
+ color: #FF7F50;
51
+ text-align: center;
52
+ margin: 20px 0;
53
+ }
54
+
55
+ .info-box {
56
+ background-color: rgba(255, 255, 255, 0.05);
57
+ padding: 20px;
58
+ border-radius: 10px;
59
+ border: 1px solid rgba(255, 255, 255, 0.1);
60
+ margin: 15px 0;
61
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
62
+ }
63
+
64
+ .bird-info {
65
+ margin: 8px 0;
66
+ padding: 8px;
67
+ background-color: rgba(255, 255, 255, 0.05);
68
+ border-radius: 5px;
69
+ color: inherit;
70
+ }
71
+
72
+ .info-label {
73
+ font-weight: bold;
74
+ color: #4B9FE1;
75
+ margin-right: 10px;
76
+ }
77
+
78
+ .bird-name {
79
+ color: #4B9FE1;
80
+ font-size: 1.5em;
81
+ margin-bottom: 15px;
82
+ }
83
+ </style>
84
+ """,
85
+ unsafe_allow_html=True
86
+ )
87
+
88
+ # App Header
89
+ st.markdown('<p class="title">🦜 Birdscribe AI</p><p class="subtext">Detect birds in images and videos using AI-powered vision.</p>', unsafe_allow_html=True)
90
+
91
+ def extract_clean_info(text):
92
+ """Extract and clean bird information from LLM response."""
93
+ # Define the expected fields
94
+ fields = [
95
+ "Scientific Name",
96
+ "Common Names",
97
+ "Geographical Distribution",
98
+ "Size",
99
+ "Weight",
100
+ "Feet Type",
101
+ "Lifespan"
102
+ ]
103
+
104
+ # Initialize dictionary to store the information
105
+ info_dict = {}
106
+
107
+ # Process each line
108
+ lines = text.split('\n')
109
+
110
+ for line in lines:
111
+ line = line.strip()
112
+ # Skip empty lines
113
+ if not line:
114
+ continue
115
+
116
+ # Check if this line contains field information
117
+ for field in fields:
118
+ if field.lower() in line.lower() and ":" in line:
119
+ parts = line.split(':', 1)
120
+ if len(parts) > 1:
121
+ info_dict[field] = parts[1].strip()
122
+ break
123
+ # Handle numbered format: "1. Scientific Name: Icterus parisorum"
124
+ elif line.startswith(f"{fields.index(field) + 1}.") and field.lower() in line.lower() and ":" in line:
125
+ parts = line.split(':', 1)
126
+ if len(parts) > 1:
127
+ info_dict[field] = parts[1].strip()
128
+ break
129
+
130
+ # Return formatted string with collected information
131
+ result = []
132
+ for field in fields:
133
+ if field in info_dict and info_dict[field]:
134
+ result.append(f"{field}: {info_dict[field]}")
135
+
136
+ return '\n'.join(result)
137
+
138
+ def query_bird_info(bird_name):
139
+ """Query bird information from Mistral API with clear formatting instructions."""
140
+ prompt = f"""Provide detailed information about the bird species '{bird_name}' using the exact format below:
141
+
142
+ Scientific Name: [scientific name]
143
+ Common Names: [common names]
144
+ Geographical Distribution: [distribution info]
145
+ Size: [size measurements]
146
+ Weight: [weight range]
147
+ Feet Type: [feet description]
148
+ Lifespan: [lifespan info]
149
+
150
+ Important: Include the labels exactly as shown above, followed by a colon and the information.
151
+ """
152
+
153
+ try:
154
+ response = requests.post(API_URL, headers=headers, json={"inputs": prompt})
155
+ if response.status_code != 200:
156
+ st.error(f"API Error: {response.status_code}")
157
+ return None
158
+
159
+ result = response.json()[0]["generated_text"]
160
+ return extract_clean_info(result)
161
+ except Exception as e:
162
+ st.error(f"Error querying bird information: {str(e)}")
163
+ return None
164
+
165
+ def format_bird_info(info_text):
166
+ """Format bird information for HTML display."""
167
+ if not info_text:
168
+ return "<div class='bird-info'>Information not available</div>"
169
+
170
+ formatted_html = ""
171
+ for line in info_text.split('\n'):
172
+ if ':' in line:
173
+ parts = line.split(':', 1)
174
+ if len(parts) == 2:
175
+ label, value = parts
176
+ formatted_html += f"<div class='bird-info'><span class='info-label'>{label.strip()}</span>{value.strip()}</div>"
177
+
178
+ return formatted_html
179
+
180
+ # File upload section
181
+ upload_type = st.selectbox(
182
+ "Choose file type",
183
+ ["Image", "Video"],
184
+ key="file_type"
185
+ )
186
+
187
+ # Set allowed file types
188
+ if upload_type == "Image":
189
+ allowed_types = ["jpg", "jpeg", "png"]
190
+ upload_message = "Upload an image (JPG, JPEG, PNG)"
191
+ else:
192
+ allowed_types = ["mp4", "avi", "mpeg4"]
193
+ upload_message = "Upload a video (MP4, AVI, MPEG4)"
194
+
195
+ uploaded_file = st.file_uploader(upload_message, type=allowed_types)
196
+
197
+ if uploaded_file is not None:
198
+ bird_info = {}
199
+
200
+ if upload_type == "Image":
201
+ # Process image
202
+ image = Image.open(uploaded_file)
203
+ if image.mode == 'RGBA':
204
+ image = image.convert('RGB')
205
+
206
+ st.image(image, caption="Uploaded Image", use_container_width=True)
207
+
208
+ # Convert PIL to Numpy array for YOLO
209
+ image_np = np.array(image)
210
+ if len(image_np.shape) == 2:
211
+ image_np = cv2.cvtColor(image_np, cv2.COLOR_GRAY2RGB)
212
+ elif image_np.shape[-1] == 4:
213
+ image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2RGB)
214
+
215
+ # Run detection
216
+ results = model(image_np)
217
+ annotated_frame = results[0].plot()
218
+
219
+ # Get detected bird names
220
+ detected_names = []
221
+ if results[0].boxes:
222
+ for box in results[0].boxes:
223
+ class_id = int(box.cls)
224
+ if class_id in model.names:
225
+ detected_names.append(model.names[class_id])
226
+
227
+ if not detected_names:
228
+ detected_names = ["No birds detected"]
229
+
230
+ # Display annotated image
231
+ st.image(annotated_frame, caption="Detected Objects", use_container_width=True)
232
+
233
+ # Display detected birds count
234
+ st.markdown(f'<p class="bird-count">Detected Bird(s): {", ".join(detected_names)}</p>', unsafe_allow_html=True)
235
+
236
+ # Get and display bird information
237
+ if "No birds detected" not in detected_names:
238
+ with st.spinner("Retrieving bird information..."):
239
+ for bird_name in detected_names:
240
+ if bird_name not in bird_info:
241
+ info = query_bird_info(bird_name)
242
+ if info:
243
+ st.markdown(
244
+ f'<div class="info-box">'
245
+ f'<h3 class="bird-name">{bird_name}</h3>'
246
+ f'{format_bird_info(info)}'
247
+ f'</div>',
248
+ unsafe_allow_html=True
249
+ )
250
+ else:
251
+ st.warning(f"Could not retrieve information for {bird_name}")
252
+
253
+ else:
254
+ # Process video
255
+ with st.spinner("Processing video..."):
256
+ tfile = tempfile.NamedTemporaryFile(delete=False)
257
+ tfile.write(uploaded_file.read())
258
+
259
+ cap = cv2.VideoCapture(tfile.name)
260
+ stframe = st.empty()
261
+ detected_birds = set()
262
+ bird_info_dict = {}
263
+
264
+ # Display detected birds list at the top (dynamic updating)
265
+ birds_placeholder = st.empty()
266
+
267
+ # Video processing progress bar
268
+ progress_bar = st.progress(0)
269
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
270
+ current_frame = 0
271
+
272
+ while cap.isOpened():
273
+ ret, frame = cap.read()
274
+ if not ret:
275
+ break
276
+
277
+ # Update progress
278
+ current_frame += 1
279
+ progress_value = min(current_frame / total_frames, 1.0)
280
+ progress_bar.progress(progress_value)
281
+
282
+ # Only process every nth frame for efficiency
283
+ if current_frame % 10 == 0: # Process every 10th frame
284
+ results = model(frame)
285
+ annotated_frame = results[0].plot()
286
+ annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
287
+
288
+ # Display the processed frame
289
+ stframe.image(annotated_frame, caption="Processing Video...", use_container_width=True)
290
+
291
+ # Detect new birds in this frame
292
+ new_birds = set()
293
+ if results[0].boxes:
294
+ for box in results[0].boxes:
295
+ class_id = int(box.cls)
296
+ if class_id in model.names:
297
+ bird_name = model.names[class_id]
298
+ if bird_name not in detected_birds:
299
+ detected_birds.add(bird_name)
300
+ new_birds.add(bird_name) # Track newly detected birds
301
+
302
+ # Update bird list dynamically
303
+ birds_placeholder.markdown(f'<p class="bird-count">Detected Bird(s): {", ".join(detected_birds)}</p>',
304
+ unsafe_allow_html=True)
305
+
306
+ # Fetch & display info for newly detected birds immediately
307
+ for bird_name in new_birds:
308
+ info = query_bird_info(bird_name)
309
+ bird_info_dict[bird_name] = info
310
+
311
+ if info:
312
+ st.markdown(
313
+ f'<div class="info-box">'
314
+ f'<h3 class="bird-name">{bird_name}</h3>'
315
+ f'{format_bird_info(info)}'
316
+ f'</div>',
317
+ unsafe_allow_html=True
318
+ )
319
+ else:
320
+ st.warning(f"Could not retrieve information for {bird_name}")
321
+
322
+ cap.release()
323
+ progress_bar.empty()
324
+
325
+
326
+ class_type = st.selectbox(
327
+ "If you want to know more about a specific bird, select the name of bird:",
328
+ [None,'Black footed Albatros',
329
+ 'Laysan Albatros',
330
+ 'Sooty Albatros',
331
+ 'Groove billed Ani',
332
+ 'Crested Aukle',
333
+ 'Least Aukle',
334
+ 'Parakeet Aukle',
335
+ 'Rhinoceros Aukle',
336
+ 'Brewer Blackbird',
337
+ 'Red winged Blackbird',
338
+ 'Rusty Blackbird',
339
+ 'Yellow headed Blackbird',
340
+ 'Bobolink',
341
+ 'Indigo Bunting',
342
+ 'Lazuli Bunting',
343
+ 'Painted Bunting',
344
+ 'Cardinal',
345
+ 'Spotted Catbird',
346
+ 'Gray Catbird',
347
+ 'Yellow breasted Chat',
348
+ 'Eastern Towhee',
349
+ 'Chuck will Widow',
350
+ 'Brandt Cormorant',
351
+ 'Red faced Cormorant',
352
+ 'Pelagic Cormorant',
353
+ 'Bronzed Cowbird',
354
+ 'Shiny Cowbird',
355
+ 'Brown Creeper',
356
+ 'American Crow',
357
+ 'Fish Crow',
358
+ 'Black billed Cuckoo',
359
+ 'Mangrove Cuckoo',
360
+ 'Yellow billed Cuckoo',
361
+ 'Gray crowned Rosy Finch',
362
+ 'Purple Finch',
363
+ 'Northern Flicker',
364
+ 'Acadian Flycatcher',
365
+ 'Great Crested Flycatcher',
366
+ 'Least Flycatcher',
367
+ 'Olive sided Flycatcher',
368
+ 'Scissor tailed Flycatcher',
369
+ 'Vermilion Flycatcher',
370
+ 'Yellow bellied Flycatcher',
371
+ 'Frigatebird',
372
+ 'Northern Fulmar',
373
+ 'Gadwall',
374
+ 'American Goldfinch',
375
+ 'European Goldfinch',
376
+ 'Boat tailed Grackle',
377
+ 'Eared Grebe',
378
+ 'Horned Grebe',
379
+ 'Pied billed Grebe',
380
+ 'Western Grebe',
381
+ 'Blue Grosbeak',
382
+ 'Evening Grosbeak',
383
+ 'Pine Grosbeak',
384
+ 'Rose breasted Grosbeak',
385
+ 'Pigeon Guillemot',
386
+ 'California Gull',
387
+ 'Glaucous winged Gull',
388
+ 'Heermann Gull',
389
+ 'Herring Gull',
390
+ 'Ivory Gull',
391
+ 'Ring billed Gull',
392
+ 'Slaty backed Gull',
393
+ 'Western Gull',
394
+ 'Anna Hummingbird',
395
+ 'Ruby throated Hummingbird',
396
+ 'Rufous Hummingbird',
397
+ 'Green Violetear',
398
+ 'Long tailed Jaeger',
399
+ 'Pomarine Jaeger',
400
+ 'Blue Jay',
401
+ 'Florida Jay',
402
+ 'Green Jay',
403
+ 'Dark eyed Junco',
404
+ 'Tropical Kingbird',
405
+ 'Gray Kingbird',
406
+ 'Belted Kingfisher',
407
+ 'Green Kingfisher',
408
+ 'Pied Kingfisher',
409
+ 'Ringed Kingfisher',
410
+ 'White breasted Kingfisher',
411
+ 'Red legged Kittiwake',
412
+ 'Horned Lark',
413
+ 'Pacific Loon',
414
+ 'Mallard',
415
+ 'Western Meadowlark',
416
+ 'Hooded Merganser',
417
+ 'Red breasted Merganser',
418
+ 'Mockingbird',
419
+ 'Nighthawk',
420
+ 'Clark Nutcracker',
421
+ 'White breasted Nuthatch',
422
+ 'Baltimore Oriole',
423
+ 'Hooded Oriole',
424
+ 'Orchard Oriole',
425
+ 'Scott Oriole',
426
+ 'Ovenbird',
427
+ 'Brown Pelican',
428
+ 'White Pelican',
429
+ 'Western Wood Pewee',
430
+ 'Sayornis',
431
+ 'American Pipit',
432
+ 'Whip poor Will',
433
+ 'Horned Puffin',
434
+ 'Common Raven',
435
+ 'White necked Raven',
436
+ 'American Redstart',
437
+ 'Geococcyx',
438
+ 'Loggerhead Shrike',
439
+ 'Great Grey Shrike',
440
+ 'Baird Sparrow',
441
+ 'Black throated Sparrow',
442
+ 'Brewer Sparrow',
443
+ 'Chipping Sparrow',
444
+ 'Clay colored Sparrow',
445
+ 'House Sparrow',
446
+ 'Field Sparrow',
447
+ 'Fox Sparrow',
448
+ 'Grasshopper Sparrow',
449
+ 'Harris Sparrow',
450
+ 'Henslow Sparrow',
451
+ 'Le Conte Sparrow',
452
+ 'Lincoln Sparrow',
453
+ 'Nelson Sharp tailed Sparrow',
454
+ 'Savannah Sparrow',
455
+ 'Seaside Sparrow',
456
+ 'Song Sparrow',
457
+ 'Tree Sparrow',
458
+ 'Vesper Sparrow',
459
+ 'White crowned Sparrow',
460
+ 'White throated Sparrow',
461
+ 'Cape Glossy Starling',
462
+ 'Bank Swallow',
463
+ 'Barn Swallow',
464
+ 'Cliff Swallow',
465
+ 'Tree Swallow',
466
+ 'Scarlet Tanager',
467
+ 'Summer Tanager',
468
+ 'Artic Tern',
469
+ 'Black Tern',
470
+ 'Caspian Tern',
471
+ 'Common Tern',
472
+ 'Elegant Tern',
473
+ 'Forsters Tern',
474
+ 'Least Tern',
475
+ 'Green tailed Towhee',
476
+ 'Brown Thrasher',
477
+ 'Sage Thrasher',
478
+ 'Black capped Vireo',
479
+ 'Blue headed Vireo',
480
+ 'Philadelphia Vireo',
481
+ 'Red eyed Vireo',
482
+ 'Warbling Vireo',
483
+ 'White eyed Vireo',
484
+ 'Yellow throated Vireo',
485
+ 'Bay breasted Warbler',
486
+ 'Black and white Warbler',
487
+ 'Black throated Blue Warbler',
488
+ 'Blue winged Warbler',
489
+ 'Canada Warbler',
490
+ 'Cape May Warbler',
491
+ 'Cerulean Warbler',
492
+ 'Chestnut sided Warbler',
493
+ 'Golden winged Warbler',
494
+ 'Hooded Warbler',
495
+ 'Kentucky Warbler',
496
+ 'Magnolia Warbler',
497
+ 'Mourning Warbler',
498
+ 'Myrtle Warbler',
499
+ 'Nashville Warbler',
500
+ 'Orange crowned Warbler',
501
+ 'Palm Warbler',
502
+ 'Pine Warbler',
503
+ 'Prairie Warbler',
504
+ 'Prothonotary Warbler',
505
+ 'Swainson Warbler',
506
+ 'Tennessee Warbler',
507
+ 'Wilson Warbler',
508
+ 'Worm eating Warbler',
509
+ 'Yellow Warbler',
510
+ 'Northern Waterthrush',
511
+ 'Louisiana Waterthrush',
512
+ 'Bohemian Waxwing',
513
+ 'Cedar Waxwing',
514
+ 'American Three toed Woodpecker',
515
+ 'Pileated Woodpecker',
516
+ 'Red bellied Woodpecker',
517
+ 'Red cockaded Woodpecker',
518
+ 'Red headed Woodpecker',
519
+ 'Downy Woodpecker',
520
+ 'Bewick Wren',
521
+ 'Cactus Wren',
522
+ 'Carolina Wren',
523
+ 'House Wren',
524
+ 'Marsh Wren',
525
+ 'Rock Wren',
526
+ 'Winter Wren',
527
+ 'Common Yell'],
528
+ key="Class Type"
529
+ )
530
+
531
+ def query_huggingface(prompt, bird_name):
532
+ system_prompt = (
533
+ f"You will only answer questions related to the birds listed below. "
534
+ f"If the question is about a bird not in the list, respond with 'I can only provide information about the detected birds.'\n\n"
535
+ f"List of detected birds: {bird_name}\n\n"
536
+ f"Now, answer the following question based only on this list: {prompt}"
537
+ )
538
+ payload = {"inputs": system_prompt, "parameters": {"temperature": 0.8, "max_length": 100}}
539
+ response = requests.post(API_URL, headers=headers, json=payload)
540
+ if response.status_code == 200:
541
+ generated_text = response.json()[0]["generated_text"]
542
+ return generated_text.replace(system_prompt, "").strip()
543
+ else:
544
+ return "Error: Unable to fetch response."
545
+
546
+ # Sidebar
547
+ st.sidebar.title("Have any question? Ask me!")
548
+ user_input = st.sidebar.text_input("You:", key="user_input")
549
+ if st.sidebar.button("Send") and user_input:
550
+ if bird_name or class_type is not None:
551
+ response = query_huggingface(user_input, class_type or bird_name)
552
+ st.sidebar.write("**Bot:**", response)
553
+ else:
554
+ print("Please select a class ")
555
+
556
+ st.markdown("""
557
+ ### Help:
558
+ - Upload an image or videos for detecting birds. After detection, information will be generated.
559
+ - Have further questions, select the bird name from drop down menu and ask the bot from sidebar.
560
+ """)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ ultralytics
2
+ streamlit==1.35.0
3
+ requests
4
+ opencv-python
5
+ pillow
6
+ numpy