|
from typing import Optional |
|
|
|
import requests |
|
import streamlit as st |
|
from app.settings import API_BASE_URL |
|
from PIL import Image |
|
|
|
|
|
def login(username: str, password: str) -> Optional[str]: |
|
"""This function calls the login endpoint of the API to authenticate the user |
|
and get a token. |
|
|
|
Args: |
|
username (str): email of the user |
|
password (str): password of the user |
|
|
|
Returns: |
|
Optional[str]: token if login is successful, None otherwise |
|
""" |
|
|
|
url = "{}/{}".format(API_BASE_URL, "login") |
|
|
|
|
|
headers = { |
|
"accept": "application/json", |
|
"Content-Type": "application/x-www-form-urlencoded", |
|
} |
|
|
|
|
|
data = { |
|
"username": username, |
|
"password": password, |
|
"grant_type": "", |
|
"scope": "", |
|
"client_id": "", |
|
"client_secret": "", |
|
} |
|
|
|
|
|
response = requests.post(url, headers=headers, data=data) |
|
if response.status_code == 200: |
|
return response.json().get("access_token") |
|
|
|
return None |
|
|
|
|
|
def predict(token: str, uploaded_file: Image) -> requests.Response: |
|
"""This function calls the predict endpoint of the API to classify the uploaded |
|
image. |
|
|
|
Args: |
|
token (str): token to authenticate the user |
|
uploaded_file (Image): image to classify |
|
|
|
Returns: |
|
requests.Response: response from the API |
|
""" |
|
|
|
files = {"file": (uploaded_file.name, uploaded_file.getvalue())} |
|
|
|
|
|
headers = {"Authorization": f"Bearer {token}"} |
|
|
|
|
|
url = f"{API_BASE_URL}/model/predict" |
|
response = requests.post(url, files=files, headers=headers) |
|
|
|
return response |
|
|
|
|
|
def send_feedback( |
|
token: str, feedback: str, score: float, prediction: str, image_file_name: str |
|
) -> requests.Response: |
|
"""This function calls the feedback endpoint of the API to send feedback about |
|
the classification. |
|
|
|
Args: |
|
token (str): token to authenticate the user |
|
feedback (str): string with feedback |
|
score (float): confidence score of the prediction |
|
prediction (str): predicted class |
|
image_file_name (str): name of the image file |
|
|
|
Returns: |
|
requests.Response: _description_ |
|
""" |
|
|
|
data = { |
|
"feedback": feedback, |
|
"score": score, |
|
"predicted_class": prediction, |
|
"image_file_name": image_file_name, |
|
} |
|
|
|
|
|
headers = {"Authorization": f"Bearer {token}"} |
|
|
|
|
|
url = f"{API_BASE_URL}/feedback" |
|
response = requests.post(url, json=data, headers=headers) |
|
|
|
return response |
|
|
|
|
|
|
|
st.set_page_config(page_title="Image Classifier", page_icon="π·") |
|
st.markdown( |
|
"<h1 style='text-align: center; color: #4B89DC;'>Image Classifier</h1>", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
if "token" not in st.session_state: |
|
st.markdown("## Login") |
|
username = st.text_input("Username") |
|
password = st.text_input("Password", type="password") |
|
if st.button("Login"): |
|
token = login(username, password) |
|
if token: |
|
st.session_state.token = token |
|
st.success("Login successful!") |
|
st.rerun() |
|
else: |
|
st.error("Login failed. Please check your credentials.") |
|
else: |
|
st.success("You are logged in!") |
|
|
|
|
|
if "token" in st.session_state: |
|
token = st.session_state.token |
|
|
|
|
|
uploaded_file = st.file_uploader("Sube una imagen", type=["jpg", "jpeg", "png"]) |
|
|
|
print(type(uploaded_file)) |
|
|
|
|
|
if uploaded_file is not None: |
|
image = Image.open(uploaded_file) |
|
st.image(image, caption="Imagen subida", width=300) |
|
|
|
if "classification_done" not in st.session_state: |
|
st.session_state.classification_done = False |
|
|
|
|
|
if st.button("Classify"): |
|
if uploaded_file is not None: |
|
response = predict(token, uploaded_file) |
|
if response.status_code == 200: |
|
result = response.json() |
|
st.write(f"**Prediction:** {result['prediction']}") |
|
st.write(f"**Score:** {result['score']}") |
|
st.session_state.classification_done = True |
|
st.session_state.result = result |
|
else: |
|
st.error("Error classifying image. Please try again.") |
|
else: |
|
st.warning("Please upload an image before classifying.") |
|
|
|
|
|
if st.session_state.classification_done: |
|
st.markdown("## Feedback") |
|
feedback = st.text_area("If the prediction was wrong, please provide feedback.") |
|
if st.button("Send Feedback"): |
|
if feedback: |
|
token = st.session_state.token |
|
result = st.session_state.result |
|
score = result["score"] |
|
prediction = result["prediction"] |
|
image_file_name = result.get("image_file_name", "uploaded_image") |
|
response = send_feedback( |
|
token, feedback, score, prediction, image_file_name |
|
) |
|
if response.status_code == 201: |
|
st.success("Thanks for your feedback!") |
|
else: |
|
st.error("Error sending feedback. Please try again.") |
|
else: |
|
st.warning("Please provide feedback before sending.") |
|
st.warning("Please provide feedback before sending.") |
|
|
|
|
|
st.markdown("<hr style='border:2px solid #4B89DC;'>", unsafe_allow_html=True) |
|
st.markdown( |
|
"<p style='text-align: center; color: #4B89DC;'>2024 Image Classifier App</p>", |
|
unsafe_allow_html=True, |
|
) |
|
|