File size: 14,260 Bytes
0424b36
4f9da92
0424b36
 
b0de847
1190885
8763ac7
 
 
 
0424b36
 
 
 
 
8907dd8
0424b36
8907dd8
0424b36
 
 
 
8907dd8
0424b36
 
 
 
 
 
 
 
 
 
1190885
 
 
 
0424b36
1190885
 
 
0424b36
1190885
 
 
0424b36
1190885
 
 
8907dd8
1190885
8907dd8
1190885
8907dd8
0424b36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5a45ab
0424b36
 
 
 
 
 
 
 
 
 
 
c599eea
0424b36
 
 
 
 
 
 
 
 
 
 
 
 
 
584f89c
0424b36
8907dd8
 
 
0424b36
 
c599eea
0424b36
4f9da92
 
 
 
 
 
 
 
 
 
 
 
 
 
0424b36
 
 
 
 
8907dd8
0424b36
5c8f078
8907dd8
1190885
 
 
b0de847
 
 
1190885
8907dd8
 
 
5c8f078
4f9da92
8907dd8
b0de847
1190885
 
4f9da92
 
 
 
0424b36
 
 
 
 
 
 
 
 
8907dd8
 
0424b36
4f9da92
 
0424b36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8907dd8
 
0424b36
8907dd8
0424b36
e23fef2
0424b36
 
 
 
 
 
 
8907dd8
0424b36
5c8f078
8907dd8
1190885
 
 
b0de847
 
 
1190885
b0de847
 
 
 
 
 
8907dd8
b0de847
1190885
 
8907dd8
0424b36
8907dd8
0424b36
 
 
 
 
 
8907dd8
 
0424b36
 
 
 
8907dd8
 
0424b36
8907dd8
0424b36
8907dd8
0424b36
b0de847
 
 
 
 
1190885
 
 
 
 
b0de847
 
 
 
 
 
 
1190885
 
 
 
 
b0de847
 
0424b36
 
 
 
1190885
 
 
0424b36
1190885
 
 
8907dd8
1190885
 
 
0424b36
 
1190885
 
 
 
 
0424b36
 
1190885
 
0424b36
1190885
0424b36
 
8763ac7
 
 
 
 
 
 
 
 
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
import discord
from discord import Option, commands
import redis
import os
import random
import time
from threading import Thread
import gradio as gr
from gradio import utils
from pathlib import Path

# Function to generate auto-incremented IDs
def generate_id(key):
    return r.incr(key)

def generate_progress_bar(num_labels, width=20, n=300):
    print(num_labels)
    percentage = int(int(num_labels) / n * 100)
    completed_blocks = int(percentage * width / 100)
    remaining_blocks = width - completed_blocks

    progress_bar = 'β–“' * completed_blocks + 'β–‘' * remaining_blocks
    percentage_text = f' {num_labels}/{n} identified 🦜🌱 '

    return f'πŸ† {progress_bar} {percentage_text}'

# Redis client setup

redis_url = 'redis://default:[email protected]:7369'
r = redis.from_url(redis_url)

r.set('species_identified', 0)

# def improve_player_stats_image(ctx):
#     # add 1 to the number of species identified
#     value = r.get(b'species_identified').decode('utf-8')
#     r.set(b'species_identified', int(value) + 1)

#     xp_key = f'{ctx.author.name}:XP'.encode('utf-8')
#     if not r.exists(xp_key):
#         r.set(xp_key, 0)

#     role_key = f'{ctx.author.name}:role'.encode('utf-8')
#     if not r.exists(role_key):
#         r.set(role_key, 'Naturalist')

#     img_oc_key = f'{ctx.author.name}:image'.encode('utf-8')
#     if not r.exists(img_oc_key):
#         r.set(img_oc_key, 0)

#     r.set(xp_key, int(r.get(xp_key)) + 10)

#     r.set(img_oc_key, int(r.get(img_oc_key)) + 1)


bot = discord.Bot()

@bot.event
async def on_ready():
    print(f"{bot.user} is ready and online!")

@bot.command(
            description="Get image predictions", 
            options=[
                Option(name="id", description="The ID of the image")
            ])
async def predict_image(ctx, id):
    # Fetch the image data from Redis
    image_data_bytes = r.hgetall(f'image:{id}'.encode('utf-8'))
    image_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in image_data_bytes.items()}
    path = f'https://gainforest-transparency-dashboard.s3.amazonaws.com/{image_data["awsCID"]}'
    print(image_data)
    message = f"**Image Observation: {id} by _{image_data['sensor']}_**"

    message += "\n_Below are Top 10 predictions of AI_"
    emoji_unicode_list = [chr(0x30 + i) + '\uFE0F\u20E3' for i in range(11)]

    prediction_data_bytes = r.hgetall(f'prediction:{id}:1'.encode('utf-8'))
    prediction_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in prediction_data_bytes.items()}

    embed = discord.Embed(
        title="",
        description=f"Label: {prediction_data['label']}\nPredictions of our AI algorithms",
        color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from
    )
    embed.set_author(name=f"Image ID: {id} - AI Predictions", icon_url=ctx.author.display_avatar.url)

    for i in range(1, 10):
        prediction_data_bytes = r.hgetall(f'prediction:{id}:{i}'.encode('utf-8'))
        prediction_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in prediction_data_bytes.items()}
        species = prediction_data['label']
        score = prediction_data['confidence']
        # message = message + f'\n> {emoji_unicode_list[i-1]} {species} with confidence {score}'
        embed.add_field(name=f'{species}', value=f'Confidence: {float(score):.4f}', inline=True)
    embed.set_thumbnail(url=path)

    # Send the image
    await ctx.respond("Hint: You can use [Singapore Biodiversity Online](https://singapore.biodiversity.online/), [NParks Flora & Fauna Database](https://www.nparks.gov.sg/florafaunaweb), and [Singapore Birds](https://singaporebirds.com/singapore-bird-list/) to verify", embed=embed)

@bot.command(
            description="Get image observation", 
            options=[
                Option(name="id", description="The ID of the image")
            ])
async def image(ctx, id):
    # Fetch the image data from Redis
    image_data_bytes = r.hgetall(f'image:{id}'.encode('utf-8'))
    image_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in image_data_bytes.items()}
    print(image_data)

    # Create an embed
    embed = discord.Embed(color=discord.Colour.blurple())
    embed.set_author(name=f"Image ID: {id}", icon_url=ctx.author.display_avatar.url)
    embed.add_field(name="Sensor", value=image_data['sensor'], inline=True)
    embed.add_field(name="Recorded at", value=image_data['timestamp'], inline=True)
    embed.add_field(name="Recent Label", value=image_data['label'], inline=True)
    embed.add_field(name="Proposed by", value=image_data['author'], inline=True)
    path = f'https://gainforest-transparency-dashboard.s3.amazonaws.com/{image_data["awsCID"]}'
    embed.set_image(url=path)
    await ctx.respond(f"You are looking at Image ID **{id}**\n!Hint: You can use [Singapore Biodiversity Online](https://singapore.biodiversity.online/), [NParks Flora & Fauna Database](https://www.nparks.gov.sg/florafaunaweb), and [Singapore Birds](https://singaporebirds.com/singapore-bird-list/) to verify", embed=embed)

def confAutocomplete(self: discord.AutocompleteContext):
        return ['low', 'medium', 'high']

def get_conf_score(confidence: str):
    match confidence:
        case "low":
            return 0
        case "medium":
            return 1
        case "high":
            return 2
        case _:
            return 0

@bot.command(
        description="Label image observation",
        options=[
            Option(name="id", description="The ID of the image"),
            Option(name="label", description="The label for the image"),
            Option(name="confidence", description="Choose your confidence: high, medium, low", autocomplete=confAutocomplete)
    ])
async def identify_image(ctx, id:int, label:str, confidence: str):

    timestamp = str(time.time())
    author_id = str(ctx.author_id)

    role = "Hobbyist"
    role_names = [role.name for role in ctx.author.roles]
    if "Expert" in role_names:
        role = "Expert"
    
    label_cnt = generate_id(f'cnt:label:image:{id}')
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'label', label.encode('utf-8'))
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'author', ctx.author.name.encode('utf-8'))
    conf_score = get_conf_score(confidence)
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'confidence', conf_score)
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'role', role)
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'authorid', author_id)
    r.hset(f'label:image:{id}:{label_cnt}'.encode('utf-8'), b'timestamp', timestamp)

    r.hset(f'image:{id}'.encode('utf-8'), b'label', label.encode('utf-8'))
    r.hset(f'image:{id}'.encode('utf-8'), b'author', ctx.author.mention.encode('utf-8'))

    # Fetch the image data from Redis
    image_data_bytes = r.hgetall(f'image:{id}'.encode('utf-8'))
    image_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in image_data_bytes.items()}
    print(image_data)

    # Create an embed
    embed = discord.Embed(color=discord.Colour.blurple())
    embed.set_author(name=f"Image Observation {id} - New Label πŸŽ‰", icon_url=ctx.author.display_avatar.url)
    embed.add_field(name="Sensor", value=image_data['sensor'], inline=True)
    embed.add_field(name="Recorded at", value=image_data['timestamp'], inline=True)
    embed.add_field(name="Recent Label", value=image_data['label'], inline=True)
    embed.add_field(name="Proposed by", value=image_data['author'], inline=True)
    path = f'https://gainforest-transparency-dashboard.s3.amazonaws.com/{image_data["awsCID"]}'
    embed.set_image(url=path)

    await ctx.respond(f"{ctx.author.mention} labeled observation **{id}** as **{label}**  πŸŽ‰ (Earned 10 XP)", embed=embed)

@bot.command(description="Get progress bar.")
async def progress(ctx):
    value = r.get(b'species_identified').decode('utf-8')
    progress_bar = generate_progress_bar(value)
    await ctx.respond(progress_bar) # this decorator makes a slash command

@bot.command(description="Get sound data.") # this decorator makes a slash command
async def sound(ctx, id): # a slash command will be created with the name "ping"
     # Fetch the sound data from Redis
    sound_data_bytes = r.hgetall(f'sound:{id}'.encode('utf-8'))
    sound_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in sound_data_bytes.items()}

    # Create an embed
    embed = discord.Embed(color=discord.Colour.blurple())
    embed.set_author(name=f"Sound Observation {id} - Task", icon_url=ctx.author.display_avatar.url)
    embed.add_field(name="Sensor", value=sound_data['sensor'], inline=True)
    embed.add_field(name="Recorded at", value=sound_data['timestamp'], inline=True)
    embed.add_field(name="Recent Label", value=sound_data['label'], inline=True)
    embed.add_field(name="Proposed by", value=sound_data['author'], inline=True)
    embed.add_field(name="Detected at Timestamp", value=sound_data['label_at'], inline=True)

    await ctx.respond(f'Please listen to Sound ID **{id}** here:\nhttps://gainforest.app/observations/{sound_data["uuid"]} 🦜🎡', embed=embed)

@bot.command(
        description="Label sound observation",
        options=[
            Option(name="id", description="The ID of the sound"),
            Option(name="label", description="The label for the sound"),
            Option(name="timestamp", description="The timestamp of the observation"),
            Option(name="confidence", description="Choose your confidence: high, medium, low", autocomplete=confAutocomplete)
    ])
async def identify_sound(ctx, id:int, label:str, timestamp:str, confidence: str):

    timestamp = str(time.time())
    author_id = str(ctx.author_id)

    role = "Hobbyist"
    role_names = [role.name for role in ctx.author.roles]
    if "Expert" in role_names:
        role = "Expert"

    label_cnt = generate_id(f'cnt:label:sound:{id}')
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'label', label.encode('utf-8'))
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'author', ctx.author.name.encode('utf-8'))
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'role', role)
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'label_at', timestamp.encode('utf-8'))
    conf_score = get_conf_score(confidence)
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'confidence', conf_score)
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'authorid', author_id)
    r.hset(f'label:sound:{id}:{label_cnt}'.encode('utf-8'), b'timestamp', timestamp)

    r.hset(f'sound:{id}'.encode('utf-8'), b'label', label.encode('utf-8'))
    r.hset(f'sound:{id}'.encode('utf-8'), b'label_at', timestamp.encode('utf-8'))
    r.hset(f'sound:{id}'.encode('utf-8'), b'author', ctx.author.mention.encode('utf-8'))

    # Fetch the sound data from Redis
    sound_data_bytes = r.hgetall(f'sound:{id}'.encode('utf-8'))
    sound_data = {k.decode('utf-8'): v.decode('utf-8') for k, v in sound_data_bytes.items()}

    print(sound_data)

    # Create an embed
    embed = discord.Embed(color=discord.Colour.blurple())
    embed.set_author(name=f"Sound Observation {id} - New Label πŸŽ‰", icon_url=ctx.author.display_avatar.url)
    embed.add_field(name="Sensor", value=sound_data['sensor'], inline=True)
    embed.add_field(name="Recorded at", value=sound_data['timestamp'], inline=True)
    embed.add_field(name="Recent Label", value=sound_data['label'], inline=True)
    embed.add_field(name="Proposed by", value=sound_data['author'], inline=True)
    embed.add_field(name="Detected at Timestamp", value=sound_data['label_at'], inline=True)

    await ctx.respond(f'{ctx.author.mention} labeled sound observation **{id}** as **{label}** at **{timestamp}**  πŸŽ‰ (Earned 10 XP).\nListen here:\nhttps://gainforest.app/observations/{sound_data["uuid"]} 🦜🎡', embed=embed)

@bot.command(
        description="Get a random unlabeled image observation"
    )
async def next_image(ctx):
    total_images = r.get(b'cnt:image').decode('utf-8')
    numbers = list(range(1, int(total_images)))
    exclude_redis = r.lrange('image:accept', 0, -1)
    exclude = set(int(num.decode('utf-8')) for num in exclude_redis)
    numbers = [num for num in numbers if num not in exclude]
    id = random.choice(numbers)
    await image(ctx, id)

@bot.command(
        description="Get a random unlabeled sound observation"
    )
async def next_sound(ctx):
    total_sound = r.get(b'cnt:sound').decode('utf-8')
    numbers = list(range(1, int(total_sound)))
    exclude_redis = r.lrange('image:accept', 0, -1)
    exclude = set(int(num.decode('utf-8')) for num in exclude_redis)
    numbers = [num for num in numbers if num not in exclude]
    id = random.choice(numbers)
    await sound(ctx, id)

@bot.command(
        description="Check your profile"
    )
async def profile(ctx):
    # xp_key = f'{ctx.author.name}:XP'.encode('utf-8')
    # if not r.exists(xp_key):
    #     r.set(xp_key, 0)

    # img_oc_key = f'{ctx.author.name}:image'.encode('utf-8')
    # if not r.exists(img_oc_key):
    #     r.set(img_oc_key, 0)

    # s_oc_key = f'{ctx.author.name}:sound'.encode('utf-8')
    # if not r.exists(s_oc_key):
    #     r.set(s_oc_key, 0)

     # Create an embed
    role = "Hobbyist"
    role_names = [role.name for role in ctx.author.roles]
    if "Expert" in role_names:
        role = "Expert"

    embed = discord.Embed(color=discord.Colour.blurple())
    embed.set_author(name=f"{ctx.author.name} - Profile", icon_url=ctx.author.display_avatar.url)
    # embed.add_field(name="**PROGRESS**", value=f"**Level**: 1\n**XP**: {r.get(xp_key).decode()}/1000\n", inline=False)
    # embed.add_field(name="**STATS**", value=f"**🌱 Images labeled**: {r.get(img_oc_key).decode()}", inline=False)
    embed.set_thumbnail(url=ctx.author.display_avatar.url)
    embed.set_footer(text=f"πŸ† Role: {r.get(role).decode()}")
    await ctx.respond(embed=embed)

t = Thread(target=bot.run, daemon=True, args=('MTA5NzMzMDI2MDI4NDAzNTEyMg.GNFiQP.hZC_2HLTvVAROlKKUmnVQjviT0G4wHeQq23-rs', ))
t.start()

import gradio as gr

with gr.Blocks() as demo:
    gr.Markdown(Path('landing.md').read_text())

demo.launch()