diff --git a/src/apps/posterize/pages/PosterizePage.tsx b/src/apps/posterize/pages/PosterizePage.tsx index 6829568..4dc8a87 100644 --- a/src/apps/posterize/pages/PosterizePage.tsx +++ b/src/apps/posterize/pages/PosterizePage.tsx @@ -2,6 +2,7 @@ import { useState } from 'react' import styles from './PosterizePage.module.css' import PosterizeNavigation from '../components/PosterizeNavigation' import ImageUploader from '../components/ImageUploader' +import { handleApiResponse } from '@/utils/apiUtils' interface BlurResponse { width: number @@ -55,12 +56,7 @@ const PosterizePage = () => { }), }) - if (!response.ok) { - const errorData = await response.json() - throw new Error(errorData.error || `HTTP error! status: ${response.status}`) - } - - const data: BlurResponse = await response.json() + const data: BlurResponse = await handleApiResponse(response) setBlurredImage(data) // Auto-scroll to result after successful blur on mobile diff --git a/src/apps/tracy/pages/TracyPage.tsx b/src/apps/tracy/pages/TracyPage.tsx index acdb399..10379a3 100644 --- a/src/apps/tracy/pages/TracyPage.tsx +++ b/src/apps/tracy/pages/TracyPage.tsx @@ -2,6 +2,7 @@ import { useState } from 'react' import styles from './TracyPage.module.css' import TracySceneEditor from '../components/TracySceneEditor' import TracyNavigation from '../components/TracyNavigation' +import { handleApiResponse } from '@/utils/apiUtils' interface SceneData { scene: { @@ -30,6 +31,20 @@ interface SceneData { } } +interface TracyResponse { + base64_png: string + width: number + height: number +} + +interface BlurResponse { + image_data: string + width: number + height: number + format: string + size_bytes: number +} + const TracyPage = () => { const [imageData, setImageData] = useState<{ base64_png: string; width: number; height: number } | null>(null) const [isLoading, setIsLoading] = useState(false) @@ -59,11 +74,7 @@ const TracyPage = () => { body: JSON.stringify(sceneData), }) - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - const data = await response.json() + const data = await handleApiResponse(response) setImageData(data) // Auto-scroll to result after successful render on mobile @@ -145,12 +156,7 @@ const TracyPage = () => { }), }) - if (!response.ok) { - const errorData = await response.json() - throw new Error(errorData.error || `HTTP error! status: ${response.status}`) - } - - const blurredData = await response.json() + const blurredData = await handleApiResponse(response) // Replace the current image with the blurred version setImageData({ diff --git a/src/utils/apiUtils.ts b/src/utils/apiUtils.ts new file mode 100644 index 0000000..78fc3e5 --- /dev/null +++ b/src/utils/apiUtils.ts @@ -0,0 +1,38 @@ +/** + * Handles API response parsing with better error handling for non-JSON responses + * Common in cases where request bodies exceed size limits and proxies return text + */ +export async function handleApiResponse(response: Response): Promise { + if (!response.ok) { + let errorMessage = `HTTP error! status: ${response.status}` + + try { + const errorData = await response.json() + errorMessage = errorData.error || errorMessage + } catch { + // If JSON parsing fails, try to get text response + try { + const errorText = await response.text() + // Check if it looks like a size/length error + if (errorText.toLowerCase().includes('too large') || + errorText.toLowerCase().includes('size') || + errorText.toLowerCase().includes('limit') || + response.status === 413) { + errorMessage = 'The image is too large. Please choose a smaller image or reduce its quality.' + } else if (errorText && errorText.length < 200) { + // Use the text if it's reasonably short + errorMessage = errorText + } + } catch { + // If both JSON and text parsing fail, use a user-friendly message + if (response.status === 413) { + errorMessage = 'The image is too large. Please choose a smaller image or reduce its quality.' + } + } + } + + throw new Error(errorMessage) + } + + return response.json() +} \ No newline at end of file