purushah commented on code in PR #1126:
URL: https://github.com/apache/flink-agents/pull/1126#discussion_r4049391504


##########
python/flink_agents/integrations/embedding_models/openai_embedding_model.py:
##########
@@ -31,6 +35,166 @@
 DEFAULT_REQUEST_TIMEOUT = 30.0
 DEFAULT_BASE_URL = "https://api.openai.com/v1";
 DEFAULT_MAX_RETRIES = 3
+DEFAULT_ENCODING_FORMAT = "float"
+# Upper bounds shared with the OpenAI chat models and the Java connection.
+MAX_OPENAI_TIMEOUT_SECONDS = 2_147_483.647
+MAX_OPENAI_RETRIES = 2_147_483_647
+MAX_DIMENSIONS = 2_147_483_647  # int range, as the Java connection requires
+ENCODING_FORMATS = frozenset({"float", "base64"})
+# Typed request fields; additional_kwargs may not repeat them.
+RESERVED_ADDITIONAL_KWARGS = frozenset(
+    {"model", "input", "encoding_format", "dimensions", "user"}
+)
+
+
+def _blank_to_none(value: Any, name: str) -> str | None:
+    """Require a string or None; blank strings are treated as absent, as in 
Java."""
+    if value is None:
+        return None
+    if not isinstance(value, str):
+        msg = f"{name} must be a string, got: {type(value).__name__}"
+        raise TypeError(msg)
+    return value if value.strip() else None
+
+
+def _check_additional_kwargs(additional_kwargs: Any) -> Dict[str, Any]:
+    """Require a mapping with non-blank string keys and no typed request 
field."""
+    if not isinstance(additional_kwargs, Mapping):
+        msg = (
+            f"additional_kwargs must be a map, got: 
{type(additional_kwargs).__name__}"
+        )
+        raise TypeError(msg)
+    # Per-call keys are stringified as Java's Map keys are (the setup field 
already
+    # requires string keys); null and blank keys are rejected in both 
languages.
+    if any(key is None or not str(key).strip() for key in additional_kwargs):
+        msg = "additional_kwargs contains an empty key."
+        raise ValueError(msg)
+    additional_kwargs = {str(key): value for key, value in 
additional_kwargs.items()}
+    collisions = sorted(RESERVED_ADDITIONAL_KWARGS & additional_kwargs.keys())
+    if collisions:
+        msg = (
+            f"additional_kwargs must not contain the typed request fields 
{collisions}; "
+            "set them through the corresponding setup argument instead."
+        )
+        raise ValueError(msg)
+    return additional_kwargs
+
+
+def _check_encoding_format(encoding_format: Any) -> str:
+    """Validate encoding_format; a blank value means the default, as in 
Java."""
+    if _blank_to_none(encoding_format, "encoding_format") is None:
+        return DEFAULT_ENCODING_FORMAT
+    if encoding_format not in ENCODING_FORMATS:
+        msg = (
+            f"encoding_format must be one of {sorted(ENCODING_FORMATS)}, "
+            f"got: {encoding_format!r}"
+        )
+        raise ValueError(msg)
+    return encoding_format
+
+
+def _check_model(model: Any) -> str:
+    if not isinstance(model, str) or not model.strip():
+        msg = "OpenAI embedding requires a non-empty 'model' (setup or 
per-call parameter)."
+        raise ValueError(msg)
+    return model
+
+
+def _check_dimensions(dimensions: Any) -> int | None:
+    """Accept a positive integer (an integral float counts, as in Java)."""
+    if dimensions is None:
+        return None
+    if isinstance(dimensions, float) and dimensions.is_integer():
+        dimensions = int(dimensions)
+    if (
+        isinstance(dimensions, bool)
+        or not isinstance(dimensions, int)
+        or not 0 < dimensions <= MAX_DIMENSIONS
+    ):
+        msg = f"dimensions must be a positive integer, got: {dimensions!r}"
+        raise ValueError(msg)
+    return dimensions
+
+
+def _usage_count(value: Any) -> int | None:
+    """A token count, or None when a compatible server sends something 
unusable."""
+    if isinstance(value, str) and value.strip().isdecimal():
+        return int(value)
+    if isinstance(value, bool):
+        return None
+    if isinstance(value, int):
+        return value
+    if isinstance(value, float) and value.is_integer():
+        return int(value)
+    return None
+
+
+def _decode_embedding(value: Any, *, base64_requested: bool) -> list[float]:
+    # With encoding_format="base64" the SDK hands the base64 string through 
untouched.
+    if isinstance(value, str):
+        if not base64_requested:
+            msg = "a string vector was returned although encoding_format was 
float"
+            raise TypeError(msg)
+        # validate=True so corrupted input raises instead of being silently 
truncated;
+        # unpadded input is accepted as Java's decoder accepts it.
+        padded = value + "=" * (-len(value) % 4)

Review Comment:
   Done: padding is now restored only for a completely unpadded value; 
partially padded input such as `AACAPw=` is passed to the decoder as-is and 
rejected (the same "malformed embedding" error as other corrupted vectors), 
matching Java's `Base64.getDecoder()`. A regression test for `AACAPw=` sits 
next to the unpadded `AACAPw` case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to