nimbro-api 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nimbro_api-0.2.1/src/nimbro_api.egg-info → nimbro_api-0.2.2}/PKG-INFO +4 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/README.md +2 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/pyproject.toml +2 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/base/vlm_gist_base.py +32 -10
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/client/vlm_gist.py +6 -4
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/test/vlm_gist_test.py +6 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/dam_base.py +6 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/florence2_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/kosmos2_base.py +6 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/mmgroundingdino_base.py +6 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/sam2_realtime_base.py +6 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/utility.py +26 -6
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/__init__.py +2 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/chat_completions_base.py +14 -10
- nimbro_api-0.2.2/src/nimbro_api/api/openai/base/classify_base.py +224 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/embeddings_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/images_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/speech_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/transcriptions_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/translations_base.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/chat_completions.py +4 -3
- nimbro_api-0.2.2/src/nimbro_api/api/openai/client/classify.py +237 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/chat_completions_test.py +223 -169
- nimbro_api-0.2.2/src/nimbro_api/api/openai/test/classify_test.py +72 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/utility.py +5 -1
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/api.py +13 -17
- {nimbro_api-0.2.1 → nimbro_api-0.2.2/src/nimbro_api.egg-info}/PKG-INFO +4 -2
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api.egg-info/SOURCES.txt +3 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api.egg-info/requires.txt +1 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/LICENSE +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/setup.cfg +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/base/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/base/no_base.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/client/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/client/no.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/test/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/misc/test/no_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/dam.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/florence2.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/kosmos2.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/mmgroundingdino.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/client/sam2_realtime.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/dam_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/florence2_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/kosmos2_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/mmgroundingdino_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/test/sam2_realtime_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/embeddings.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/images.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/speech.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/transcriptions.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/client/translations.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/json_decode.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/pointing_molmo.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/pointing_qwen.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/reasoning_extract.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/string_normalize.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/string_strip.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/parser/template.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/embeddings_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/images_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/speech_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/transcriptions_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/test/translations_test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/voice_presets.json +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/client/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/client/client.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/client/client_base.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/core/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/core/core.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/core/core_base.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/fonts/DejaVuSans.ttf +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/fonts/LICENSE +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/assets/test.mp4 +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/assets/test.pdf +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/assets/test.png +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/assets/test.wav +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/test/test.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/__init__.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/io.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/logger.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/misc.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/string.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/utility/visual.py +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api.egg-info/dependency_links.txt +0 -0
- {nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nimbro-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A robust and flexible framework for API clients in Python
|
|
5
5
|
Author-email: Bastian Pätzold <paetzoldbastian@gmail.com>
|
|
6
6
|
Maintainer-email: Bastian Pätzold <paetzoldbastian@gmail.com>
|
|
@@ -42,6 +42,7 @@ Requires-Dist: pybase64; extra == "full"
|
|
|
42
42
|
Requires-Dist: numpy; extra == "full"
|
|
43
43
|
Requires-Dist: pillow; extra == "full"
|
|
44
44
|
Requires-Dist: opencv-python; extra == "full"
|
|
45
|
+
Requires-Dist: jsonschema; extra == "full"
|
|
45
46
|
Dynamic: license-file
|
|
46
47
|
|
|
47
48
|
# NimbRo API
|
|
@@ -65,6 +66,7 @@ Dynamic: license-file
|
|
|
65
66
|
| Client | API Docs |
|
|
66
67
|
|--------|----------|
|
|
67
68
|
| [nimbro_api.openai.ChatCompletions](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/chat_completions.py) | [Chat Completions](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create) |
|
|
69
|
+
| [nimbro_api.openai.Classify](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/classify.py) | [Classify](https://docs.vllm.ai/en/latest/models/pooling_models/classify) |
|
|
68
70
|
| [nimbro_api.openai.Embeddings](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/embeddings.py) | [Embeddings](https://developers.openai.com/api/reference/resources/embeddings/methods/create) |
|
|
69
71
|
| [nimbro_api.openai.Images](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/images.py) | [Images](https://developers.openai.com/api/reference/resources/images/methods/generate) |
|
|
70
72
|
| [nimbro_api.openai.Speech](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/speech.py) | [Speech](https://developers.openai.com/api/reference/resources/audio/subresources/speech/methods/create) |
|
|
@@ -123,7 +125,7 @@ Create and use a [ChatCompletions](https://github.com/ptzld/nimbro-api/blob/main
|
|
|
123
125
|
```python
|
|
124
126
|
import nimbro_api
|
|
125
127
|
# nimbro_api.set_api_key(name="OPENROUTER_API_KEY", key="supersecretkey") # alternatively, set API key here
|
|
126
|
-
client = nimbro_api.openai.ChatCompletions(endpoint="OpenRouter", model="google/gemini-
|
|
128
|
+
client = nimbro_api.openai.ChatCompletions(endpoint="OpenRouter", model="~google/gemini-flash-latest")
|
|
127
129
|
success, message, response = client.prompt(text="Tell me a joke!")
|
|
128
130
|
```
|
|
129
131
|
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
| Client | API Docs |
|
|
20
20
|
|--------|----------|
|
|
21
21
|
| [nimbro_api.openai.ChatCompletions](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/chat_completions.py) | [Chat Completions](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create) |
|
|
22
|
+
| [nimbro_api.openai.Classify](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/classify.py) | [Classify](https://docs.vllm.ai/en/latest/models/pooling_models/classify) |
|
|
22
23
|
| [nimbro_api.openai.Embeddings](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/embeddings.py) | [Embeddings](https://developers.openai.com/api/reference/resources/embeddings/methods/create) |
|
|
23
24
|
| [nimbro_api.openai.Images](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/images.py) | [Images](https://developers.openai.com/api/reference/resources/images/methods/generate) |
|
|
24
25
|
| [nimbro_api.openai.Speech](https://github.com/ptzld/nimbro-api/blob/main/src/nimbro_api/api/openai/client/speech.py) | [Speech](https://developers.openai.com/api/reference/resources/audio/subresources/speech/methods/create) |
|
|
@@ -77,7 +78,7 @@ Create and use a [ChatCompletions](https://github.com/ptzld/nimbro-api/blob/main
|
|
|
77
78
|
```python
|
|
78
79
|
import nimbro_api
|
|
79
80
|
# nimbro_api.set_api_key(name="OPENROUTER_API_KEY", key="supersecretkey") # alternatively, set API key here
|
|
80
|
-
client = nimbro_api.openai.ChatCompletions(endpoint="OpenRouter", model="google/gemini-
|
|
81
|
+
client = nimbro_api.openai.ChatCompletions(endpoint="OpenRouter", model="~google/gemini-flash-latest")
|
|
81
82
|
success, message, response = client.prompt(text="Tell me a joke!")
|
|
82
83
|
```
|
|
83
84
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nimbro-api"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "A robust and flexible framework for API clients in Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -58,6 +58,7 @@ full = [
|
|
|
58
58
|
"numpy",
|
|
59
59
|
"pillow",
|
|
60
60
|
"opencv-python",
|
|
61
|
+
"jsonschema",
|
|
61
62
|
]
|
|
62
63
|
|
|
63
64
|
[project.urls]
|
|
@@ -244,6 +244,8 @@ class VlmGistBase(ClientBase):
|
|
|
244
244
|
assert_type_value(obj=output_dir, type_or_value=[None, str], name="argument 'output_dir'")
|
|
245
245
|
if isinstance(output_dir, str):
|
|
246
246
|
output_dir = os.path.realpath(output_dir)
|
|
247
|
+
assert_log(expression=os.path.isfile(output_dir), message="Expected argument 'output_dir' to not exist or point to an existing folder but it points to an existing file.")
|
|
248
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
247
249
|
assert_log(expression=IMPORT_ERROR is None, message=f"Visual utilities are not available due to missing dependencies: {IMPORT_ERROR}")
|
|
248
250
|
if isinstance(result, str):
|
|
249
251
|
success, message, result = read_json(file_path=result, name="result", logger=self._logger)
|
|
@@ -305,20 +307,34 @@ class VlmGistBase(ClientBase):
|
|
|
305
307
|
if image is None:
|
|
306
308
|
images = [None] * num_images
|
|
307
309
|
else:
|
|
308
|
-
if
|
|
310
|
+
if isinstance(image, list):
|
|
311
|
+
assert_log(expression=len(image) == num_images, message=f"Expected argument 'image' provided as list to contain '{num_images}' item{'' if num_images == 1 else 's'} but got '{len(image)}'.")
|
|
312
|
+
elif os.path.isdir(image):
|
|
313
|
+
self._logger.debug("Argument 'image' provide as local path.")
|
|
314
|
+
path = image
|
|
315
|
+
image = sorted([os.path.join(image, item) for item in os.listdir(path) if os.path.isfile(os.path.join(path, item))])
|
|
316
|
+
self._logger.debug(f"Files in '{path}': {image}")
|
|
317
|
+
assert_log(expression=len(image) == num_images, message=f"Expected argument 'image' provided as path to contain '{num_images}' item{'' if num_images == 1 else 's'} but got '{len(image)}'.")
|
|
318
|
+
else:
|
|
319
|
+
assert_log(expression=num_images == 1, message=f"Expected argument 'image' to be provided as list containing '{num_images}' item{'' if num_images == 1 else 's'} but got 'str'.")
|
|
309
320
|
image = [image]
|
|
310
|
-
assert_log(expression=len(image) == num_images, message=f"Expected argument 'image' provided as list to contain '{num_images}' item{'' if num_images == 1 else 's'} but got '{len(image)}'.")
|
|
311
321
|
images = [None] * num_images
|
|
312
322
|
for i, item in enumerate(image):
|
|
313
323
|
if item is not None:
|
|
314
324
|
success, message, images[i], _ = parse_image_b64(image=item, logger=self._logger)
|
|
315
325
|
if not success:
|
|
316
326
|
self._logger.error(f"Failed to visualize result '{i + 1}' of '{num_images}': {message}")
|
|
327
|
+
|
|
317
328
|
# visualize
|
|
329
|
+
|
|
330
|
+
self._logger.info(f"Visualizing '{num_images}' result{'' if num_images == 1 else 's'}.")
|
|
331
|
+
|
|
318
332
|
visualizations = [None] * num_images
|
|
319
333
|
paths = [None] * num_images
|
|
320
334
|
|
|
321
335
|
for i, batch_item in enumerate(batch):
|
|
336
|
+
# TODO parallelize using batch.size and batch.threading
|
|
337
|
+
|
|
322
338
|
# validate data
|
|
323
339
|
if images[i] is None and image is not None:
|
|
324
340
|
continue
|
|
@@ -452,7 +468,7 @@ class VlmGistBase(ClientBase):
|
|
|
452
468
|
if sum(item is None for item in points) == len(points):
|
|
453
469
|
points = None
|
|
454
470
|
|
|
455
|
-
#
|
|
471
|
+
# draw
|
|
456
472
|
self._logger.debug(f"Visualizing result '{i + 1}' of '{num_images}'.")
|
|
457
473
|
tic = time.perf_counter()
|
|
458
474
|
if vis_args is None:
|
|
@@ -481,7 +497,6 @@ class VlmGistBase(ClientBase):
|
|
|
481
497
|
success, visual = cv2.imencode('.png', visual)
|
|
482
498
|
if success:
|
|
483
499
|
visual = visual.tobytes()
|
|
484
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
485
500
|
out_path = os.path.join(output_dir, f"{i}_{datetime.datetime.now().isoformat()[:23].replace('-', '_').replace(':', '_').replace('.', '_')}.png")
|
|
486
501
|
with open(out_path, "wb") as file:
|
|
487
502
|
file.write(visual)
|
|
@@ -495,7 +510,8 @@ class VlmGistBase(ClientBase):
|
|
|
495
510
|
|
|
496
511
|
# consolidate
|
|
497
512
|
num_success = sum(item is not None for item in visualizations)
|
|
498
|
-
success = num_success == num_images
|
|
513
|
+
# success = num_success == num_images
|
|
514
|
+
success = True # to prevent any retry attempts
|
|
499
515
|
if num_success == 0:
|
|
500
516
|
visualizations = None
|
|
501
517
|
paths = None
|
|
@@ -669,7 +685,10 @@ class VlmGistBase(ClientBase):
|
|
|
669
685
|
f"{('thread' if settings['batch']['style'] == 'threading' else 'process')}"
|
|
670
686
|
f"{'' if (settings['batch']['size'] if settings['batch']['size'] > 0 else len(image)) == 1 else ('s' if settings['batch']['style'] == 'threading' else 'es')}."
|
|
671
687
|
)
|
|
672
|
-
|
|
688
|
+
if settings['message_process']:
|
|
689
|
+
self._logger.info(message)
|
|
690
|
+
else:
|
|
691
|
+
self._logger.debug(message)
|
|
673
692
|
|
|
674
693
|
# full settings here instead of individual results
|
|
675
694
|
data['run']['type'] = "batch"
|
|
@@ -709,7 +728,7 @@ class VlmGistBase(ClientBase):
|
|
|
709
728
|
# extract batch results
|
|
710
729
|
successes = [res[0] for res in results]
|
|
711
730
|
failures = len(image) - sum(successes)
|
|
712
|
-
data['run']['success'] = failures == 0
|
|
731
|
+
data['run']['success'] = failures == 0
|
|
713
732
|
duration = time.perf_counter() - stamp_global
|
|
714
733
|
data['run']['message'] = (
|
|
715
734
|
f"Processed batch with '{len(image)}' image{'' if len(image) == 1 else 's'} using "
|
|
@@ -945,8 +964,8 @@ class VlmGistBase(ClientBase):
|
|
|
945
964
|
except json.JSONDecodeError:
|
|
946
965
|
pass
|
|
947
966
|
else:
|
|
948
|
-
data['structured_description']['logs'].append("
|
|
949
|
-
self._logger.
|
|
967
|
+
data['structured_description']['logs'].append("Parsed text response as JSON.")
|
|
968
|
+
self._logger.debug(data['structured_description']['logs'][-1])
|
|
950
969
|
break
|
|
951
970
|
else:
|
|
952
971
|
return False, "Failed to extract JSON from structured description received as string.", data
|
|
@@ -959,7 +978,10 @@ class VlmGistBase(ClientBase):
|
|
|
959
978
|
|
|
960
979
|
# structured description must be list
|
|
961
980
|
if not isinstance(description, list):
|
|
962
|
-
|
|
981
|
+
try:
|
|
982
|
+
return False, f"Expected structured description to be of type 'list' but got '{type(description).__name__}': {description}", data
|
|
983
|
+
except Exception:
|
|
984
|
+
return False, f"Expected structured description to be of type 'list' but got '{type(description).__name__}'.", data
|
|
963
985
|
|
|
964
986
|
# obtain image dimensions if required
|
|
965
987
|
dimensions = None
|
|
@@ -15,7 +15,7 @@ default_settings = {
|
|
|
15
15
|
'logger_severity': "warn",
|
|
16
16
|
'endpoint': "OpenRouter",
|
|
17
17
|
'model': "~google/gemini-pro-latest",
|
|
18
|
-
'reasoning_effort': "
|
|
18
|
+
'reasoning_effort': "minimal"
|
|
19
19
|
},
|
|
20
20
|
'system_prompt_role': "system",
|
|
21
21
|
'system_prompt': "You are a visual perception system that identifies and analyzes objects and other visible features in an image.",
|
|
@@ -35,7 +35,7 @@ default_settings = {
|
|
|
35
35
|
'logger_severity': "warn",
|
|
36
36
|
'endpoint': "OpenRouter",
|
|
37
37
|
'model': "~google/gemini-pro-latest",
|
|
38
|
-
'reasoning_effort': "
|
|
38
|
+
'reasoning_effort': "minimal"
|
|
39
39
|
},
|
|
40
40
|
'use_scene_description': False,
|
|
41
41
|
'system_prompt_role': "system",
|
|
@@ -194,11 +194,13 @@ class VlmGist(Client):
|
|
|
194
194
|
- logger_severity (str | None): Logger severity applied to each worker in ["debug", "info", "warn", "error", "fatal", "off"] (str) or `None` to adopt global process-wide severity.
|
|
195
195
|
- size (int): Number of parallel workers when processing a list of images (>= 0). Use `0` to spawn one worker per image.
|
|
196
196
|
- style (str): Parallelization backend used for batch processing. One of ["threading", "multiprocessing"].
|
|
197
|
-
- retry (bool | int): Retry behavior for a single worker
|
|
197
|
+
- retry (bool | int): Retry behavior for a single worker when passing multiple images.
|
|
198
|
+
Then, the global 'retry' setting is applied to the entire batch, triggering retry when at least one worker failed (after using up all their retry attempts).
|
|
198
199
|
retry (bool | int):
|
|
199
200
|
Defines retry behavior in failure cases, if the cause is eligible for retry:
|
|
200
201
|
- If `True`, retries indefinitely. If `False`, failure is returned immediately.
|
|
201
202
|
- Use a positive integer (`int`) to permit a specific number of retry attempts.
|
|
203
|
+
- Scope depends on mode (see 'batch.retry').
|
|
202
204
|
|
|
203
205
|
Raises:
|
|
204
206
|
UnrecoverableError: If 'name' is provided and does not refer to an existing setting.
|
|
@@ -239,7 +241,7 @@ class VlmGist(Client):
|
|
|
239
241
|
result (str | dict):
|
|
240
242
|
A result returned by `run()` (for either a single image or a batch), either as the dictionary (`dict`) itself or as a path (`str`) to a JSON file containing it.
|
|
241
243
|
image (str | bytes | list[str] | list[bytes] | None):
|
|
242
|
-
The image(s) corresponding to the result as a local path, URL, Base64 encoding (all `str`), or raw `bytes`.
|
|
244
|
+
The image(s) corresponding to the result as a local path to a file or a folder containing files, URL, Base64 encoding (all `str`), or raw `bytes`.
|
|
243
245
|
For a batch result, a `list` of length matching the batch size is required. If `None`, the image must be provided
|
|
244
246
|
within 'result', which requires the setting 'include_image' to have been enabled during the originating call to `run()`. Defaults to `None`.
|
|
245
247
|
output_dir (str | None):
|
|
@@ -578,7 +578,9 @@ def test_13_parallel_threads(n=10):
|
|
|
578
578
|
client = VlmGist(settings={
|
|
579
579
|
'batch.size': n,
|
|
580
580
|
'batch.style': "threading",
|
|
581
|
-
'
|
|
581
|
+
'batch.retry': 2,
|
|
582
|
+
'include_image': True,
|
|
583
|
+
'retry': False
|
|
582
584
|
})
|
|
583
585
|
images = [os.path.join(nimbro_api.__path__[0], "test", "assets", "test.png")] * n
|
|
584
586
|
success, message, result = client.run(image=images)
|
|
@@ -592,7 +594,9 @@ def test_14_parallel_multiprocessing(n=10):
|
|
|
592
594
|
client = VlmGist(settings={
|
|
593
595
|
'batch.size': n,
|
|
594
596
|
'batch.style': "multiprocessing",
|
|
595
|
-
'
|
|
597
|
+
'batch.retry': 2,
|
|
598
|
+
'include_image': False,
|
|
599
|
+
'retry': False
|
|
596
600
|
})
|
|
597
601
|
images = [os.path.join(nimbro_api.__path__[0], "test", "assets", "test.png")] * n
|
|
598
602
|
success, message, result = client.run(image=images)
|
{nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/dam_base.py
RENAMED
|
@@ -4,7 +4,7 @@ import time
|
|
|
4
4
|
from nimbro_api.client import ClientBase
|
|
5
5
|
from nimbro_api.utility.io import parse_image_b64
|
|
6
6
|
from nimbro_api.utility.api import get_api_key, validate_endpoint, post_request
|
|
7
|
-
from nimbro_api.utility.misc import assert_type_value, assert_keys, assert_log, format_obj
|
|
7
|
+
from nimbro_api.utility.misc import UnrecoverableError, assert_type_value, assert_keys, assert_log, format_obj
|
|
8
8
|
from nimbro_api.utility.string import is_base64
|
|
9
9
|
from ..utility import get_status, get_health, get_flavors, load, unload
|
|
10
10
|
|
|
@@ -183,7 +183,9 @@ class DamBase(ClientBase):
|
|
|
183
183
|
return False, message, None
|
|
184
184
|
|
|
185
185
|
# retrieve API key
|
|
186
|
-
api_key = self.get_api_key()
|
|
186
|
+
success, message, api_key = self.get_api_key()
|
|
187
|
+
if not success:
|
|
188
|
+
raise UnrecoverableError(message)
|
|
187
189
|
|
|
188
190
|
# construct payload
|
|
189
191
|
headers = {
|
|
@@ -192,6 +194,8 @@ class DamBase(ClientBase):
|
|
|
192
194
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
193
195
|
'X-Title': "NimbRo API"
|
|
194
196
|
}
|
|
197
|
+
if api_key == "":
|
|
198
|
+
del headers['Authorization']
|
|
195
199
|
data = {
|
|
196
200
|
'images': [image_file],
|
|
197
201
|
'prompts': [prompts],
|
|
@@ -157,7 +157,9 @@ class Florence2Base(ClientBase):
|
|
|
157
157
|
return False, message, None
|
|
158
158
|
|
|
159
159
|
# retrieve API key
|
|
160
|
-
api_key = self.get_api_key()
|
|
160
|
+
success, message, api_key = self.get_api_key()
|
|
161
|
+
if not success:
|
|
162
|
+
raise UnrecoverableError(message)
|
|
161
163
|
|
|
162
164
|
# construct payload
|
|
163
165
|
headers = {
|
|
@@ -166,6 +168,8 @@ class Florence2Base(ClientBase):
|
|
|
166
168
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
167
169
|
'X-Title': "NimbRo API"
|
|
168
170
|
}
|
|
171
|
+
if api_key == "":
|
|
172
|
+
del headers['Authorization']
|
|
169
173
|
data = {
|
|
170
174
|
'images': [image_file],
|
|
171
175
|
'prompts': [self._settings['prompt']],
|
{nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/nimbro_vision_servers/base/kosmos2_base.py
RENAMED
|
@@ -3,7 +3,7 @@ import time
|
|
|
3
3
|
from nimbro_api.client import ClientBase
|
|
4
4
|
from nimbro_api.utility.io import parse_image_b64
|
|
5
5
|
from nimbro_api.utility.api import get_api_key, validate_endpoint, post_request
|
|
6
|
-
from nimbro_api.utility.misc import assert_type_value, assert_log, format_obj
|
|
6
|
+
from nimbro_api.utility.misc import UnrecoverableError, assert_type_value, assert_log, format_obj
|
|
7
7
|
from ..utility import get_status, get_health, get_flavors, load, unload
|
|
8
8
|
|
|
9
9
|
class Kosmos2Base(ClientBase):
|
|
@@ -152,7 +152,9 @@ class Kosmos2Base(ClientBase):
|
|
|
152
152
|
return False, message, None
|
|
153
153
|
|
|
154
154
|
# retrieve API key
|
|
155
|
-
api_key = self.get_api_key()
|
|
155
|
+
success, message, api_key = self.get_api_key()
|
|
156
|
+
if not success:
|
|
157
|
+
raise UnrecoverableError(message)
|
|
156
158
|
|
|
157
159
|
# construct payload
|
|
158
160
|
headers = {
|
|
@@ -161,6 +163,8 @@ class Kosmos2Base(ClientBase):
|
|
|
161
163
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
162
164
|
'X-Title': "NimbRo API"
|
|
163
165
|
}
|
|
166
|
+
if api_key == "":
|
|
167
|
+
del headers['Authorization']
|
|
164
168
|
data = {
|
|
165
169
|
'images': [image_file],
|
|
166
170
|
'prompts': [self._settings['prompt']],
|
|
@@ -3,7 +3,7 @@ import time
|
|
|
3
3
|
from nimbro_api.client import ClientBase
|
|
4
4
|
from nimbro_api.utility.io import parse_image_b64
|
|
5
5
|
from nimbro_api.utility.api import get_api_key, validate_endpoint, post_request
|
|
6
|
-
from nimbro_api.utility.misc import assert_type_value, assert_log
|
|
6
|
+
from nimbro_api.utility.misc import UnrecoverableError, assert_type_value, assert_log
|
|
7
7
|
from ..utility import get_status, get_health, get_flavors, load, unload
|
|
8
8
|
|
|
9
9
|
class MmGroundingDinoBase(ClientBase):
|
|
@@ -148,7 +148,9 @@ class MmGroundingDinoBase(ClientBase):
|
|
|
148
148
|
return False, message, None
|
|
149
149
|
|
|
150
150
|
# retrieve API key
|
|
151
|
-
api_key = self.get_api_key()
|
|
151
|
+
success, message, api_key = self.get_api_key()
|
|
152
|
+
if not success:
|
|
153
|
+
raise UnrecoverableError(message)
|
|
152
154
|
|
|
153
155
|
# construct payload
|
|
154
156
|
headers = {
|
|
@@ -157,6 +159,8 @@ class MmGroundingDinoBase(ClientBase):
|
|
|
157
159
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
158
160
|
'X-Title': "NimbRo API"
|
|
159
161
|
}
|
|
162
|
+
if api_key == "":
|
|
163
|
+
del headers['Authorization']
|
|
160
164
|
data = {
|
|
161
165
|
'images': [image_file],
|
|
162
166
|
'inference_parameters': [{
|
|
@@ -4,7 +4,7 @@ import copy
|
|
|
4
4
|
from nimbro_api.client import ClientBase
|
|
5
5
|
from nimbro_api.utility.io import parse_image_b64
|
|
6
6
|
from nimbro_api.utility.api import get_api_key, validate_endpoint, post_request
|
|
7
|
-
from nimbro_api.utility.misc import assert_type_value, assert_log
|
|
7
|
+
from nimbro_api.utility.misc import UnrecoverableError, assert_type_value, assert_log
|
|
8
8
|
from ..utility import get_status, get_health, get_flavors, load, unload
|
|
9
9
|
|
|
10
10
|
class Sam2RealtimeBase(ClientBase):
|
|
@@ -187,7 +187,9 @@ class Sam2RealtimeBase(ClientBase):
|
|
|
187
187
|
self._logger.debug(message)
|
|
188
188
|
|
|
189
189
|
# retrieve API key
|
|
190
|
-
api_key = self.get_api_key()
|
|
190
|
+
success, message, api_key = self.get_api_key()
|
|
191
|
+
if not success:
|
|
192
|
+
raise UnrecoverableError(message)
|
|
191
193
|
|
|
192
194
|
# construct payload
|
|
193
195
|
headers = {
|
|
@@ -196,6 +198,8 @@ class Sam2RealtimeBase(ClientBase):
|
|
|
196
198
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
197
199
|
'X-Title': "NimbRo API"
|
|
198
200
|
}
|
|
201
|
+
if api_key == "":
|
|
202
|
+
del headers['Authorization']
|
|
199
203
|
if prompts is None:
|
|
200
204
|
data = {
|
|
201
205
|
'images': [image_file],
|
|
@@ -2,7 +2,7 @@ import datetime
|
|
|
2
2
|
|
|
3
3
|
import nimbro_api
|
|
4
4
|
from nimbro_api.utility.api import get_request, post_request
|
|
5
|
-
from nimbro_api.utility.misc import assert_type_value, assert_log
|
|
5
|
+
from nimbro_api.utility.misc import UnrecoverableError, assert_type_value, assert_log
|
|
6
6
|
|
|
7
7
|
def get_status(self, age):
|
|
8
8
|
# parse arguments
|
|
@@ -41,7 +41,9 @@ def get_status(self, age):
|
|
|
41
41
|
self._logger.debug(message)
|
|
42
42
|
|
|
43
43
|
# retrieve API key
|
|
44
|
-
api_key = self.get_api_key()
|
|
44
|
+
success, message, api_key = self.get_api_key()
|
|
45
|
+
if not success:
|
|
46
|
+
raise UnrecoverableError(message)
|
|
45
47
|
|
|
46
48
|
# use status API
|
|
47
49
|
headers = {
|
|
@@ -50,6 +52,8 @@ def get_status(self, age):
|
|
|
50
52
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
51
53
|
'X-Title': "NimbRo API"
|
|
52
54
|
}
|
|
55
|
+
if api_key == "":
|
|
56
|
+
del headers['Authorization']
|
|
53
57
|
success, message, response = get_request(
|
|
54
58
|
api_name="NimbRo-Vision-Servers API",
|
|
55
59
|
api_url=f"{self._endpoint['api_url']}/status",
|
|
@@ -132,7 +136,9 @@ def get_health(self, age):
|
|
|
132
136
|
self._logger.debug(message)
|
|
133
137
|
|
|
134
138
|
# retrieve API key
|
|
135
|
-
api_key = self.get_api_key()
|
|
139
|
+
success, message, api_key = self.get_api_key()
|
|
140
|
+
if not success:
|
|
141
|
+
raise UnrecoverableError(message)
|
|
136
142
|
|
|
137
143
|
# use health API
|
|
138
144
|
headers = {
|
|
@@ -141,6 +147,8 @@ def get_health(self, age):
|
|
|
141
147
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
142
148
|
'X-Title': "NimbRo API"
|
|
143
149
|
}
|
|
150
|
+
if api_key == "":
|
|
151
|
+
del headers['Authorization']
|
|
144
152
|
success, message, response = get_request(
|
|
145
153
|
api_name="NimbRo-Vision-Servers API",
|
|
146
154
|
api_url=f"{self._endpoint['api_url']}/health",
|
|
@@ -210,7 +218,9 @@ def get_flavors(self, age):
|
|
|
210
218
|
self._logger.debug(message)
|
|
211
219
|
|
|
212
220
|
# retrieve API key
|
|
213
|
-
api_key = self.get_api_key()
|
|
221
|
+
success, message, api_key = self.get_api_key()
|
|
222
|
+
if not success:
|
|
223
|
+
raise UnrecoverableError(message)
|
|
214
224
|
|
|
215
225
|
# use model_flavors API
|
|
216
226
|
headers = {
|
|
@@ -219,6 +229,8 @@ def get_flavors(self, age):
|
|
|
219
229
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
220
230
|
'X-Title': "NimbRo API"
|
|
221
231
|
}
|
|
232
|
+
if api_key == "":
|
|
233
|
+
del headers['Authorization']
|
|
222
234
|
success, message, response = get_request(
|
|
223
235
|
api_name="NimbRo-Vision-Servers API",
|
|
224
236
|
api_url=f"{self._endpoint['api_url']}/model_flavors",
|
|
@@ -295,7 +307,9 @@ def load(self, flavor=None, age=0):
|
|
|
295
307
|
self._logger.debug(message)
|
|
296
308
|
|
|
297
309
|
# retrieve API key
|
|
298
|
-
api_key = self.get_api_key()
|
|
310
|
+
success, message, api_key = self.get_api_key()
|
|
311
|
+
if not success:
|
|
312
|
+
raise UnrecoverableError(message)
|
|
299
313
|
|
|
300
314
|
# use load API
|
|
301
315
|
headers = {
|
|
@@ -304,6 +318,8 @@ def load(self, flavor=None, age=0):
|
|
|
304
318
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
305
319
|
'X-Title': "NimbRo API"
|
|
306
320
|
}
|
|
321
|
+
if api_key == "":
|
|
322
|
+
del headers['Authorization']
|
|
307
323
|
success, message, _ = post_request(
|
|
308
324
|
api_name="NimbRo-Vision-Servers API",
|
|
309
325
|
api_url=f"{self._endpoint['api_url']}/load",
|
|
@@ -339,7 +355,9 @@ def unload(self):
|
|
|
339
355
|
self._logger.debug(message)
|
|
340
356
|
|
|
341
357
|
# retrieve API key
|
|
342
|
-
api_key = self.get_api_key()
|
|
358
|
+
success, message, api_key = self.get_api_key()
|
|
359
|
+
if not success:
|
|
360
|
+
raise UnrecoverableError(message)
|
|
343
361
|
|
|
344
362
|
# use unload API
|
|
345
363
|
headers = {
|
|
@@ -348,6 +366,8 @@ def unload(self):
|
|
|
348
366
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
349
367
|
'X-Title': "NimbRo API"
|
|
350
368
|
}
|
|
369
|
+
if api_key == "":
|
|
370
|
+
del headers['Authorization']
|
|
351
371
|
success, message, response = post_request(
|
|
352
372
|
api_name="NimbRo-Vision-Servers API",
|
|
353
373
|
api_url=f"{self._endpoint['api_url']}/unload",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from .client.chat_completions import ChatCompletions
|
|
2
|
+
from .client.classify import Classify
|
|
2
3
|
from .client.embeddings import Embeddings
|
|
3
4
|
from .client.images import Images
|
|
4
5
|
from .client.speech import Speech
|
|
5
6
|
from .client.transcriptions import Transcriptions
|
|
6
7
|
from .client.translations import Translations
|
|
7
8
|
|
|
8
|
-
__all__ = ["ChatCompletions", "Embeddings", "Images", "Speech", "Transcriptions", "Translations"]
|
|
9
|
+
__all__ = ["ChatCompletions", "Classify", "Embeddings", "Images", "Speech", "Transcriptions", "Translations"]
|
{nimbro_api-0.2.1 → nimbro_api-0.2.2}/src/nimbro_api/api/openai/base/chat_completions_base.py
RENAMED
|
@@ -131,7 +131,7 @@ class ChatCompletionsBase(ClientBase):
|
|
|
131
131
|
|
|
132
132
|
# reasoning_effort
|
|
133
133
|
assert_type_value(obj=settings['reasoning_effort'], type_or_value=str, name="setting 'reasoning_effort'")
|
|
134
|
-
valid_values = ["", "none", "minimal", "low", "medium", "high"]
|
|
134
|
+
valid_values = ["", "none", "minimal", "low", "medium", "high", "xhigh", "max"]
|
|
135
135
|
assert_log(
|
|
136
136
|
expression=settings['reasoning_effort'] in valid_values,
|
|
137
137
|
message=f"Expected setting 'reasoning_effort' to be in {valid_values} but got '{settings['reasoning_effort']}'."
|
|
@@ -717,12 +717,11 @@ class ChatCompletionsBase(ClientBase):
|
|
|
717
717
|
|
|
718
718
|
def generate_completion(self, response_type):
|
|
719
719
|
# retrieve API key
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
except UnrecoverableError as e:
|
|
720
|
+
success, message, api_key = self.get_api_key()
|
|
721
|
+
if not success:
|
|
723
722
|
self._logger.debug("Restoring original context.")
|
|
724
723
|
self.messages = self.context_dump
|
|
725
|
-
raise
|
|
724
|
+
raise UnrecoverableError(message)
|
|
726
725
|
|
|
727
726
|
# validate connection
|
|
728
727
|
success, message = self.validate_connection(api_key=api_key)
|
|
@@ -1078,6 +1077,8 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1078
1077
|
'HTTP-Referer': "https://github.com/ptzld/nimbro-api",
|
|
1079
1078
|
'X-Title': "NimbRo API"
|
|
1080
1079
|
}
|
|
1080
|
+
if api_key == "":
|
|
1081
|
+
del headers['Authorization']
|
|
1081
1082
|
|
|
1082
1083
|
if self._endpoint['api_flavor'] == "openai":
|
|
1083
1084
|
data = {
|
|
@@ -1094,7 +1095,7 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1094
1095
|
'n': 1,
|
|
1095
1096
|
'stream': self._settings['stream']
|
|
1096
1097
|
}
|
|
1097
|
-
if self._settings['reasoning_effort']
|
|
1098
|
+
if self._settings['reasoning_effort'] != "":
|
|
1098
1099
|
data['reasoning_effort'] = self._settings['reasoning_effort']
|
|
1099
1100
|
if len(self.tools) == 0:
|
|
1100
1101
|
del data['tools']
|
|
@@ -1118,6 +1119,10 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1118
1119
|
'n': 1,
|
|
1119
1120
|
'stream': self._settings['stream']
|
|
1120
1121
|
}
|
|
1122
|
+
if self._settings['reasoning_effort'] != "":
|
|
1123
|
+
data['reasoning_effort'] = self._settings['reasoning_effort']
|
|
1124
|
+
if len(self.tools) > 0:
|
|
1125
|
+
data['parallel_tool_calls'] = self._settings['max_tool_calls'] is None or self._settings['max_tool_calls'] > 1
|
|
1121
1126
|
|
|
1122
1127
|
elif self._endpoint['api_flavor'] == "openrouter":
|
|
1123
1128
|
data = {
|
|
@@ -1133,7 +1138,7 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1133
1138
|
'n': 1,
|
|
1134
1139
|
'stream': self._settings['stream']
|
|
1135
1140
|
}
|
|
1136
|
-
if self._settings['reasoning_effort']
|
|
1141
|
+
if self._settings['reasoning_effort'] != "":
|
|
1137
1142
|
data['reasoning'] = {
|
|
1138
1143
|
'effort': self._settings['reasoning_effort'],
|
|
1139
1144
|
'exclude': False
|
|
@@ -1665,7 +1670,7 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1665
1670
|
|
|
1666
1671
|
# error case: tool-choice "use specific function" was violated
|
|
1667
1672
|
if len(self.tools) > 0 and response_type != "text" and response_type != "auto" and response_type != "always" and response_type != "json":
|
|
1668
|
-
if text != "":
|
|
1673
|
+
if text != "": # is text actually forbidden if the response still contains the demanded tool call?
|
|
1669
1674
|
is_valid = False
|
|
1670
1675
|
logs.append(f"Completion contains text content despite tool-choice being set to '{response_type}'.")
|
|
1671
1676
|
correction_messages[-1]['content'] = f"Your response must only contain a tool-call of '{response_type}' without additional text."
|
|
@@ -1764,8 +1769,7 @@ class ChatCompletionsBase(ClientBase):
|
|
|
1764
1769
|
logs.append(f"Completion contains a tool-call that violates the JSON Schema: {errors[0].message}")
|
|
1765
1770
|
reason = f"Your response contains a tool-call that violates the JSON Schema: {errors[0].message}"
|
|
1766
1771
|
else:
|
|
1767
|
-
|
|
1768
|
-
self._logger.warn(logs[-1], once=True)
|
|
1772
|
+
self._logger.warn("Tool-call cannot be validated against tool definitions because the 'jsonschema' module is not available.", once=True)
|
|
1769
1773
|
|
|
1770
1774
|
if success:
|
|
1771
1775
|
self._logger.debug("Tool-call is valid.")
|