File size: 18,316 Bytes
c145d80
 
 
 
 
 
b43e4df
 
 
4c49fde
b43e4df
 
c145d80
 
b43e4df
c145d80
082969f
 
 
 
 
 
 
c145d80
b43e4df
 
 
 
 
 
 
 
 
9f8e402
b43e4df
 
 
9f8e402
b43e4df
 
 
 
 
 
 
 
a9e98de
b43e4df
 
 
 
 
c145d80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594d078
c145d80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
082969f
c145d80
 
 
 
 
 
 
 
 
 
 
b43e4df
c145d80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
082969f
c145d80
 
082969f
c145d80
 
082969f
c145d80
 
 
 
082969f
594d078
082969f
 
 
 
c145d80
 
 
082969f
 
 
 
 
 
 
c145d80
 
 
 
 
 
 
 
082969f
c145d80
 
 
 
 
 
 
 
 
 
082969f
c145d80
 
 
 
 
 
 
b43e4df
 
4c49fde
082969f
b43e4df
 
 
 
 
 
 
 
 
 
 
9f8e402
 
b43e4df
 
 
 
 
 
 
 
9f8e402
b43e4df
 
 
 
 
 
9f8e402
b43e4df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c145d80
 
 
 
 
 
 
082969f
 
 
 
 
c145d80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
082969f
c145d80
 
082969f
c145d80
 
082969f
c145d80
 
 
 
082969f
594d078
082969f
 
 
 
c145d80
 
 
082969f
 
 
 
 
 
 
c145d80
 
 
 
 
 
 
 
 
082969f
 
c145d80
 
 
 
 
 
 
 
 
 
 
082969f
 
 
 
 
 
 
 
 
 
 
 
 
c145d80
082969f
c145d80
 
 
 
 
 
 
 
 
 
 
 
082969f
 
 
c145d80
 
 
 
 
082969f
 
 
 
 
 
 
 
 
 
c145d80
 
 
 
082969f
c145d80
082969f
c145d80
 
 
082969f
 
c145d80
 
 
082969f
 
 
 
 
 
 
 
 
 
 
c145d80
 
 
 
 
 
 
 
082969f
 
 
 
 
c145d80
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
import streamlit as st
import plotly.express as px
import pandas as pd
import streamlit_authenticator as stauth
import yaml
from yaml.loader import SafeLoader
import plotly.graph_objects as go

from transformers import pipeline
from PIL import Image, ImageDraw

from backend import *


# Start of Streamlit App
st.set_page_config(layout="centered")
hide_streamlit_style = '''
            <style>
            #MainMenu {visibility: show;}
            footer {visibility: hidden;}
            </style>
            '''
st.markdown(hide_streamlit_style, unsafe_allow_html=True) 


@st.cache_resource
# Function to initialise object_detection model
def initialise_object_detection_model():
    checkpoint = "google/owlvit-base-patch32"
    detector = pipeline(model=checkpoint, task="zero-shot-object-detection")
    return detector
    
# Function to get result from object detection
def get_object_detection_results(detector, image_path, object_labels):
    image = Image.open(image_path)
    predictions = detector(
        image,
        candidate_labels=object_labels,
    ) 
    draw = ImageDraw.Draw(image)
    for prediction in predictions:
        box = prediction["box"]
        label = prediction["label"]
        score = prediction["score"]
        xmin, ymin, xmax, ymax = box.values()
        draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
        draw.text((xmin, ymin), f"{label}: {round(score,2)}", fill="white")
    return image

detector = initialise_object_detection_model()


# Import configuration file for user authentication
with open('credentials.yaml') as file:
    config = yaml.load(file, Loader=SafeLoader)
    
# Create an authentication object.
authenticator = stauth.Authenticate(
    config['credentials'],
    config['cookie']['name'],
    config['cookie']['key'],
    config['cookie']['expiry_days']
    )
# List of advanced users
advanced_users = ['advanced']

# Landing page if user not logged in
if st.session_state['authentication_status'] is None:
    # Landing page copy and banner
    st.markdown('<h1 style="text-align: left;">Fly Situation Monitoring App 🪰</h1>', unsafe_allow_html=True)
    st.markdown('<h4 style="text-align: left;">Keeping You Informed, Keeping Flies at Bay</h4>', unsafe_allow_html=True)
    st.write('\n')
    st.write('\n')
    
    # Loging log-in details
    name, authentication_status, username = authenticator.login('', 'main')
    
    # If log-in failed
    if st.session_state['authentication_status'] is False:
        st.error('Username/password is incorrect.')
    st.write('\n')
    st.write('\n')

    
# App if user is logged in and authenticated
if st.session_state['authentication_status']:
    
    # Streamlit app start
    st.title("Fly Situation Monitoring App 🪰")
    st.markdown("Keeping You Informed, Keeping Flies at Bay")
    st.write('\n')
    
    # User selects a canteen
    canteen = st.selectbox("Select a Canteen:", options=["Deck", "Frontier"])
    st.write('\n')
    
    # If user is a student, show basic app layout
    if not st.session_state['username'] in advanced_users:
        
        # Tabs
        tab1, tab2, tab3 = st.tabs(["Current", "History", "FAQ"])
        
        # Tab 1: Fly Situation
        with tab1:
            st.header("Current Fly Situation")
            
            # Get data
            fly_situation, delta1, delta2, delta3 = get_fly_situation(canteen)
            
            # Display key information using cards
            col1_fly_curr, col2_fly_curr, col3_fly_curr = st.columns(3)
            col1_fly_curr.metric("Temperature", str(fly_situation["temperature"]) + " °C", delta=delta1)
            col2_fly_curr.metric("Humidty", str(fly_situation["humidity"]) + " %", delta=delta2)
            col3_fly_curr.metric("Fly Count", str(fly_situation["fly_count"]), delta=delta3, delta_color="inverse")
            st.caption("Last updated at " + fly_situation["last_updated"] + " (5 min intervals)")
            
            # Alert level
            if fly_situation["fly_count"] > 20:
                alert_level = "High 🔴"
                alert_colour = "red"
            elif fly_situation["fly_count"] > 10:
                alert_level = "Moderate 🟠"
                alert_colour = "orange"
            else: 
                alert_level = "Low 🟢"
                alert_colour = "green"
            st.markdown(f"<h2 style='color:{alert_colour}; text-align: left'>Alert Level: {alert_level}</h3>", unsafe_allow_html=True)
            st.markdown('---')
            
            # Camera locations
            st.header("Smart Sensor Locations")
            camera_locations = get_camera_locations(canteen)
            st.map(camera_locations, size='size', zoom=18)
            st.markdown('---')
            
            # Feedback
            st.header("Feedback")
            # Gather feedback
            feedback_col1, feedback_col2 = st.columns(2)
            with feedback_col1:
                user_feedback = st.text_area("Provide Feedback on the Fly Situation:")
            with feedback_col2:
                uploaded_files = st.file_uploader("Upload a Photo", accept_multiple_files=True, type=['jpg', 'png'])
                for uploaded_file in uploaded_files:
                    st.image(uploaded_file)
            if st.button("Submit Feedback"):
                st.success("Feedback submitted successfully!")
            st.write('\n')
            st.write('\n')
            st.write('\n')
                
        # Tab 2: History
        with tab2:
            st.subheader("Fly Count Over Time")
            
            # Get history data
            fly_situation_history = get_fly_situation_history(canteen)
            
            # Create a DataFrame for the time series data
            df = pd.DataFrame(fly_situation_history)
            sum_by_timestamp = df.groupby('timestamp')['fly_count'].sum().reset_index()
            sum_by_timestamp["timestamp"] = pd.to_datetime(sum_by_timestamp["timestamp"])
            
            # Plot the time series using Plotly Express
            fig = px.line(sum_by_timestamp, x="timestamp", y="fly_count", labels={"fly_count": "Fly Count", "timestamp": "Timestamp"})
            st.plotly_chart(fig)

            # Question-and-Answer
            with st.form("form"):
                prompt = st.text_input("Ask a Question:")
                submit = st.form_submit_button("Submit")
                if prompt:
                    pass
                    #with st.spinner("Generating..."):
                        
                               
        # Tab 3: FAQ
        with tab3:
            st.header("Frequently Asked Questions")
            with st.expander("What is this app about?"):            
                st.write("This app provides you real-time information on fly activity by the smart fly monitoring system.")
            with st.expander("How do the sensors work/detect fly activity?"):
                st.write("The sensors built into the fly traps leverages cutting-edge AI methodologies for advanced fly detection.")
                st.write("1) Object Detection - Using OWL-ViT, an open-vocabulary object detector, we can finetune the model specifically to recognise flies.")
                st.write('\n')
                st.write('\n')
                st.write("Try OWL-ViT:")
                object_labels = st.text_input("Enter your labels for the model to detect (comma-separated)", value="insect")
                labels = object_labels.split(", ")
                image_file = st.file_uploader("Upload an image", type=["jpg", "png"])
                demo_image = st.checkbox("Load in demo image")
                if image_file:
                    st.write('Before:')
                    st.image(image_file)
                if image_file and object_labels:
                    st.write('After:')
                    with st.spinner("Detecting"):
                        st.image(image = get_object_detection_results(detector, image_file, labels))
                if demo_image:
                    st.write('Before:')
                    st.image("images/fly.jpg")
                if demo_image and object_labels:
                    st.write('After:')
                    with st.spinner("Detecting"):
                        st.image(image = get_object_detection_results(detector, "images/fly.jpg", labels))
                st.write('\n')
                st.write('\n')
                st.write("2) Behaviour Analysis - By comparing consecutive frames, the system can extract data such as the trajectory, speed, and direction of each fly's movement. Training the system on these data can improve the system's detection of flies.")
                trajectory_data = pd.DataFrame({
                    'X': [1, 2, 3, 4, 5],
                    'Y': [10, 25, 20, 25, 30],
                    'Timestamp': pd.date_range('2023-01-01', '2023-01-05', freq='D')
                })
                # Create a Plotly figure
                fig = go.Figure()
                # Add a trace for the trajectory
                fig.add_trace(go.Scatter(x=trajectory_data['X'], y=trajectory_data['Y'], mode='lines'))
                # Update layout
                fig.update_layout(
                    xaxis_title='X-Coordinate',
                    yaxis_title='Y-Coordinate',
                    title='Example of a Fly Trajectory'
                )
                # Display the Plotly figure
                st.plotly_chart(fig, use_container_width=True)
                st.write('\n')
                st.write('\n')
                st.write('3) Training Augmentation - The fly detection system employs generative adversial networks, which generates synthetic fly images for training the fly detection model. This makes the system more robust at detecting flies in all scenarios.')
            with st.expander("How accurate is the fly detection in the system?"):
                st.write("The system is still in experimental phase.")
            with st.expander("How often is the data updated or refreshed in real-time?"):
                st.write("5 minute intervals.")
            with st.expander("Why do I hear some sounds coming out from the fly traps?"):
                st.write("The fly traps are built to emit accoustic sounds to attract flies.")
            with st.expander("The traps seem to release some gas. What is that?"):
                st.write("The fly traps release non-toxic pheremones that attract flies.")
                
        # Logout
        logout_col1, logout_col2 = st.columns([6,1])
        with logout_col2:    
            st.write('\n')
            st.write('\n')
            st.write('\n')
            authenticator.logout('Logout', 'main')
            
        # Footer Credits
        st.markdown('##')
        st.markdown("---")
        st.markdown("Created with ❤️ by HS2912 W4 Group 2")
    
    else:
        # Tabs
        tab1, tab2, tab3 = st.tabs(["Current", "History", "Control System"])
        
        # Tab 1: Fly Situation
        with tab1:
            st.header("Current Fly Situation")
            # Get current data
            fly_situation, delta1, delta2, delta3 = get_fly_situation(canteen)
            # Display key information using cards
            col1_fly_curr, col2_fly_curr, col3_fly_curr = st.columns(3)
            col1_fly_curr.metric("Temperature", str(fly_situation["temperature"]) + " °C", delta=delta1)
            col2_fly_curr.metric("Humidty", str(fly_situation["humidity"]) + " %", delta=delta2)
            col3_fly_curr.metric("Fly Count", str(fly_situation["fly_count"]), delta=delta3, delta_color="inverse")
            st.caption("Last updated at " + fly_situation["last_updated"] + " (5 min intervals)")
            
            # Alert 
            if fly_situation["fly_count"] > 20:
                alert_level = "High 🔴"
                alert_colour = "red"
            elif fly_situation["fly_count"] > 10:
                alert_level = "Moderate 🟠"
                alert_colour = "orange"
            else: 
                alert_level = "Low 🟢"
                alert_colour = "green"
            st.markdown(f"<h2 style='color:{alert_colour}; text-align: left'>Alert Level: {alert_level}</h3>", unsafe_allow_html=True)
            st.markdown('---')
            
            # Camera locations
            st.header("Smart Sensor Locations")
            camera_locations = get_camera_locations(canteen)
            st.map(camera_locations, size='size', zoom=18)
            st.markdown('---')
            
            # Feedback
            st.header("Feedback")
            # Gather feedback
            feedback_col1, feedback_col2 = st.columns(2)
            with feedback_col1:
                user_feedback = st.text_area("Provide Feedback on the Fly Situation:")
            with feedback_col2:
                uploaded_files = st.file_uploader("Upload a Photo", accept_multiple_files=True, type=['jpg', 'png'])
                for uploaded_file in uploaded_files:
                    st.image(uploaded_file)
            if st.button("Submit Feedback"):
                st.success("Feedback submitted successfully!")
            st.write('\n')
            st.write('\n')
            st.write('\n')
                

        # Tab 2: History
        with tab2:
            # Fly count over time 
            st.subheader("Fly Count Over Time")
            # Select sensor
            selected_sensor = st.selectbox("Select Sensor:", ["All", "Sensor 1", "Sensor 2", "Sensor 3"])
            # Get history data
            fly_situation_history = get_fly_situation_history(canteen)
            # Create a DataFrame for the time series data
            df = pd.DataFrame(fly_situation_history)
            if selected_sensor != "All":
                df = df[df["sensor"]==int(selected_sensor[-1])]
            sum_by_timestamp = df.groupby('timestamp')['fly_count'].sum().reset_index()
            sum_by_timestamp["timestamp"] = pd.to_datetime(sum_by_timestamp["timestamp"])
            # Plot the time series using Plotly Express
            fig = px.line(sum_by_timestamp, x="timestamp", y="fly_count", labels={"fly_count": "Fly Count", "timestamp": "Timestamp"})
            st.plotly_chart(fig)
            
            # Pheremones level
            st.subheader("Pheremone Level Over Time")
            selected_sensor_level = st.selectbox("Select Sensor:", ["Sensor 1", "Sensor 2", "Sensor 3"])
            # Get history data
            sensor_pheremone_history = get_pheremone_levels(selected_sensor_level)
            pheremone_df = pd.DataFrame(sensor_pheremone_history)
            pheremone_df = pheremone_df[pheremone_df["sensor"] == int(selected_sensor_level[-1])]
            pheremone_df['timestamp'] = pd.to_datetime(pheremone_df['timestamp'])
            # Plot the time series using Plotly Express
            fig = px.line(pheremone_df, x="timestamp", y="pheremone_level", labels={"pheremone_level": "Pheremone Level", "timestamp": "Timestamp"})
            st.plotly_chart(fig)
            

            # Question-and-Answer
            with st.form("form"):
                prompt = st.text_input("Ask a Question:")
                submit = st.form_submit_button("Submit")
                if prompt:
                    with st.spinner("Generating..."):
                        pass
        
        # Tab 3: Control System
        with tab3:
            # Enable/disable automatic pest control system
            st.header("System Settings")
            automatic_control_enabled = st.toggle("Enable Automatic Pest Control", value=True)
            st.write('\n')
            st.write('\n')
            if not automatic_control_enabled:
                disabled = False
            else:
                disabled = True
            
            # Camera
            st.subheader("Smart Camera/Sensors")
            sensor1 = st.toggle("Enable Sensor 1", value=True, disabled=disabled, key='deck_sensor_1')
            sensor2 = st.toggle("Enable Sensor 2", value=True, disabled=disabled, key='deck_sensor_2')
            sensor3 = st.toggle("Enable Sensor 3", value=True, disabled=disabled, key='deck_sensor_3')
            st.write('\n')
            
            # Audio
            st.subheader("Audio")
            # Accoustic 
            accoustic = st.selectbox("Accoustic Audio", ["Audio 1", "Audio 2", "Audio 3"], disabled=disabled)
            st.write('\n')
            
            # Pheremones
            # Time interval for pheremones discharge in minutes)
            st.subheader("Pheremones")
            pheremones_interval = st.slider("Pheremones Discharge Interval (minutes)", min_value=5, max_value=60, value=15, step=5, disabled=disabled)
            st.write('\n')

            # Alerts
            st.subheader('Alerts')
            # Pest activity threshold for alerts
            pest_activity_threshold = st.slider("Fly Count Threshold to Send Out Alerts", min_value=0, max_value=100, value=30, step=5, disabled=disabled)
            st.write('\n')
            # Instant alerts for pest sightings or unusual activity
            st.markdown('<h5>Instant alert</h3>', unsafe_allow_html=True)
            if st.button("Send Pest Alert", disabled=disabled):
                st.success("Pest alert sent!")
            st.write('\n')
            # Notifications for upcoming preventive measures or scheduled treatments
            st.markdown('<h5>Schedule notification for upcoming treatment day</h3>', unsafe_allow_html=True)
            upcoming_event_date = st.date_input("Schedule Date", disabled=disabled)
            upcoming_event_time = st.time_input("Set time for alert", disabled=disabled)
            if st.button("Schedule Notification", disabled=disabled):
                st.success(f"Notification scheduled for {upcoming_event_date} {upcoming_event_time}")

        # Logout
        logout_col1, logout_col2 = st.columns([6,1])
        with logout_col2:    
            st.write('\n')
            st.write('\n')
            st.write('\n')
            authenticator.logout('Logout', 'main')
            
        # Footer Credits
        st.markdown('##')
        st.markdown("---")
        st.markdown("Created with ❤️ by HS2912 W4 Group 2")