openai-sdk-helpers 0.1.1__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 +3 -0
- openai_sdk_helpers/files_api.py +373 -0
- openai_sdk_helpers/response/__init__.py +7 -3
- openai_sdk_helpers/response/base.py +166 -65
- openai_sdk_helpers/response/config.py +16 -1
- openai_sdk_helpers/response/files.py +392 -0
- openai_sdk_helpers/streamlit_app/app.py +83 -4
- openai_sdk_helpers/utils/__init__.py +18 -0
- openai_sdk_helpers/utils/encoding.py +189 -0
- openai_sdk_helpers/vector_storage/storage.py +50 -22
- {openai_sdk_helpers-0.1.1.dist-info → openai_sdk_helpers-0.1.2.dist-info}/METADATA +94 -1
- {openai_sdk_helpers-0.1.1.dist-info → openai_sdk_helpers-0.1.2.dist-info}/RECORD +15 -12
- {openai_sdk_helpers-0.1.1.dist-info → openai_sdk_helpers-0.1.2.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.1.1.dist-info → openai_sdk_helpers-0.1.2.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.1.1.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}"
|
|
@@ -12,7 +12,8 @@ import logging
|
|
|
12
12
|
import mimetypes
|
|
13
13
|
import os
|
|
14
14
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
15
|
-
from
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, cast
|
|
16
17
|
|
|
17
18
|
from openai import OpenAI
|
|
18
19
|
from openai.pagination import SyncPage
|
|
@@ -20,8 +21,10 @@ from openai.types.vector_store import VectorStore
|
|
|
20
21
|
from openai.types.vector_store_search_response import VectorStoreSearchResponse
|
|
21
22
|
from tqdm import tqdm
|
|
22
23
|
|
|
24
|
+
from ..config import OpenAISettings
|
|
25
|
+
from ..errors import ConfigurationError, VectorStorageError
|
|
23
26
|
from ..types import OpenAIClient
|
|
24
|
-
from ..utils import ensure_list, log
|
|
27
|
+
from ..utils import ensure_list, ensure_directory, log
|
|
25
28
|
from .types import VectorStorageFileInfo, VectorStorageFileStats
|
|
26
29
|
|
|
27
30
|
TEXT_MIME_PREFIXES = ("text/",)
|
|
@@ -119,26 +122,21 @@ class VectorStorage:
|
|
|
119
122
|
|
|
120
123
|
Raises
|
|
121
124
|
------
|
|
122
|
-
|
|
125
|
+
ConfigurationError
|
|
123
126
|
If no API key or embedding model can be resolved.
|
|
124
|
-
RuntimeError
|
|
125
|
-
If the OpenAI client cannot be initialized.
|
|
126
127
|
"""
|
|
127
|
-
self._client: OpenAIClient
|
|
128
128
|
if client is None:
|
|
129
|
-
api_key = os.getenv("OPENAI_API_KEY")
|
|
130
|
-
if api_key is None:
|
|
131
|
-
raise ValueError("OpenAI API key is required")
|
|
132
129
|
try:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
settings = OpenAISettings.from_env()
|
|
131
|
+
self._client = settings.create_client()
|
|
132
|
+
except ValueError as exc:
|
|
133
|
+
raise ConfigurationError(str(exc)) from exc
|
|
136
134
|
else:
|
|
137
135
|
self._client = client
|
|
138
136
|
|
|
139
137
|
self._model = model or os.getenv("OPENAI_MODEL")
|
|
140
138
|
if self._model is None:
|
|
141
|
-
raise
|
|
139
|
+
raise ConfigurationError("OpenAI model is required")
|
|
142
140
|
|
|
143
141
|
self._vector_storage = self._get_or_create_vector_storage(store_name)
|
|
144
142
|
self._existing_files: dict[str, str] | None = {}
|
|
@@ -234,6 +232,7 @@ class VectorStorage:
|
|
|
234
232
|
attributes: dict[str, str | float | bool] | None = None,
|
|
235
233
|
overwrite: bool = False,
|
|
236
234
|
refresh_cache: bool = False,
|
|
235
|
+
expires_after: int | None = None,
|
|
237
236
|
) -> VectorStorageFileInfo:
|
|
238
237
|
"""Upload a single file to the vector store.
|
|
239
238
|
|
|
@@ -255,6 +254,9 @@ class VectorStorage:
|
|
|
255
254
|
refresh_cache : bool, optional
|
|
256
255
|
When True, refresh the local cache of existing files before
|
|
257
256
|
checking for duplicates, by default False.
|
|
257
|
+
expires_after : int or None, optional
|
|
258
|
+
Number of seconds after which the file expires and is deleted.
|
|
259
|
+
If None and purpose is "user_data", defaults to 86400 (24 hours).
|
|
258
260
|
|
|
259
261
|
Returns
|
|
260
262
|
-------
|
|
@@ -265,6 +267,10 @@ class VectorStorage:
|
|
|
265
267
|
attributes = dict(attributes or {})
|
|
266
268
|
attributes["file_name"] = file_name
|
|
267
269
|
|
|
270
|
+
# Default to 24 hours expiration for user_data files
|
|
271
|
+
if expires_after is None and purpose == "user_data":
|
|
272
|
+
expires_after = 86400 # 24 hours in seconds
|
|
273
|
+
|
|
268
274
|
if refresh_cache:
|
|
269
275
|
self._existing_files = self._load_existing_files()
|
|
270
276
|
|
|
@@ -293,7 +299,9 @@ class VectorStorage:
|
|
|
293
299
|
file_data = handle.read()
|
|
294
300
|
|
|
295
301
|
file = self._client.files.create(
|
|
296
|
-
file=(
|
|
302
|
+
file=(file_name, file_data),
|
|
303
|
+
purpose=cast(Any, purpose), # Cast to avoid type error
|
|
304
|
+
expires_after=expires_after, # type: ignore
|
|
297
305
|
)
|
|
298
306
|
|
|
299
307
|
self._client.vector_stores.files.create(
|
|
@@ -322,6 +330,7 @@ class VectorStorage:
|
|
|
322
330
|
purpose: str = "assistants",
|
|
323
331
|
attributes: dict[str, str | float | bool] | None = None,
|
|
324
332
|
overwrite: bool = False,
|
|
333
|
+
expires_after: int | None = None,
|
|
325
334
|
) -> VectorStorageFileStats:
|
|
326
335
|
"""Upload files matching glob patterns using a thread pool.
|
|
327
336
|
|
|
@@ -340,6 +349,9 @@ class VectorStorage:
|
|
|
340
349
|
overwrite : bool, optional
|
|
341
350
|
When True, re-upload files even if files with the same name
|
|
342
351
|
exist, by default False.
|
|
352
|
+
expires_after : int or None, optional
|
|
353
|
+
Number of seconds after which files expire and are deleted.
|
|
354
|
+
If None and purpose is "user_data", defaults to 86400 (24 hours).
|
|
343
355
|
|
|
344
356
|
Returns
|
|
345
357
|
-------
|
|
@@ -376,6 +388,7 @@ class VectorStorage:
|
|
|
376
388
|
attributes=attributes,
|
|
377
389
|
overwrite=overwrite,
|
|
378
390
|
refresh_cache=False,
|
|
391
|
+
expires_after=expires_after,
|
|
379
392
|
): path
|
|
380
393
|
for path in all_paths
|
|
381
394
|
}
|
|
@@ -393,10 +406,10 @@ class VectorStorage:
|
|
|
393
406
|
return stats
|
|
394
407
|
|
|
395
408
|
def delete_file(self, file_id: str) -> VectorStorageFileInfo:
|
|
396
|
-
"""Delete a specific file from the vector store.
|
|
409
|
+
"""Delete a specific file from the vector store and OpenAI Files API.
|
|
397
410
|
|
|
398
|
-
Removes the file from the vector store
|
|
399
|
-
The operation is irreversible.
|
|
411
|
+
Removes the file from the vector store, then deletes it from OpenAI's
|
|
412
|
+
Files API storage. Updates the local cache. The operation is irreversible.
|
|
400
413
|
|
|
401
414
|
Parameters
|
|
402
415
|
----------
|
|
@@ -410,10 +423,22 @@ class VectorStorage:
|
|
|
410
423
|
"success" or "failed".
|
|
411
424
|
"""
|
|
412
425
|
try:
|
|
426
|
+
# First remove from vector store
|
|
413
427
|
self._client.vector_stores.files.delete(
|
|
414
428
|
vector_store_id=self._vector_storage.id, file_id=file_id
|
|
415
429
|
)
|
|
416
430
|
|
|
431
|
+
# Then delete the actual file from OpenAI storage
|
|
432
|
+
try:
|
|
433
|
+
self._client.files.delete(file_id)
|
|
434
|
+
log(f"Deleted file {file_id} from OpenAI Files API")
|
|
435
|
+
except Exception as file_delete_exc:
|
|
436
|
+
# Log but don't fail if file doesn't exist or can't be deleted
|
|
437
|
+
log(
|
|
438
|
+
f"Warning: Could not delete file {file_id} from Files API: {file_delete_exc}",
|
|
439
|
+
level=logging.WARNING,
|
|
440
|
+
)
|
|
441
|
+
|
|
417
442
|
to_remove = [k for k, v in self.existing_files.items() if v == file_id]
|
|
418
443
|
for key in to_remove:
|
|
419
444
|
del self.existing_files[key]
|
|
@@ -466,16 +491,19 @@ class VectorStorage:
|
|
|
466
491
|
def delete(self) -> None:
|
|
467
492
|
"""Delete the entire vector store and all associated files.
|
|
468
493
|
|
|
469
|
-
Removes each file
|
|
470
|
-
|
|
494
|
+
Removes each file from the vector store and deletes it from OpenAI's
|
|
495
|
+
Files API storage before deleting the store itself. The local cache
|
|
496
|
+
is cleared after deletion.
|
|
471
497
|
|
|
472
498
|
Warning: This operation is irreversible and will permanently delete
|
|
473
|
-
the vector store and all its files.
|
|
499
|
+
the vector store and all its files from OpenAI storage.
|
|
474
500
|
"""
|
|
475
501
|
try:
|
|
476
502
|
existing_files = list(self.existing_files.items())
|
|
477
503
|
for file_name, file_id in existing_files:
|
|
478
|
-
log(
|
|
504
|
+
log(
|
|
505
|
+
f"Deleting file {file_id} ({file_name}) from vector store and Files API"
|
|
506
|
+
)
|
|
479
507
|
self.delete_file(file_id)
|
|
480
508
|
|
|
481
509
|
self._client.vector_stores.delete(self._vector_storage.id)
|
|
@@ -505,7 +533,7 @@ class VectorStorage:
|
|
|
505
533
|
VectorStorageFileStats
|
|
506
534
|
Aggregated statistics describing the download results.
|
|
507
535
|
"""
|
|
508
|
-
|
|
536
|
+
ensure_directory(Path(output_dir))
|
|
509
537
|
|
|
510
538
|
try:
|
|
511
539
|
files = self._client.vector_stores.files.list(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openai-sdk-helpers
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
|
|
5
5
|
Author: openai-sdk-helpers maintainers
|
|
6
6
|
License: MIT
|
|
@@ -306,6 +306,99 @@ response.close()
|
|
|
306
306
|
|
|
307
307
|
## Advanced Usage
|
|
308
308
|
|
|
309
|
+
### Image and File Analysis
|
|
310
|
+
|
|
311
|
+
The `response` module automatically detects file types and handles them appropriately:
|
|
312
|
+
|
|
313
|
+
```python
|
|
314
|
+
from openai_sdk_helpers.response import BaseResponse
|
|
315
|
+
from openai_sdk_helpers import OpenAISettings
|
|
316
|
+
|
|
317
|
+
settings = OpenAISettings.from_env()
|
|
318
|
+
|
|
319
|
+
with BaseResponse(
|
|
320
|
+
name="analyzer",
|
|
321
|
+
instructions="You are a helpful assistant that can analyze files.",
|
|
322
|
+
tools=None,
|
|
323
|
+
output_structure=None,
|
|
324
|
+
tool_handlers={},
|
|
325
|
+
openai_settings=settings,
|
|
326
|
+
) as response:
|
|
327
|
+
# Automatic type detection - single files parameter
|
|
328
|
+
# Images are sent as base64-encoded images
|
|
329
|
+
# Documents are sent as base64-encoded file data
|
|
330
|
+
result = response.run_sync(
|
|
331
|
+
"Analyze these files",
|
|
332
|
+
files=["photo.jpg", "document.pdf"]
|
|
333
|
+
)
|
|
334
|
+
print(result)
|
|
335
|
+
|
|
336
|
+
# Single file - automatically detected
|
|
337
|
+
result = response.run_sync(
|
|
338
|
+
"What's in this image?",
|
|
339
|
+
files="photo.jpg" # Automatically detected as image
|
|
340
|
+
)
|
|
341
|
+
print(result)
|
|
342
|
+
|
|
343
|
+
# Use vector store for RAG (Retrieval-Augmented Generation)
|
|
344
|
+
result = response.run_sync(
|
|
345
|
+
"Search these documents",
|
|
346
|
+
files=["doc1.pdf", "doc2.pdf"],
|
|
347
|
+
use_vector_store=True # Enable RAG with vector stores
|
|
348
|
+
)
|
|
349
|
+
print(result)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**How It Works:**
|
|
353
|
+
|
|
354
|
+
- **Images** (jpg, png, gif, etc.) are automatically sent as base64-encoded images
|
|
355
|
+
- **Documents** (pdf, txt, xlsx, etc.) are sent as base64-encoded file data by default
|
|
356
|
+
- **Vector Stores** can optionally be used for documents when `use_vector_store=True`
|
|
357
|
+
- **Batch Processing** is automatically used for multiple files (>3) for efficient encoding
|
|
358
|
+
|
|
359
|
+
**Advanced File Processing:**
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from openai_sdk_helpers.response import process_files
|
|
363
|
+
|
|
364
|
+
# Process files directly with the dedicated module
|
|
365
|
+
vector_files, base64_files, images = process_files(
|
|
366
|
+
response,
|
|
367
|
+
files=["photo1.jpg", "photo2.jpg", "doc1.pdf", "doc2.pdf"],
|
|
368
|
+
use_vector_store=False,
|
|
369
|
+
batch_size=20, # Files per batch
|
|
370
|
+
max_workers=10, # Concurrent workers
|
|
371
|
+
)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Base64 Encoding Utilities:**
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
from openai_sdk_helpers.utils import (
|
|
378
|
+
encode_image,
|
|
379
|
+
encode_file,
|
|
380
|
+
is_image_file,
|
|
381
|
+
create_image_data_url,
|
|
382
|
+
create_file_data_url,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# Check if a file is an image
|
|
386
|
+
is_image_file("photo.jpg") # True
|
|
387
|
+
is_image_file("document.pdf") # False
|
|
388
|
+
|
|
389
|
+
# Encode an image to base64
|
|
390
|
+
base64_image = encode_image("photo.jpg")
|
|
391
|
+
|
|
392
|
+
# Create a data URL for an image
|
|
393
|
+
image_url, detail = create_image_data_url("photo.jpg", detail="high")
|
|
394
|
+
|
|
395
|
+
# Encode a file to base64
|
|
396
|
+
base64_file = encode_file("document.pdf")
|
|
397
|
+
|
|
398
|
+
# Create a data URL for a file
|
|
399
|
+
file_data = create_file_data_url("document.pdf")
|
|
400
|
+
```
|
|
401
|
+
|
|
309
402
|
### Custom Prompt Templates
|
|
310
403
|
|
|
311
404
|
Create custom Jinja2 templates for specialized agent behaviors:
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
openai_sdk_helpers/__init__.py,sha256=
|
|
1
|
+
openai_sdk_helpers/__init__.py,sha256=rsCoQ2yB8jJmWZxbXeXTf0dPcyWJIzghCS_CVPkBWKg,4626
|
|
2
2
|
openai_sdk_helpers/cli.py,sha256=J62XKPkGgYzYHKHfnkFy53Dp4rvBXf9cPEl1hrev3ZU,7400
|
|
3
3
|
openai_sdk_helpers/config.py,sha256=pjBzjYM9Fs4DQqwio387lBt_4IwWKct_VNZBSe-bMqg,10972
|
|
4
4
|
openai_sdk_helpers/context_manager.py,sha256=QqlrtenwKoz2krY0IzuToKdTX1HptUYtIEylxieybgY,6633
|
|
5
5
|
openai_sdk_helpers/deprecation.py,sha256=VF0VDDegawYhsu5f-vE6dop9ob-jv8egxsm0KsPvP9E,4753
|
|
6
6
|
openai_sdk_helpers/environment.py,sha256=RBYpRFamclaom07msipJ7jnnPkfVqjl1PRhDE5phZdg,1401
|
|
7
7
|
openai_sdk_helpers/errors.py,sha256=0TLrcpRXPBvk2KlrU5I1VAQl-sYy-d15h_SMDkEawvI,2757
|
|
8
|
+
openai_sdk_helpers/files_api.py,sha256=cNZObACSDX52kUvUOwanPyFqXcqRJe8D8_iB6AFqC2c,11810
|
|
8
9
|
openai_sdk_helpers/logging_config.py,sha256=JcR0FTWht1tYdwD-bXH835pr0JV0RwHfY3poruiZGHM,795
|
|
9
10
|
openai_sdk_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
11
|
openai_sdk_helpers/retry.py,sha256=J10oQYphfzDXm3BnLoXwxk7PAhN93TC2LQOv0VDGOwI,6533
|
|
@@ -31,15 +32,16 @@ openai_sdk_helpers/prompt/base.py,sha256=o-O5S-et4mE30_LkFPzL3o67Z_3KrLFG55gQDlL
|
|
|
31
32
|
openai_sdk_helpers/prompt/summarizer.jinja,sha256=jliSetWDISbql1EkWi1RB8-L_BXUg8JMkRRsPRHuzbY,309
|
|
32
33
|
openai_sdk_helpers/prompt/translator.jinja,sha256=SZhW8ipEzM-9IA4wyS_r2wIMTAclWrilmk1s46njoL0,291
|
|
33
34
|
openai_sdk_helpers/prompt/validator.jinja,sha256=6t8q_IdxFd3mVBGX6SFKNOert1Wo3YpTOji2SNEbbtE,547
|
|
34
|
-
openai_sdk_helpers/response/__init__.py,sha256=
|
|
35
|
-
openai_sdk_helpers/response/base.py,sha256=
|
|
36
|
-
openai_sdk_helpers/response/config.py,sha256=
|
|
35
|
+
openai_sdk_helpers/response/__init__.py,sha256=td-HTSPLtl1d5AkUFZ0rrUBUfsacM_CGtZQNj1_GWB8,1886
|
|
36
|
+
openai_sdk_helpers/response/base.py,sha256=rDzFBLl8hU1Rho7SfLUcd0eQLRpn1ZRAvvzXDqdWf0c,29854
|
|
37
|
+
openai_sdk_helpers/response/config.py,sha256=zZ4w2-GTSKg-7XgK6iUb5pDK-5aBFd2WkvbIjvegyHU,10871
|
|
38
|
+
openai_sdk_helpers/response/files.py,sha256=ANCoedNHXmpTXSaaGUvesAGq2DIUXT7SKZDCIJlXOv8,13226
|
|
37
39
|
openai_sdk_helpers/response/messages.py,sha256=G4V8a9gis4b8wFW5XnvBE0AHMX0FrkOzqiQ6FxigpnU,9145
|
|
38
40
|
openai_sdk_helpers/response/runner.py,sha256=Rf13cQGsR7sN9gA81Y5th1tfH2DCCAwQ6RMs3bVgjnk,4269
|
|
39
41
|
openai_sdk_helpers/response/tool_call.py,sha256=VYPvKUR-Ren0Y_nYS4jUSinhTyXKzFwQLxu-d3r_YuM,4506
|
|
40
42
|
openai_sdk_helpers/response/vector_store.py,sha256=MyHUu6P9ueNsd9erbBkyVqq3stLK6qVuehdvmFAHq9E,3074
|
|
41
43
|
openai_sdk_helpers/streamlit_app/__init__.py,sha256=RjJbnBDS5_YmAmxvaa3phB5u9UcXsXDEk_jMlY_pa5Q,793
|
|
42
|
-
openai_sdk_helpers/streamlit_app/app.py,sha256=
|
|
44
|
+
openai_sdk_helpers/streamlit_app/app.py,sha256=Sm9010pfrNlobF-ah-GKepob8slFEv1kEI_6-61R4O8,13690
|
|
43
45
|
openai_sdk_helpers/streamlit_app/config.py,sha256=EK6LWACo7YIkDko1oesvupOx56cTuWWnwnXRiu8EYbs,15986
|
|
44
46
|
openai_sdk_helpers/streamlit_app/streamlit_web_search.py,sha256=0RjB545dIvEeZiiLWM7C4CufbD3DITOWLZEVgxAL6mo,2812
|
|
45
47
|
openai_sdk_helpers/structure/__init__.py,sha256=QUvRdJMbKsumjwJdWq9ihfcOED4ZbJMBQbmA1nmYJVw,3339
|
|
@@ -57,20 +59,21 @@ openai_sdk_helpers/structure/plan/helpers.py,sha256=Vc6dBTMFrNWlsaCTpEImEIKjfFq4
|
|
|
57
59
|
openai_sdk_helpers/structure/plan/plan.py,sha256=LtfwWwZiHGe06nFCXSbT8p3x3w9hhI0wXS7hTeeWXvY,9663
|
|
58
60
|
openai_sdk_helpers/structure/plan/task.py,sha256=R2MInXiOWvs5zFGVOfAhVivRxXWTBp8NrmVpZ7aUmM8,4580
|
|
59
61
|
openai_sdk_helpers/structure/plan/types.py,sha256=7y9QEVdZreQUXV7n-R4RoNZzw5HeOVbJGWx9QkSfuNY,418
|
|
60
|
-
openai_sdk_helpers/utils/__init__.py,sha256=
|
|
62
|
+
openai_sdk_helpers/utils/__init__.py,sha256=UauMvn_2klGxXlz2Sn0RwJB1tIEkg7p0Qm9J8zaZFlM,3289
|
|
61
63
|
openai_sdk_helpers/utils/async_utils.py,sha256=9KbPEVfi6IXdbwkTUE0h5DleK8TI7I6P_VPL8UgUv98,3689
|
|
62
64
|
openai_sdk_helpers/utils/coercion.py,sha256=Pq1u7tAbD7kTZ84lK-7Fb9CyYKKKQt4fypG5BlSI6oQ,3774
|
|
63
65
|
openai_sdk_helpers/utils/deprecation.py,sha256=VF0VDDegawYhsu5f-vE6dop9ob-jv8egxsm0KsPvP9E,4753
|
|
66
|
+
openai_sdk_helpers/utils/encoding.py,sha256=oDtlNGZ5p-edXiHW76REs-0-8NXkQNReKJdj6sHLkt8,4615
|
|
64
67
|
openai_sdk_helpers/utils/json_utils.py,sha256=dpv0IPZp4WKL7HsDAQY2za820ukn0cre6kAv-pYw7P0,3141
|
|
65
68
|
openai_sdk_helpers/utils/output_validation.py,sha256=O9Adt-fxL5DtnMd1GuZ9E2YxX3yj4uzSZuBNKVH2GkI,12152
|
|
66
69
|
openai_sdk_helpers/utils/path_utils.py,sha256=qGGDpuDnY5EODOACzH23MYECQOE2rKhrQ3sbDvefwEg,1307
|
|
67
70
|
openai_sdk_helpers/utils/validation.py,sha256=ZjnZNOy5AoFlszRxarNol6YZwfgw6LnwPtkCekZmwAU,7826
|
|
68
71
|
openai_sdk_helpers/vector_storage/__init__.py,sha256=L5LxO09puh9_yBB9IDTvc1CvVkARVkHqYY1KX3inB4c,975
|
|
69
72
|
openai_sdk_helpers/vector_storage/cleanup.py,sha256=ImWIE-9lli-odD8qIARvmeaa0y8ZD4pYYP-kT0O3178,3552
|
|
70
|
-
openai_sdk_helpers/vector_storage/storage.py,sha256=
|
|
73
|
+
openai_sdk_helpers/vector_storage/storage.py,sha256=1juu3Qq6hy33afvVfQeI5A35fQzIPjVZumZ-aP_MxhU,23305
|
|
71
74
|
openai_sdk_helpers/vector_storage/types.py,sha256=jTCcOYMeOpZWvcse0z4T3MVs-RBOPC-fqWTBeQrgafU,1639
|
|
72
|
-
openai_sdk_helpers-0.1.
|
|
73
|
-
openai_sdk_helpers-0.1.
|
|
74
|
-
openai_sdk_helpers-0.1.
|
|
75
|
-
openai_sdk_helpers-0.1.
|
|
76
|
-
openai_sdk_helpers-0.1.
|
|
75
|
+
openai_sdk_helpers-0.1.2.dist-info/METADATA,sha256=3nSHx2-Xs0U_2Y1DHYcntmSkHmGEEYBonXbfFi2OINo,23557
|
|
76
|
+
openai_sdk_helpers-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
77
|
+
openai_sdk_helpers-0.1.2.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
|
|
78
|
+
openai_sdk_helpers-0.1.2.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
|
|
79
|
+
openai_sdk_helpers-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|