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.
@@ -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 typing import cast
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
- ValueError
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
- self._client = OpenAI(api_key=api_key)
134
- except Exception as exc:
135
- raise RuntimeError("Failed to initialize OpenAI client") from exc
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 ValueError("OpenAI model is required")
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=(file_path, file_data), purpose=purpose # type: ignore
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 and updates the local cache.
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 individually before deleting the store itself.
470
- The local cache is cleared after deletion.
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(f"Deleting file {file_id} ({file_name}) from vector store")
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
- os.makedirs(output_dir, exist_ok=True)
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.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=7UoioqeijT413TbjSjiAl64vKgJcQkY067OEpSDTdbU,4532
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=eoQF086o3OZYmVfJWXhSpYlPhQBb-VLDA5hvw7guLEc,1741
35
- openai_sdk_helpers/response/base.py,sha256=zxQQRKmmpzYPmw0aqIgwKry713gYmMLkA8jhSKIoyHY,26207
36
- openai_sdk_helpers/response/config.py,sha256=WheEWkTxNFHL54_yvFY3M0LclNmajwTiMftSFeAH2eI,10300
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=MBMtzZk3ywEccLHfy3K--pmKNGTBHw_PpQjIBeXzqtI,11099
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=N4jHd0QXaqU7aDBYraRoXas-MG1_CKm8uU1HdPVDS_k,2875
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=pRUPssHH_o-ydijGW8U9XC2Lu06HEO0KnrNd3X9_Qc0,21807
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.1.dist-info/METADATA,sha256=tFCRcJgKKEpRRDYFVYUSHwJ7GBKVtnK2h7x8MzopFMU,20927
73
- openai_sdk_helpers-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
- openai_sdk_helpers-0.1.1.dist-info/entry_points.txt,sha256=gEOD1ZeXe8d2OP-KzUlG-b_9D9yUZTCt-GFW3EDbIIY,63
75
- openai_sdk_helpers-0.1.1.dist-info/licenses/LICENSE,sha256=CUhc1NrE50bs45tcXF7OcTQBKEvkUuLqeOHgrWQ5jaA,1067
76
- openai_sdk_helpers-0.1.1.dist-info/RECORD,,
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,,