Skip to content

Commit b1c8878

Browse files
authored
Merge branch 'main' into fix/pydantic-v2-swagger-ui
2 parents 079d94c + a19be12 commit b1c8878

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

src/google/adk/models/lite_llm.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,19 @@
8181
}
8282

8383
_SUPPORTED_FILE_CONTENT_MIME_TYPES = set(
84-
["application/pdf", "application/json", "text/plain"]
84+
["application/pdf", "application/json"]
8585
)
8686

8787

88+
def _decode_inline_text_data(raw_bytes: bytes) -> str:
89+
"""Decodes inline file bytes that represent textual content."""
90+
try:
91+
return raw_bytes.decode("utf-8")
92+
except UnicodeDecodeError:
93+
logger.debug("Falling back to latin-1 decoding for inline file bytes.")
94+
return raw_bytes.decode("latin-1", errors="replace")
95+
96+
8897
class ChatCompletionFileUrlObject(TypedDict, total=False):
8998
file_data: str
9099
file_id: str
@@ -371,6 +380,15 @@ def _get_content(
371380
and part.inline_data.data
372381
and part.inline_data.mime_type
373382
):
383+
if part.inline_data.mime_type.startswith("text/"):
384+
decoded_text = _decode_inline_text_data(part.inline_data.data)
385+
if len(parts) == 1:
386+
return decoded_text
387+
content_objects.append({
388+
"type": "text",
389+
"text": decoded_text,
390+
})
391+
continue
374392
base64_string = base64.b64encode(part.inline_data.data).decode("utf-8")
375393
data_uri = f"data:{part.inline_data.mime_type};base64,{base64_string}"
376394
# LiteLLM providers extract the MIME type from the data URI; avoid
@@ -397,7 +415,10 @@ def _get_content(
397415
"file": {"file_data": data_uri},
398416
})
399417
else:
400-
raise ValueError("LiteLlm(BaseLlm) does not support this content part.")
418+
raise ValueError(
419+
"LiteLlm(BaseLlm) does not support content part with MIME type "
420+
f"{part.inline_data.mime_type}."
421+
)
401422
elif part.file_data and part.file_data.file_uri:
402423
file_object: ChatCompletionFileUrlObject = {
403424
"file_id": part.file_data.file_uri,

tests/unittests/models/test_litellm.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,6 @@
109109
"data:application/json;base64,eyJoZWxsbyI6IndvcmxkIn0=",
110110
id="json",
111111
),
112-
pytest.param(
113-
b"hello world",
114-
"text/plain",
115-
"data:text/plain;base64,aGVsbG8gd29ybGQ=",
116-
id="txt",
117-
),
118112
]
119113

120114
STREAMING_MODEL_RESPONSE = [
@@ -1477,6 +1471,38 @@ def test_get_content_text():
14771471
assert content == "Test text"
14781472

14791473

1474+
def test_get_content_text_inline_data_single_part():
1475+
parts = [
1476+
types.Part.from_bytes(
1477+
data="Inline text".encode("utf-8"), mime_type="text/plain"
1478+
)
1479+
]
1480+
content = _get_content(parts)
1481+
assert content == "Inline text"
1482+
1483+
1484+
def test_get_content_text_inline_data_multiple_parts():
1485+
parts = [
1486+
types.Part.from_bytes(
1487+
data="First part".encode("utf-8"), mime_type="text/plain"
1488+
),
1489+
types.Part.from_text(text="Second part"),
1490+
]
1491+
content = _get_content(parts)
1492+
assert content[0]["type"] == "text"
1493+
assert content[0]["text"] == "First part"
1494+
assert content[1]["type"] == "text"
1495+
assert content[1]["text"] == "Second part"
1496+
1497+
1498+
def test_get_content_text_inline_data_fallback_decoding():
1499+
parts = [
1500+
types.Part.from_bytes(data=b"\xff", mime_type="text/plain"),
1501+
]
1502+
content = _get_content(parts)
1503+
assert content == "ÿ"
1504+
1505+
14801506
def test_get_content_image():
14811507
parts = [
14821508
types.Part.from_bytes(data=b"test_image_data", mime_type="image/png")

0 commit comments

Comments
 (0)