Spaces:
Build error
Build error
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 |
)
|