Skip to content

Latest commit

 

History

History
167 lines (132 loc) · 4.79 KB

File metadata and controls

167 lines (132 loc) · 4.79 KB

Image Upload Fix - Multipart Form Data

Problem

When uploading images to /answers/submit endpoint, you were getting:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 374: invalid start byte

Root Cause:

  • Frontend was sending multipart/form-data with binary image files
  • Backend was expecting JSON with base64-encoded image strings
  • When validation failed, FastAPI tried to encode the binary data as UTF-8, causing the error

Solution

Backend Changes (routes/answers.py)

Changed the /answers/submit endpoint from:

@router.post("/submit", response_model=APIResponse)
async def submit_answer(answer: AnswerSubmit, ...):

To:

@router.post("/submit", response_model=APIResponse)
async def submit_answer(
    question_id: str = Form(...),
    image: UploadFile = File(...),           # ← Accept binary file directly
    text_answer: str = Form(...),
    gps_latitude: float = Form(...),
    gps_longitude: float = Form(...),
    gps_accuracy: float = Form(...),
    verification_data: Optional[str] = Form(None),  # ← JSON as string
    authorization: str = Form(None),
    ...
):

Key Changes:

  1. ✅ Accept UploadFile for binary image data
  2. ✅ Accept form fields separately
  3. ✅ Parse verification_data as JSON string
  4. ✅ Convert binary to base64 inside endpoint
  5. ✅ Prevent binary data from appearing in error responses

Frontend Changes (submit-answer.js)

Changed from sending JSON with base64:

const payload = {
    question_id: questionId,
    image_base64: verificationData.imageBase64,  // ← Base64 string
    text_answer: answerText,
    ...
};
const response = await apiCall('/answers/submit', {
    method: 'POST',
    body: JSON.stringify(payload)
});

To sending multipart/form-data:

const formData = new FormData();
formData.append('question_id', questionId);
formData.append('image', verificationData.imageFile);  // ← Binary file object
formData.append('text_answer', answerText);
formData.append('gps_latitude', verificationData.gps.latitude);
formData.append('gps_longitude', verificationData.gps.longitude);
formData.append('gps_accuracy', verificationData.gps.accuracy);
formData.append('verification_data', JSON.stringify(verificationJson));

const response = await fetch(`${API_URL}/answers/submit`, {
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${token}`
    },
    body: formData  // ← Send FormData directly, no JSON.stringify
});

Key Changes:

  1. ✅ Store File object instead of base64 string
  2. ✅ Create FormData object for multipart
  3. ✅ Append file directly (not encoded)
  4. ✅ Use fetch() instead of apiCall() to handle FormData properly
  5. ✅ Browser automatically sets correct Content-Type header

Why This Fixes The Error

Before: Binary JPEG bytes → Tried to encode as JSON → UnicodeDecodeError After: Binary file → Stored directly in multipart form → No encoding issues

File Changes

Modified Files

  1. routes/answers.py - Updated /answers/submit endpoint
  2. frontend-html/submit-answer.js - Updated form submission logic

Added Imports

from fastapi import UploadFile, File, Form
import json

Testing

Run the test script:

python test_multipart_upload.py

Expected output:

🧪 Testing Multipart Form Upload for /answers/submit
==================================================

1️⃣ Getting authentication token...
✅ Token: eyJ0eXAiOiJKV1QiLc...

2️⃣ Finding a question nearby...
✅ Question ID: uuid-here

3️⃣ Creating test image...
✅ Test image created (100x100px JPEG)

4️⃣ Preparing multipart form data...
✅ Form data prepared

5️⃣ Sending POST request to /answers/submit...
Status Code: 200

✅ SUCCESS!
Answer ID: answer-uuid
Message: Answer submitted and queued for ML verification

Verification

The fix ensures:

  • ✅ Binary image data is NOT converted to text (avoids UnicodeDecodeError)
  • ✅ Multipart form data is properly handled
  • ✅ Verification data is correctly parsed as JSON
  • ✅ ML pipeline still processes images in background
  • ✅ Image is stored in Supabase and converted to base64 for ML processing

Deployment Notes

For friend's laptop (HTML/CSS/JS frontend):

  1. Update frontend-html/submit-answer.js (already done ✅)
  2. Ensure API_URL points to backend: http://localhost:8000 or deployed URL
  3. No build step needed - just serve HTML files

For React frontend (if using later): Similar changes needed in frontend/src/pages/SubmitAnswerPage.tsx

Rollback (if needed)

If you need to go back to base64 encoding:

  1. Revert routes/answers.py to accept AnswerSubmit model
  2. Change frontend to encode image as base64
  3. Frontend sends JSON.stringify(payload) with base64 image

Status: ✅ Fixed and ready to test!