stack_overflow_users / stack_overflow_users.py
ardaatahan's picture
Upload folder using huggingface_hub
47974bf verified
raw
history blame
7.88 kB
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()