Skip to content

Commit eef133d

Browse files
committed
✨ The model ultimately renders an image from the S3 bucket.
1 parent 7a2e178 commit eef133d

File tree

8 files changed

+524
-18
lines changed

8 files changed

+524
-18
lines changed

backend/apps/file_management_app.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22
import re
3+
import base64
34
from http import HTTPStatus
45
from typing import List, Optional
56
from urllib.parse import urlparse, urlunparse, unquote, quote
@@ -149,7 +150,16 @@ async def process_files(
149150
@file_management_config_router.get("/download/{object_name:path}")
150151
async def get_storage_file(
151152
object_name: str = PathParam(..., description="File object name"),
152-
download: str = Query("ignore", description="How to get the file"),
153+
download: str = Query(
154+
"ignore",
155+
description=(
156+
"How to get the file: "
157+
"'ignore' (default, return file info), "
158+
"'stream' (return file stream), "
159+
"'redirect' (redirect to download URL), "
160+
"'base64' (return base64-encoded content for images)."
161+
),
162+
),
153163
expires: int = Query(3600, description="URL validity period (seconds)"),
154164
filename: Optional[str] = Query(None, description="Original filename for download (optional)")
155165
):
@@ -192,6 +202,28 @@ async def get_storage_file(
192202
"ETag": f'"{object_name}"',
193203
}
194204
)
205+
elif download == "base64":
206+
# Return base64 encoded file content (primarily for images)
207+
file_stream, content_type = await get_file_stream_impl(object_name=object_name)
208+
try:
209+
data = file_stream.read()
210+
except Exception as exc:
211+
logger.error("Failed to read file stream for base64: %s", str(exc))
212+
raise HTTPException(
213+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
214+
detail="Failed to read file content for base64 encoding",
215+
)
216+
217+
base64_content = base64.b64encode(data).decode("utf-8")
218+
return JSONResponse(
219+
status_code=HTTPStatus.OK,
220+
content={
221+
"success": True,
222+
"base64": base64_content,
223+
"content_type": content_type,
224+
"object_name": object_name,
225+
},
226+
)
195227
else:
196228
# return file metadata
197229
return await get_file_url_impl(object_name=object_name, expires=expires)

backend/services/image_service.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22
from http import HTTPStatus
3+
from urllib.parse import quote
34

45
import aiohttp
56

@@ -16,8 +17,9 @@
1617
async def proxy_image_impl(decoded_url: str):
1718
# Create session to call the data processing service
1819
async with aiohttp.ClientSession() as session:
19-
# Call the data processing service to load the image
20-
data_process_url = f"{DATA_PROCESS_SERVICE}/tasks/load_image?url={decoded_url}"
20+
# Encode URL for query string safety
21+
encoded_url = quote(decoded_url, safe="")
22+
data_process_url = f"{DATA_PROCESS_SERVICE}/tasks/load_image?url={encoded_url}"
2123

2224
async with session.get(data_process_url) as response:
2325
if response.status != HTTPStatus.OK:
@@ -29,6 +31,7 @@ async def proxy_image_impl(decoded_url: str):
2931
result = await response.json()
3032
return result
3133

34+
3235
def get_vlm_model(tenant_id: str):
3336
# Get the tenant config
3437
vlm_model_config = tenant_config_manager.get_model_config(

frontend/app/[locale]/chat/streaming/chatStreamFinalMessage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ export function ChatStreamFinalMessage({
272272
content={message.finalAnswer || message.content || ""}
273273
searchResults={message?.searchResults}
274274
onCitationHover={onCitationHover}
275+
// For historical messages, content already represents the final answer
276+
// when finalAnswer is not present, so enable S3 resolution in both cases.
277+
resolveS3Media={Boolean(message.finalAnswer || message.content)}
275278
/>
276279

277280
{/* Button group - only show when hideButtons is false and message is complete */}

frontend/app/[locale]/chat/streaming/chatStreamMessage.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ export function ChatStreamMessage({
231231
<MarkdownRenderer
232232
content={message.finalAnswer}
233233
searchResults={message?.searchResults}
234+
resolveS3Media
234235
/>
235236

236237
{/* Button group */}

0 commit comments

Comments
 (0)