openai-sdk-helpers 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
- openai_sdk_helpers/__init__.py +44 -7
- openai_sdk_helpers/agent/base.py +5 -1
- openai_sdk_helpers/agent/coordination.py +4 -5
- openai_sdk_helpers/agent/runner.py +4 -1
- openai_sdk_helpers/agent/search/base.py +1 -0
- openai_sdk_helpers/agent/search/vector.py +2 -0
- openai_sdk_helpers/cli.py +265 -0
- openai_sdk_helpers/config.py +93 -2
- openai_sdk_helpers/context_manager.py +1 -1
- openai_sdk_helpers/deprecation.py +167 -0
- openai_sdk_helpers/environment.py +3 -2
- openai_sdk_helpers/errors.py +0 -12
- openai_sdk_helpers/files_api.py +373 -0
- openai_sdk_helpers/logging_config.py +24 -95
- openai_sdk_helpers/prompt/base.py +1 -1
- openai_sdk_helpers/response/__init__.py +7 -3
- openai_sdk_helpers/response/base.py +217 -147
- openai_sdk_helpers/response/config.py +16 -1
- openai_sdk_helpers/response/files.py +392 -0
- openai_sdk_helpers/response/messages.py +1 -0
- openai_sdk_helpers/retry.py +1 -1
- openai_sdk_helpers/streamlit_app/app.py +97 -7
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +15 -8
- openai_sdk_helpers/structure/base.py +6 -6
- openai_sdk_helpers/structure/plan/helpers.py +1 -0
- openai_sdk_helpers/structure/plan/task.py +7 -7
- openai_sdk_helpers/tools.py +116 -13
- openai_sdk_helpers/utils/__init__.py +100 -35
- openai_sdk_helpers/{async_utils.py → utils/async_utils.py} +5 -6
- openai_sdk_helpers/utils/coercion.py +138 -0
- openai_sdk_helpers/utils/deprecation.py +167 -0
- openai_sdk_helpers/utils/encoding.py +189 -0
- openai_sdk_helpers/utils/json_utils.py +98 -0
- openai_sdk_helpers/utils/output_validation.py +448 -0
- openai_sdk_helpers/utils/path_utils.py +46 -0
- openai_sdk_helpers/{validation.py → utils/validation.py} +7 -3
- openai_sdk_helpers/vector_storage/storage.py +59 -28
- {openai_sdk_helpers-0.1.0.dist-info → openai_sdk_helpers-0.1.2.dist-info}/METADATA +152 -3
- openai_sdk_helpers-0.1.2.dist-info/RECORD +79 -0
- openai_sdk_helpers-0.1.2.dist-info/entry_points.txt +2 -0
- openai_sdk_helpers/utils/core.py +0 -596
- openai_sdk_helpers-0.1.0.dist-info/RECORD +0 -69
- {openai_sdk_helpers-0.1.0.dist-info → openai_sdk_helpers-0.1.2.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.1.0.dist-info → openai_sdk_helpers-0.1.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Utilities for encoding files and images to base64.
|
|
2
|
+
|
|
3
|
+
This module provides helper functions for encoding images and files
|
|
4
|
+
to base64 format for use with OpenAI API's input_image and input_file
|
|
5
|
+
content types.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import base64
|
|
9
|
+
import mimetypes
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Literal
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_image_file(file_path: str | Path) -> bool:
|
|
15
|
+
"""Check if a file is an image based on its MIME type.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
file_path : str or Path
|
|
20
|
+
Path to the file to check.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
bool
|
|
25
|
+
True if the file is an image, False otherwise.
|
|
26
|
+
|
|
27
|
+
Examples
|
|
28
|
+
--------
|
|
29
|
+
>>> is_image_file("photo.jpg")
|
|
30
|
+
True
|
|
31
|
+
>>> is_image_file("document.pdf")
|
|
32
|
+
False
|
|
33
|
+
"""
|
|
34
|
+
mime_type = get_mime_type(file_path)
|
|
35
|
+
return mime_type.startswith("image/")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def encode_image(image_path: str | Path) -> str:
|
|
39
|
+
"""Encode an image file to base64.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
image_path : str or Path
|
|
44
|
+
Path to the image file to encode. Relative paths are converted
|
|
45
|
+
to absolute paths.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
str
|
|
50
|
+
Base64-encoded string representation of the image.
|
|
51
|
+
|
|
52
|
+
Raises
|
|
53
|
+
------
|
|
54
|
+
FileNotFoundError
|
|
55
|
+
If the image file does not exist.
|
|
56
|
+
IOError
|
|
57
|
+
If the file cannot be read.
|
|
58
|
+
|
|
59
|
+
Examples
|
|
60
|
+
--------
|
|
61
|
+
>>> base64_image = encode_image("photo.jpg")
|
|
62
|
+
>>> image_url = f"data:image/jpeg;base64,{base64_image}"
|
|
63
|
+
"""
|
|
64
|
+
path = Path(image_path).resolve()
|
|
65
|
+
if not path.exists():
|
|
66
|
+
raise FileNotFoundError(f"Image file not found: {image_path}")
|
|
67
|
+
|
|
68
|
+
with open(path, "rb") as image_file:
|
|
69
|
+
return base64.b64encode(image_file.read()).decode("utf-8")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def encode_file(file_path: str | Path) -> str:
|
|
73
|
+
"""Encode a file to base64.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
file_path : str or Path
|
|
78
|
+
Path to the file to encode. Relative paths are converted
|
|
79
|
+
to absolute paths.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
str
|
|
84
|
+
Base64-encoded string representation of the file.
|
|
85
|
+
|
|
86
|
+
Raises
|
|
87
|
+
------
|
|
88
|
+
FileNotFoundError
|
|
89
|
+
If the file does not exist.
|
|
90
|
+
IOError
|
|
91
|
+
If the file cannot be read.
|
|
92
|
+
|
|
93
|
+
Examples
|
|
94
|
+
--------
|
|
95
|
+
>>> base64_file = encode_file("document.pdf")
|
|
96
|
+
>>> file_data = f"data:application/pdf;base64,{base64_file}"
|
|
97
|
+
"""
|
|
98
|
+
path = Path(file_path).resolve()
|
|
99
|
+
if not path.exists():
|
|
100
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
101
|
+
|
|
102
|
+
with open(path, "rb") as f:
|
|
103
|
+
return base64.b64encode(f.read()).decode("utf-8")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_mime_type(file_path: str | Path) -> str:
|
|
107
|
+
"""Get the MIME type of a file.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
file_path : str or Path
|
|
112
|
+
Path to the file.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
str
|
|
117
|
+
MIME type of the file, or "application/octet-stream" if unknown.
|
|
118
|
+
|
|
119
|
+
Examples
|
|
120
|
+
--------
|
|
121
|
+
>>> get_mime_type("photo.jpg")
|
|
122
|
+
'image/jpeg'
|
|
123
|
+
>>> get_mime_type("document.pdf")
|
|
124
|
+
'application/pdf'
|
|
125
|
+
"""
|
|
126
|
+
path = Path(file_path)
|
|
127
|
+
mime_type, _ = mimetypes.guess_type(str(path))
|
|
128
|
+
return mime_type or "application/octet-stream"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def create_image_data_url(
|
|
132
|
+
image_path: str | Path, detail: Literal["low", "high", "auto"] = "auto"
|
|
133
|
+
) -> tuple[str, Literal["low", "high", "auto"]]:
|
|
134
|
+
"""Create a data URL for an image with MIME type detection.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
image_path : str or Path
|
|
139
|
+
Path to the image file.
|
|
140
|
+
detail : {"low", "high", "auto"}, default "auto"
|
|
141
|
+
Detail level for image processing.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
tuple[str, str]
|
|
146
|
+
A tuple containing the data URL and detail level.
|
|
147
|
+
|
|
148
|
+
Raises
|
|
149
|
+
------
|
|
150
|
+
FileNotFoundError
|
|
151
|
+
If the image file does not exist.
|
|
152
|
+
|
|
153
|
+
Examples
|
|
154
|
+
--------
|
|
155
|
+
>>> image_url, detail = create_image_data_url("photo.jpg", "high")
|
|
156
|
+
>>> # Use with ResponseInputImageContentParam
|
|
157
|
+
"""
|
|
158
|
+
mime_type = get_mime_type(image_path)
|
|
159
|
+
base64_image = encode_image(image_path)
|
|
160
|
+
data_url = f"data:{mime_type};base64,{base64_image}"
|
|
161
|
+
return data_url, detail
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def create_file_data_url(file_path: str | Path) -> str:
|
|
165
|
+
"""Create a data URL for a file with MIME type detection.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
file_path : str or Path
|
|
170
|
+
Path to the file.
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
str
|
|
175
|
+
Data URL with MIME type and base64-encoded content.
|
|
176
|
+
|
|
177
|
+
Raises
|
|
178
|
+
------
|
|
179
|
+
FileNotFoundError
|
|
180
|
+
If the file does not exist.
|
|
181
|
+
|
|
182
|
+
Examples
|
|
183
|
+
--------
|
|
184
|
+
>>> file_data = create_file_data_url("document.pdf")
|
|
185
|
+
>>> # Use with ResponseInputFileContentParam
|
|
186
|
+
"""
|
|
187
|
+
mime_type = get_mime_type(file_path)
|
|
188
|
+
base64_file = encode_file(file_path)
|
|
189
|
+
return f"data:{mime_type};base64,{base64_file}"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""JSON serialization helpers for helper types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import asdict, is_dataclass
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from .path_utils import check_filepath
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _to_jsonable(value: Any) -> Any:
|
|
16
|
+
"""Convert common helper types to JSON-serializable forms."""
|
|
17
|
+
from openai_sdk_helpers.structure.base import BaseStructure
|
|
18
|
+
|
|
19
|
+
if value is None:
|
|
20
|
+
return None
|
|
21
|
+
if isinstance(value, Enum):
|
|
22
|
+
return value.value
|
|
23
|
+
if isinstance(value, Path):
|
|
24
|
+
return str(value)
|
|
25
|
+
if isinstance(value, datetime):
|
|
26
|
+
return value.isoformat()
|
|
27
|
+
if is_dataclass(value) and not isinstance(value, type):
|
|
28
|
+
return {k: _to_jsonable(v) for k, v in asdict(value).items()}
|
|
29
|
+
if hasattr(value, "model_dump"):
|
|
30
|
+
model_dump = getattr(value, "model_dump")
|
|
31
|
+
return model_dump()
|
|
32
|
+
if isinstance(value, dict):
|
|
33
|
+
return {str(k): _to_jsonable(v) for k, v in value.items()}
|
|
34
|
+
if isinstance(value, (list, tuple, set)):
|
|
35
|
+
return [_to_jsonable(v) for v in value]
|
|
36
|
+
if isinstance(value, BaseStructure):
|
|
37
|
+
return value.model_dump()
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def coerce_jsonable(value: Any) -> Any:
|
|
42
|
+
"""Convert value into a JSON-serializable representation."""
|
|
43
|
+
from openai_sdk_helpers.response.base import BaseResponse
|
|
44
|
+
|
|
45
|
+
if value is None:
|
|
46
|
+
return None
|
|
47
|
+
if isinstance(value, BaseResponse):
|
|
48
|
+
return coerce_jsonable(value.messages.to_json())
|
|
49
|
+
if is_dataclass(value) and not isinstance(value, type):
|
|
50
|
+
return {key: coerce_jsonable(item) for key, item in asdict(value).items()}
|
|
51
|
+
coerced = _to_jsonable(value)
|
|
52
|
+
try:
|
|
53
|
+
json.dumps(coerced)
|
|
54
|
+
return coerced
|
|
55
|
+
except TypeError:
|
|
56
|
+
return str(coerced)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class customJSONEncoder(json.JSONEncoder):
|
|
60
|
+
"""JSON encoder for common helper types like enums and paths."""
|
|
61
|
+
|
|
62
|
+
def default(self, o: Any) -> Any: # noqa: D401
|
|
63
|
+
"""Return JSON-serializable representation of ``o``."""
|
|
64
|
+
return _to_jsonable(o)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class JSONSerializable:
|
|
68
|
+
"""Mixin for classes that can be serialized to JSON."""
|
|
69
|
+
|
|
70
|
+
def to_json(self) -> dict[str, Any]:
|
|
71
|
+
"""Return a JSON-compatible dict representation."""
|
|
72
|
+
if is_dataclass(self) and not isinstance(self, type):
|
|
73
|
+
return {k: _to_jsonable(v) for k, v in asdict(self).items()}
|
|
74
|
+
if hasattr(self, "model_dump"):
|
|
75
|
+
model_dump = getattr(self, "model_dump")
|
|
76
|
+
return _to_jsonable(model_dump())
|
|
77
|
+
return _to_jsonable(self.__dict__)
|
|
78
|
+
|
|
79
|
+
def to_json_file(self, filepath: str | Path) -> str:
|
|
80
|
+
"""Write serialized JSON data to a file path."""
|
|
81
|
+
target = Path(filepath)
|
|
82
|
+
check_filepath(fullfilepath=str(target))
|
|
83
|
+
with open(target, "w", encoding="utf-8") as handle:
|
|
84
|
+
json.dump(
|
|
85
|
+
self.to_json(),
|
|
86
|
+
handle,
|
|
87
|
+
indent=2,
|
|
88
|
+
ensure_ascii=False,
|
|
89
|
+
cls=customJSONEncoder,
|
|
90
|
+
)
|
|
91
|
+
return str(target)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
__all__ = [
|
|
95
|
+
"coerce_jsonable",
|
|
96
|
+
"JSONSerializable",
|
|
97
|
+
"customJSONEncoder",
|
|
98
|
+
]
|