Skip to content

Commit bb6c629

Browse files
Copilotbbbugg
andcommitted
Implement base64 fallback for image handling when no uploader is configured (#1)
* Initial plan * Implement base64 fallback for image handling when no uploader configured Co-authored-by: bbbugg <80089841+bbbugg@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bbbugg <80089841+bbbugg@users.noreply.github.com>
1 parent 4af17ce commit bb6c629

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

app/handler/response_handler.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from app.config.config import settings
1111
from app.utils.uploader import ImageUploaderFactory
1212
from app.log.logger import get_openai_logger
13+
from app.utils.helpers import is_image_upload_configured
1314

1415
logger = get_openai_logger()
1516

@@ -251,7 +252,22 @@ def _extract_result(
251252
return text, reasoning_content, tool_calls, thought
252253

253254

255+
def _has_inline_image_part(response: Dict[str, Any]) -> bool:
256+
try:
257+
for c in response.get("candidates", []):
258+
for p in c.get("content", {}).get("parts", []):
259+
if isinstance(p, dict) and ("inlineData" in p):
260+
return True
261+
except Exception:
262+
return False
263+
return False
264+
265+
254266
def _extract_image_data(part: dict) -> str:
267+
# Return empty string if no uploader is configured
268+
if not is_image_upload_configured():
269+
return ""
270+
255271
image_uploader = None
256272
if settings.UPLOAD_PROVIDER == "smms":
257273
image_uploader = ImageUploaderFactory.create(
@@ -322,6 +338,10 @@ def _extract_tool_calls(
322338
def _handle_gemini_stream_response(
323339
response: Dict[str, Any], model: str, stream: bool
324340
) -> Dict[str, Any]:
341+
# Early return raw Gemini response if no uploader configured and contains inline images
342+
if not is_image_upload_configured() and _has_inline_image_part(response):
343+
return response
344+
325345
text, reasoning_content, tool_calls, thought = _extract_result(
326346
response, model, stream=stream, gemini_format=True
327347
)
@@ -339,6 +359,10 @@ def _handle_gemini_stream_response(
339359
def _handle_gemini_normal_response(
340360
response: Dict[str, Any], model: str, stream: bool
341361
) -> Dict[str, Any]:
362+
# Early return raw Gemini response if no uploader configured and contains inline images
363+
if not is_image_upload_configured() and _has_inline_image_part(response):
364+
return response
365+
342366
text, reasoning_content, tool_calls, thought = _extract_result(
343367
response, model, stream=stream, gemini_format=True
344368
)

app/service/image/image_create_service.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from app.domain.openai_models import ImageGenerationRequest
1111
from app.log.logger import get_image_create_logger
1212
from app.utils.uploader import ImageUploaderFactory
13+
from app.utils.helpers import is_image_upload_configured
1314

1415
logger = get_image_create_logger()
1516

@@ -97,12 +98,15 @@ def generate_images(self, request: ImageGenerationRequest):
9798
image_data = generated_image.image.image_bytes
9899
image_uploader = None
99100

100-
if request.response_format == "b64_json":
101+
# Return base64 if explicitly requested or if no uploader is configured
102+
if request.response_format == "b64_json" or not is_image_upload_configured():
101103
base64_image = base64.b64encode(image_data).decode("utf-8")
102104
images_data.append(
103105
{"b64_json": base64_image, "revised_prompt": request.prompt}
104106
)
107+
continue
105108
else:
109+
# Upload to configured provider
106110
current_date = time.strftime("%Y/%m/%d")
107111
filename = f"{current_date}/{uuid.uuid4().hex[:8]}.png"
108112

app/utils/helpers.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import logging
1111

1212
from app.core.constants import DATA_URL_PATTERN, IMAGE_URL_PATTERN, VALID_IMAGE_RATIOS
13+
from app.config.config import settings
1314

1415
helper_logger = logging.getLogger("app.utils")
1516

@@ -189,3 +190,19 @@ def get_current_version(default_version: str = "0.0.0") -> str:
189190
except IOError as e:
190191
helper_logger.error(f"Error reading VERSION file ('{version_file}'): {e}. Using default version '{default_version}'.")
191192
return default_version
193+
194+
195+
def is_image_upload_configured() -> bool:
196+
"""Return True only if a valid upload provider is selected and all required settings for that provider are present."""
197+
provider = getattr(settings, "UPLOAD_PROVIDER", "").strip().lower()
198+
if provider == "smms":
199+
return bool(getattr(settings, "SMMS_SECRET_TOKEN", None))
200+
if provider == "picgo":
201+
return bool(getattr(settings, "PICGO_API_KEY", None))
202+
if provider == "cloudflare_imgbed":
203+
return all([
204+
getattr(settings, "CLOUDFLARE_IMGBED_URL", None),
205+
getattr(settings, "CLOUDFLARE_IMGBED_AUTH_CODE", None),
206+
getattr(settings, "CLOUDFLARE_IMGBED_UPLOAD_FOLDER", None),
207+
])
208+
return False

0 commit comments

Comments
 (0)