Spaces:
Sleeping
Sleeping
File size: 7,875 Bytes
dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 47974bf dde4343 |
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 |
import numpy as np
import gradio as gr
import aiohttp
import asyncio
import cv2
import dlib
import base64
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
URL = "https://api.stackexchange.com/2.2/users?site=stackoverflow"
MAX_USERS = 10
def filter_profile_data(data):
"""
Filter user profile data to get reputation, display name, profile link, and profile image
of first 10 users based on reputation.
:param data: array of dicts containing raw user profile information
:return: array of dicts filtered user profile information
"""
data = data["items"]
data = data[: min(MAX_USERS, len(data))]
keys_to_keep = ["reputation", "location", "display_name", "link", "profile_image"]
filtered_data = []
for raw_user in data:
user = {}
for key in keys_to_keep:
user[key] = raw_user[key] if key in raw_user else None
filtered_data.append(user)
return filtered_data
async def fetch_stack_overflow_profiles(url):
"""
Fetch user profiles from Stack Overflow API.
:param url: URL of API to be called
:return: Raw user profile data if response is successful else error message
"""
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, timeout=10) as response:
if response.status == 200:
data = await response.json()
data = filter_profile_data(data)
return data
else:
return f"Failed to retrieve Stack Overflow user data: Status Code {response.status}"
except aiohttp.ClientError as e:
return str(e)
except asyncio.TimeoutError:
return "User data request timed out"
async def download_profile_image(url):
"""
Download profile image from given URL.
:param url: URL of profile image
:return: RGB decoded image if image can be downloaded else error message
"""
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, timeout=10) as response:
if response.status == 200:
data = await response.read()
array = np.asarray(bytearray(data), dtype=np.uint8)
image = cv2.imdecode(array, 1)
return image
else:
return f"Failed to retrieve user profile image: Status Code {response.status}"
except aiohttp.ClientError as e:
return f"Profile image could not be downloaded: {str(e)}"
except asyncio.TimeoutError:
return "User profile image request timed out"
def detect_face_in_image(image):
"""
Detects whether a there is a face in the input image using dlib.
:param image: Image to check for face
:return: Image with bounding box highlighting face if face exists else original image
:return: True if face exists in image else False
"""
detector = dlib.get_frontal_face_detector()
faces, _, _ = detector.run(image, 1, -0.5)
for face in faces:
cv2.rectangle(
image,
(face.left(), face.top()),
(face.right(), face.bottom()),
(0, 255, 0),
4,
)
_, buffer = cv2.imencode(".jpg", image)
image = base64.b64encode(buffer)
return image, len(faces) > 0
def fetch_and_process_users():
"""
Higher level function to fetch users and analyze their profile images.
:return: HTML content displaying fetched user information and error messages as necessary
"""
profiles = asyncio.run(fetch_stack_overflow_profiles(URL))
if type(profiles) is str:
return get_error_html(profiles)
user_content = []
for profile in profiles:
image_url = profile["profile_image"]
image = asyncio.run(download_profile_image(image_url)) if image_url else None
if image is None:
user_html = get_user_html(
None, profile, "", "Image for this user could not be fetched!"
)
user_content.append(user_html)
continue
if type(image) is str:
user_html = get_user_html(None, profile, "", image)
user_content.append(user_html)
continue
image, face_exists = detect_face_in_image(image)
face_message = (
"Face detected and highlighted in the user profile image!"
if face_exists
else "No face detected in the user profile image!"
)
image = image.decode("utf-8")
user_html = get_user_html(image, profile, face_message, None)
user_content.append(user_html)
return "".join(user_content)
def get_error_html(error_message):
"""
Constructs an HTML template to display error message.
:param error_message: Message to be displayed
:return: HTML code with the error message
"""
return f"""
<div style='display: flex; flex-direction: column; align-items: center; margin-bottom: 5rem;'>
<div style='text-align: center; font-size: 16px;'>
<strong style='font-size: 18px;'></strong> {error_message} Try generating again.
<br>
</div>
</div>
"""
def get_user_html(image, profile, face_message, error_message):
"""
Constructs an HTML template to display user information and error message.
:param image: Base64 image to be displayed on the page
:param profile: Profile information to be displayed
:param face_message: Message that indicates whether face exists or not in the picture
:param error_message: Error message to display in case image cannot be fetched
:return: HTML code with the user information with a potential error message
"""
if error_message is None:
image_html = f"""
<div style="margin-bottom: 1rem;">
<img src="data:image/jpeg;base64,{image}" alt="Profile image" style="width: 100%; height: 100%; object-fit: cover;">
</div>
<span style="font-size: 16px; color: grey;">{face_message}</span>
"""
else:
image_html = f"""
<div style="text-align: center; font-size: 16px; margin-bottom: 1rem;">
<strong style="font-size: 18px;"></strong> {error_message} Try generating again.
<br>
</div>
"""
user_html = f"""
<div style="display: flex; flex-direction: column; align-items: center; margin-bottom: 5rem;">
{image_html}
<div style="text-align: center; font-size: 16px;">
<strong style="font-size: 18px;">Name:</strong> {profile.get("display_name", "Not available")}
<br>
<strong style="font-size: 18px;">Reputation:</strong> {profile.get("reputation", "Not available")}
<br>
<strong style="font-size: 18px;">Location:</strong> {profile.get("location", "Not available")}
<br>
<a href="{profile.get("link", "")}" target="_blank" style="font-size: 16px; color: blue; text-decoration: none;">View Profile</a>
</div>
</div>
"""
return user_html
def get_html_content():
"""
Constructs the whole HTML template to be displayed to the user.
:return: HTML code to display each user's information and error messages
"""
html_content = fetch_and_process_users()
return html_content
demo = gr.Interface(
fn=get_html_content,
inputs=[],
outputs=gr.components.HTML(label="Stack Overflow User Profiles"),
title="Stack Overflow User Profiles and Face Detection",
css="footer{display:none !important}",
allow_flagging="never",
)
if __name__ == "__main__":
demo.launch()
|