Update app.py
Browse files
app.py
CHANGED
@@ -50,7 +50,7 @@ with st.sidebar:
|
|
50 |
def log_debug(message):
|
51 |
"""Helper function to log debug messages only when debug mode is enabled"""
|
52 |
if st.session_state.debug:
|
53 |
-
st.write(f"DEBUG: {message}")
|
54 |
|
55 |
# Function to check environment
|
56 |
def check_environment():
|
@@ -509,11 +509,10 @@ def preprocess_image_xception(image):
|
|
509 |
log_debug("Image is None - this should never happen!")
|
510 |
return None, None, None
|
511 |
|
512 |
-
#
|
513 |
-
image_np = np.array(image.convert('RGB'))
|
514 |
-
log_debug(f"Image shape: {image_np.shape}")
|
515 |
|
516 |
-
# Face detection
|
517 |
gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
|
518 |
faces = face_detector.detectMultiScale(gray, 1.1, 5)
|
519 |
|
@@ -528,7 +527,6 @@ def preprocess_image_xception(image):
|
|
528 |
areas = [w * h for (x, y, w, h) in faces]
|
529 |
largest_idx = np.argmax(areas)
|
530 |
x, y, w, h = faces[largest_idx]
|
531 |
-
log_debug(f"Using largest face at: x={x}, y={y}, w={w}, h={h}")
|
532 |
|
533 |
padding_x = int(w * 0.05) # Use percentages as in gradcam_xception
|
534 |
padding_y = int(h * 0.05)
|
@@ -544,7 +542,6 @@ def preprocess_image_xception(image):
|
|
544 |
transform = get_xception_transform()
|
545 |
# Apply transform to the selected region (face or whole image)
|
546 |
input_tensor = transform(face_img_for_transform).unsqueeze(0)
|
547 |
-
log_debug(f"Preprocessed tensor shape: {input_tensor.shape}")
|
548 |
|
549 |
# Return tensor, original full image, and the display face box
|
550 |
return input_tensor, image, face_box_display
|
@@ -552,21 +549,10 @@ def preprocess_image_xception(image):
|
|
552 |
except Exception as e:
|
553 |
st.error(f"Error in preprocessing image: {str(e)}")
|
554 |
import traceback
|
555 |
-
|
556 |
-
log_debug(f"Preprocessing error details: {error_details}")
|
557 |
-
if st.session_state.debug:
|
558 |
-
st.error(error_details)
|
559 |
|
560 |
-
#
|
561 |
-
|
562 |
-
log_debug("Trying fallback preprocessing method")
|
563 |
-
transform = get_xception_transform()
|
564 |
-
input_tensor = transform(image).unsqueeze(0)
|
565 |
-
return input_tensor, image, None
|
566 |
-
except Exception as fallback_e:
|
567 |
-
log_debug(f"Fallback also failed: {str(fallback_e)}")
|
568 |
-
st.error("Both preprocessing attempts failed. Please try another image.")
|
569 |
-
return None, None, None
|
570 |
|
571 |
# Main app
|
572 |
def main():
|
@@ -706,18 +692,12 @@ def main():
|
|
706 |
uploaded_file = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])
|
707 |
if uploaded_file is not None:
|
708 |
try:
|
709 |
-
#
|
710 |
-
|
711 |
-
|
712 |
-
st.write(f"Debug: Received file of size {len(file_bytes)} bytes")
|
713 |
-
# Process directly in memory
|
714 |
-
image_stream = io.BytesIO(file_bytes)
|
715 |
-
uploaded_image = Image.open(image_stream).convert("RGB")
|
716 |
st.session_state.upload_method = "file"
|
717 |
-
# Log success
|
718 |
-
st.success("File loaded successfully in memory")
|
719 |
except Exception as e:
|
720 |
-
st.error(f"Error loading
|
721 |
import traceback
|
722 |
st.error(traceback.format_exc())
|
723 |
|
@@ -726,33 +706,21 @@ def main():
|
|
726 |
if url and url.strip():
|
727 |
try:
|
728 |
import requests
|
729 |
-
#
|
730 |
-
display_url = url.split("?")[0] if "?" in url else url
|
731 |
-
st.write(f"Debug: Attempting to fetch image from {display_url}")
|
732 |
-
|
733 |
headers = {
|
734 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
735 |
}
|
736 |
response = requests.get(url, stream=True, headers=headers, timeout=10)
|
737 |
|
738 |
if response.status_code == 200:
|
739 |
-
#
|
740 |
-
|
741 |
-
|
742 |
-
# Process directly in memory
|
743 |
-
image_stream = io.BytesIO(response.content)
|
744 |
-
uploaded_image = Image.open(image_stream).convert("RGB")
|
745 |
st.session_state.upload_method = "url"
|
746 |
-
st.success(f"Image successfully loaded from URL - Size: {len(response.content)} bytes")
|
747 |
else:
|
748 |
st.error(f"Failed to load image from URL: Status code {response.status_code}")
|
749 |
-
if response.status_code in [403, 401]:
|
750 |
-
st.warning("This appears to be an access permissions issue. The server is refusing to serve this image.")
|
751 |
-
st.info("Try using an image URL from a site that allows hotlinking, or upload a file directly.")
|
752 |
except Exception as e:
|
753 |
st.error(f"Error loading image from URL: {str(e)}")
|
754 |
-
import traceback
|
755 |
-
st.error(traceback.format_exc())
|
756 |
|
757 |
# If we have an uploaded image, process it
|
758 |
if uploaded_image is not None:
|
@@ -777,9 +745,12 @@ def main():
|
|
777 |
try:
|
778 |
with st.spinner("Analyzing image with Xception model..."):
|
779 |
# Preprocess image for Xception
|
780 |
-
st.write("Starting Xception processing...")
|
781 |
input_tensor, original_image, face_box = preprocess_image_xception(image)
|
782 |
|
|
|
|
|
|
|
|
|
783 |
# Get device and model
|
784 |
device = st.session_state.device
|
785 |
model = st.session_state.xception_model
|
@@ -789,23 +760,17 @@ def main():
|
|
789 |
|
790 |
# Move tensor to device
|
791 |
input_tensor = input_tensor.to(device)
|
792 |
-
st.write(f"Input tensor on device: {device}")
|
793 |
|
794 |
# Forward pass with proper error handling
|
795 |
try:
|
796 |
with torch.no_grad():
|
797 |
-
st.write("Running model inference...")
|
798 |
logits = model(input_tensor)
|
799 |
-
st.write(f"Raw logits: {logits}")
|
800 |
probabilities = torch.softmax(logits, dim=1)[0]
|
801 |
-
st.write(f"Probabilities: {probabilities}")
|
802 |
pred_class = torch.argmax(probabilities).item()
|
803 |
confidence = probabilities[pred_class].item()
|
804 |
-
st.write(f"Predicted class: {pred_class}, Confidence: {confidence:.4f}")
|
805 |
|
806 |
# Explicit class mapping - adjust if needed based on your model
|
807 |
pred_label = "Fake" if pred_class == 0 else "Real"
|
808 |
-
st.write(f"Mapped to label: {pred_label}")
|
809 |
except Exception as e:
|
810 |
st.error(f"Error in model inference: {str(e)}")
|
811 |
import traceback
|
@@ -831,7 +796,6 @@ def main():
|
|
831 |
# GradCAM visualization with error handling
|
832 |
st.subheader("GradCAM Visualization")
|
833 |
try:
|
834 |
-
st.write("Generating GradCAM visualization...")
|
835 |
cam, overlay, comparison, detected_face_box = process_image_with_xception_gradcam(
|
836 |
image, model, device, pred_class
|
837 |
)
|
|
|
50 |
def log_debug(message):
|
51 |
"""Helper function to log debug messages only when debug mode is enabled"""
|
52 |
if st.session_state.debug:
|
53 |
+
st.sidebar.write(f"DEBUG: {message}")
|
54 |
|
55 |
# Function to check environment
|
56 |
def check_environment():
|
|
|
509 |
log_debug("Image is None - this should never happen!")
|
510 |
return None, None, None
|
511 |
|
512 |
+
# Convert to numpy array for processing
|
513 |
+
image_np = np.array(image.convert('RGB'))
|
|
|
514 |
|
515 |
+
# Face detection
|
516 |
gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
|
517 |
faces = face_detector.detectMultiScale(gray, 1.1, 5)
|
518 |
|
|
|
527 |
areas = [w * h for (x, y, w, h) in faces]
|
528 |
largest_idx = np.argmax(areas)
|
529 |
x, y, w, h = faces[largest_idx]
|
|
|
530 |
|
531 |
padding_x = int(w * 0.05) # Use percentages as in gradcam_xception
|
532 |
padding_y = int(h * 0.05)
|
|
|
542 |
transform = get_xception_transform()
|
543 |
# Apply transform to the selected region (face or whole image)
|
544 |
input_tensor = transform(face_img_for_transform).unsqueeze(0)
|
|
|
545 |
|
546 |
# Return tensor, original full image, and the display face box
|
547 |
return input_tensor, image, face_box_display
|
|
|
549 |
except Exception as e:
|
550 |
st.error(f"Error in preprocessing image: {str(e)}")
|
551 |
import traceback
|
552 |
+
log_debug(f"Preprocessing error details: {traceback.format_exc()}")
|
|
|
|
|
|
|
553 |
|
554 |
+
# Return None values to indicate failure
|
555 |
+
return None, None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
556 |
|
557 |
# Main app
|
558 |
def main():
|
|
|
692 |
uploaded_file = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])
|
693 |
if uploaded_file is not None:
|
694 |
try:
|
695 |
+
# Simple direct approach - load the image directly
|
696 |
+
image = Image.open(uploaded_file).convert("RGB")
|
697 |
+
uploaded_image = image
|
|
|
|
|
|
|
|
|
698 |
st.session_state.upload_method = "file"
|
|
|
|
|
699 |
except Exception as e:
|
700 |
+
st.error(f"Error loading image: {str(e)}")
|
701 |
import traceback
|
702 |
st.error(traceback.format_exc())
|
703 |
|
|
|
706 |
if url and url.strip():
|
707 |
try:
|
708 |
import requests
|
709 |
+
# Simplified URL handling
|
|
|
|
|
|
|
710 |
headers = {
|
711 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
712 |
}
|
713 |
response = requests.get(url, stream=True, headers=headers, timeout=10)
|
714 |
|
715 |
if response.status_code == 200:
|
716 |
+
# Process directly as in original code
|
717 |
+
image = Image.open(io.BytesIO(response.content)).convert("RGB")
|
718 |
+
uploaded_image = image
|
|
|
|
|
|
|
719 |
st.session_state.upload_method = "url"
|
|
|
720 |
else:
|
721 |
st.error(f"Failed to load image from URL: Status code {response.status_code}")
|
|
|
|
|
|
|
722 |
except Exception as e:
|
723 |
st.error(f"Error loading image from URL: {str(e)}")
|
|
|
|
|
724 |
|
725 |
# If we have an uploaded image, process it
|
726 |
if uploaded_image is not None:
|
|
|
745 |
try:
|
746 |
with st.spinner("Analyzing image with Xception model..."):
|
747 |
# Preprocess image for Xception
|
|
|
748 |
input_tensor, original_image, face_box = preprocess_image_xception(image)
|
749 |
|
750 |
+
if input_tensor is None:
|
751 |
+
st.error("Failed to preprocess image. Please try another image.")
|
752 |
+
st.stop()
|
753 |
+
|
754 |
# Get device and model
|
755 |
device = st.session_state.device
|
756 |
model = st.session_state.xception_model
|
|
|
760 |
|
761 |
# Move tensor to device
|
762 |
input_tensor = input_tensor.to(device)
|
|
|
763 |
|
764 |
# Forward pass with proper error handling
|
765 |
try:
|
766 |
with torch.no_grad():
|
|
|
767 |
logits = model(input_tensor)
|
|
|
768 |
probabilities = torch.softmax(logits, dim=1)[0]
|
|
|
769 |
pred_class = torch.argmax(probabilities).item()
|
770 |
confidence = probabilities[pred_class].item()
|
|
|
771 |
|
772 |
# Explicit class mapping - adjust if needed based on your model
|
773 |
pred_label = "Fake" if pred_class == 0 else "Real"
|
|
|
774 |
except Exception as e:
|
775 |
st.error(f"Error in model inference: {str(e)}")
|
776 |
import traceback
|
|
|
796 |
# GradCAM visualization with error handling
|
797 |
st.subheader("GradCAM Visualization")
|
798 |
try:
|
|
|
799 |
cam, overlay, comparison, detected_face_box = process_image_with_xception_gradcam(
|
800 |
image, model, device, pred_class
|
801 |
)
|