-
Notifications
You must be signed in to change notification settings - Fork 3.2k
[VoiceLive]Add NoTurnDetection to disable turn detection #44610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -171,6 +171,21 @@ def default(self, o): # pylint: disable=too-many-return-statements | |||||
| r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" | ||||||
| ) | ||||||
|
|
||||||
| _ARRAY_ENCODE_MAPPING = { | ||||||
| "pipeDelimited": "|", | ||||||
| "spaceDelimited": " ", | ||||||
| "commaDelimited": ",", | ||||||
| "newlineDelimited": "\n", | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| def _deserialize_array_encoded(delimit: str, attr): | ||||||
| if isinstance(attr, str): | ||||||
| if attr == "": | ||||||
| return [] | ||||||
| return attr.split(delimit) | ||||||
| return attr | ||||||
|
|
||||||
|
|
||||||
| def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: | ||||||
| """Deserialize ISO-8601 formatted string into Datetime object. | ||||||
|
|
@@ -315,6 +330,8 @@ def _deserialize_int_as_str(attr): | |||||
| def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): | ||||||
| if annotation is int and rf and rf._format == "str": | ||||||
| return _deserialize_int_as_str | ||||||
| if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING: | ||||||
| return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format]) | ||||||
| if rf and rf._format: | ||||||
| return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) | ||||||
| return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore | ||||||
|
|
@@ -353,9 +370,39 @@ def __contains__(self, key: typing.Any) -> bool: | |||||
| return key in self._data | ||||||
|
|
||||||
| def __getitem__(self, key: str) -> typing.Any: | ||||||
| # If this key has been deserialized (for mutable types), we need to handle serialization | ||||||
| if hasattr(self, "_attr_to_rest_field"): | ||||||
| cache_attr = f"_deserialized_{key}" | ||||||
| if hasattr(self, cache_attr): | ||||||
| rf = _get_rest_field(getattr(self, "_attr_to_rest_field"), key) | ||||||
| if rf: | ||||||
| value = self._data.get(key) | ||||||
| if isinstance(value, (dict, list, set)): | ||||||
| # For mutable types, serialize and return | ||||||
| # But also update _data with serialized form and clear flag | ||||||
| # so mutations via this returned value affect _data | ||||||
| serialized = _serialize(value, rf._format) | ||||||
| # If serialized form is same type (no transformation needed), | ||||||
| # return _data directly so mutations work | ||||||
| if isinstance(serialized, type(value)) and serialized == value: | ||||||
| return self._data.get(key) | ||||||
| # Otherwise return serialized copy and clear flag | ||||||
| try: | ||||||
| object.__delattr__(self, cache_attr) | ||||||
| except AttributeError: | ||||||
| pass | ||||||
| # Store serialized form back | ||||||
| self._data[key] = serialized | ||||||
| return serialized | ||||||
| return self._data.__getitem__(key) | ||||||
|
|
||||||
| def __setitem__(self, key: str, value: typing.Any) -> None: | ||||||
| # Clear any cached deserialized value when setting through dictionary access | ||||||
| cache_attr = f"_deserialized_{key}" | ||||||
| try: | ||||||
| object.__delattr__(self, cache_attr) | ||||||
| except AttributeError: | ||||||
| pass | ||||||
| self._data.__setitem__(key, value) | ||||||
|
Comment on lines
372
to
406
|
||||||
|
|
||||||
| def __delitem__(self, key: str) -> None: | ||||||
|
|
@@ -483,6 +530,8 @@ def _is_model(obj: typing.Any) -> bool: | |||||
|
|
||||||
| def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements | ||||||
| if isinstance(o, list): | ||||||
| if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o): | ||||||
| return _ARRAY_ENCODE_MAPPING[format].join(o) | ||||||
| return [_serialize(x, format) for x in o] | ||||||
| if isinstance(o, dict): | ||||||
| return {k: _serialize(v, format) for k, v in o.items()} | ||||||
|
|
@@ -767,6 +816,17 @@ def _deserialize_sequence( | |||||
| return obj | ||||||
| if isinstance(obj, ET.Element): | ||||||
| obj = list(obj) | ||||||
| try: | ||||||
| if ( | ||||||
| isinstance(obj, str) | ||||||
| and isinstance(deserializer, functools.partial) | ||||||
| and isinstance(deserializer.args[0], functools.partial) | ||||||
| and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable | ||||||
| ): | ||||||
| # encoded string may be deserialized to sequence | ||||||
| return deserializer(obj) | ||||||
| except: # pylint: disable=bare-except | ||||||
|
||||||
| except: # pylint: disable=bare-except | |
| except (AttributeError, TypeError, IndexError): |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -821,13 +821,20 @@ def serialize_basic(cls, data, data_type, **kwargs): | |
| :param str data_type: Type of object in the iterable. | ||
| :rtype: str, int, float, bool | ||
| :return: serialized object | ||
| :raises TypeError: raise if data_type is not one of str, int, float, bool. | ||
| """ | ||
| custom_serializer = cls._get_custom_serializers(data_type, **kwargs) | ||
| if custom_serializer: | ||
| return custom_serializer(data) | ||
| if data_type == "str": | ||
| return cls.serialize_unicode(data) | ||
| return eval(data_type)(data) # nosec # pylint: disable=eval-used | ||
| if data_type == "int": | ||
| return int(data) | ||
| if data_type == "float": | ||
| return float(data) | ||
| if data_type == "bool": | ||
| return bool(data) | ||
| raise TypeError("Unknown basic data type: {}".format(data_type)) | ||
|
Comment on lines
+831
to
+837
|
||
|
|
||
| @classmethod | ||
| def serialize_unicode(cls, data): | ||
|
|
@@ -1757,7 +1764,7 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return | |
| :param str data_type: deserialization data type. | ||
| :return: Deserialized basic type. | ||
| :rtype: str, int, float or bool | ||
| :raises TypeError: if string format is not valid. | ||
| :raises TypeError: if string format is not valid or data_type is not one of str, int, float, bool. | ||
| """ | ||
| # If we're here, data is supposed to be a basic type. | ||
| # If it's still an XML node, take the text | ||
|
|
@@ -1783,7 +1790,11 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return | |
|
|
||
| if data_type == "str": | ||
| return self.deserialize_unicode(attr) | ||
| return eval(data_type)(attr) # nosec # pylint: disable=eval-used | ||
| if data_type == "int": | ||
| return int(attr) | ||
| if data_type == "float": | ||
| return float(attr) | ||
| raise TypeError("Unknown basic data type: {}".format(data_type)) | ||
|
Comment on lines
+1793
to
+1797
|
||
|
|
||
| @staticmethod | ||
| def deserialize_unicode(data): | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -777,17 +777,17 @@ class TurnDetection(_Model): | |||||
| """Top-level union for turn detection configuration. | ||||||
|
|
||||||
| You probably want to use the sub-classes and not this class directly. Known sub-classes are: | ||||||
| AzureSemanticVad, AzureSemanticVadEn, AzureSemanticVadMultilingual, ServerVad | ||||||
| AzureSemanticVad, AzureSemanticVadEn, AzureSemanticVadMultilingual, NoTurnDetection, ServerVad | ||||||
|
|
||||||
| :ivar type: Required. Known values are: "server_vad", "azure_semantic_vad", | ||||||
| :ivar type: Required. Known values are: "none", "server_vad", "azure_semantic_vad", | ||||||
| "azure_semantic_vad_en", and "azure_semantic_vad_multilingual". | ||||||
| :vartype type: str or ~azure.ai.voicelive.models.TurnDetectionType | ||||||
| """ | ||||||
|
|
||||||
| __mapping__: dict[str, _Model] = {} | ||||||
| type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) | ||||||
| """Required. Known values are: \"server_vad\", \"azure_semantic_vad\", \"azure_semantic_vad_en\", | ||||||
| and \"azure_semantic_vad_multilingual\".""" | ||||||
| """Required. Known values are: \"none\", \"server_vad\", \"azure_semantic_vad\", | ||||||
| \"azure_semantic_vad_en\", and \"azure_semantic_vad_multilingual\".""" | ||||||
|
|
||||||
| @overload | ||||||
| def __init__( | ||||||
|
|
@@ -2489,6 +2489,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: | |||||
| super().__init__(*args, **kwargs) | ||||||
|
|
||||||
|
|
||||||
| class NoTurnDetection(TurnDetection, discriminator="none"): | ||||||
| """No turn detection - client manages turn taking. | ||||||
|
|
||||||
| :ivar type: Required. | ||||||
| :vartype type: str or ~azure.ai.voicelive.models.NONE | ||||||
|
||||||
| :vartype type: str or ~azure.ai.voicelive.models.NONE | |
| :vartype type: str or ~azure.ai.voicelive.models.TurnDetectionType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new array encoding/decoding functionality (lines 174-188, 330-334, 532-534, 819-829) lacks test coverage. Since the repository has comprehensive test coverage for serialization (test_unit_serialization.py), tests should be added for the new delimited array formats (pipe, space, comma, newline) to ensure proper encoding and decoding.