openaivec 0.12.5__py3-none-any.whl → 1.0.10__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.
Files changed (46) hide show
  1. openaivec/__init__.py +13 -4
  2. openaivec/_cache/__init__.py +12 -0
  3. openaivec/_cache/optimize.py +109 -0
  4. openaivec/_cache/proxy.py +806 -0
  5. openaivec/{di.py → _di.py} +36 -12
  6. openaivec/_embeddings.py +203 -0
  7. openaivec/{log.py → _log.py} +2 -2
  8. openaivec/_model.py +113 -0
  9. openaivec/{prompt.py → _prompt.py} +95 -28
  10. openaivec/_provider.py +207 -0
  11. openaivec/_responses.py +511 -0
  12. openaivec/_schema/__init__.py +9 -0
  13. openaivec/_schema/infer.py +340 -0
  14. openaivec/_schema/spec.py +350 -0
  15. openaivec/_serialize.py +234 -0
  16. openaivec/{util.py → _util.py} +25 -85
  17. openaivec/pandas_ext.py +1496 -318
  18. openaivec/spark.py +485 -183
  19. openaivec/task/__init__.py +9 -7
  20. openaivec/task/customer_support/__init__.py +9 -15
  21. openaivec/task/customer_support/customer_sentiment.py +17 -15
  22. openaivec/task/customer_support/inquiry_classification.py +23 -22
  23. openaivec/task/customer_support/inquiry_summary.py +14 -13
  24. openaivec/task/customer_support/intent_analysis.py +21 -19
  25. openaivec/task/customer_support/response_suggestion.py +16 -16
  26. openaivec/task/customer_support/urgency_analysis.py +24 -25
  27. openaivec/task/nlp/__init__.py +4 -4
  28. openaivec/task/nlp/dependency_parsing.py +10 -12
  29. openaivec/task/nlp/keyword_extraction.py +11 -14
  30. openaivec/task/nlp/morphological_analysis.py +12 -14
  31. openaivec/task/nlp/named_entity_recognition.py +16 -18
  32. openaivec/task/nlp/sentiment_analysis.py +14 -11
  33. openaivec/task/nlp/translation.py +6 -9
  34. openaivec/task/table/__init__.py +2 -2
  35. openaivec/task/table/fillna.py +11 -11
  36. openaivec-1.0.10.dist-info/METADATA +399 -0
  37. openaivec-1.0.10.dist-info/RECORD +39 -0
  38. {openaivec-0.12.5.dist-info → openaivec-1.0.10.dist-info}/WHEEL +1 -1
  39. openaivec/embeddings.py +0 -172
  40. openaivec/model.py +0 -67
  41. openaivec/provider.py +0 -45
  42. openaivec/responses.py +0 -393
  43. openaivec/serialize.py +0 -225
  44. openaivec-0.12.5.dist-info/METADATA +0 -696
  45. openaivec-0.12.5.dist-info/RECORD +0 -33
  46. {openaivec-0.12.5.dist-info → openaivec-1.0.10.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,399 @@
1
+ Metadata-Version: 2.4
2
+ Name: openaivec
3
+ Version: 1.0.10
4
+ Summary: Generative mutation for tabular calculation
5
+ Project-URL: Homepage, https://microsoft.github.io/openaivec/
6
+ Project-URL: Repository, https://github.com/microsoft/openaivec
7
+ Author-email: Hiroki Mizukami <hmizukami@microsoft.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: llm,openai,openai-api,openai-python,pandas,pyspark
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: ipywidgets>=8.1.7
19
+ Requires-Dist: openai>=1.74.0
20
+ Requires-Dist: pandas>=2.2.3
21
+ Requires-Dist: tiktoken>=0.9.0
22
+ Requires-Dist: tqdm>=4.67.1
23
+ Provides-Extra: spark
24
+ Requires-Dist: pyspark>=3.5.5; extra == 'spark'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # openaivec
28
+
29
+ Transform pandas and Spark workflows with AI-powered text processing—batching, caching, and guardrails included. Built for OpenAI batch pipelines so you can group prompts, cut API overhead, and keep outputs aligned with your data.
30
+
31
+ [Contributor guidelines](AGENTS.md)
32
+
33
+ ## Quick start
34
+
35
+ ```bash
36
+ pip install openaivec
37
+ ```
38
+
39
+ ```python
40
+ import os
41
+ import pandas as pd
42
+ from openaivec import pandas_ext
43
+
44
+ # Auth: choose OpenAI or Azure OpenAI
45
+ os.environ["OPENAI_API_KEY"] = "your-api-key"
46
+ # Azure alternative:
47
+ # os.environ["AZURE_OPENAI_API_KEY"] = "your-azure-key"
48
+ # os.environ["AZURE_OPENAI_BASE_URL"] = "https://YOUR-RESOURCE-NAME.services.ai.azure.com/openai/v1/"
49
+ # os.environ["AZURE_OPENAI_API_VERSION"] = "preview"
50
+
51
+ pandas_ext.set_responses_model("gpt-5.1") # Optional override (use deployment name for Azure)
52
+
53
+ reviews = pd.Series([
54
+ "Great coffee and friendly staff.",
55
+ "Delivery was late and the package was damaged.",
56
+ ])
57
+
58
+ sentiment = reviews.ai.responses(
59
+ "Summarize sentiment in one short sentence.",
60
+ reasoning={"effort": "none"}, # Mirrors OpenAI SDK for reasoning models
61
+ )
62
+ print(sentiment.tolist())
63
+ # Output: ['Positive sentiment', 'Negative sentiment']
64
+ ```
65
+
66
+ **Try it live:** https://microsoft.github.io/openaivec/examples/pandas/
67
+
68
+ ## Benchmarks
69
+
70
+ Simple task benchmark from [benchmark.ipynb](https://github.com/microsoft/openaivec/blob/main/docs/examples/benchmark.ipynb) (100 numeric strings → integer literals, `Series.aio.responses`, model `gpt-5.1`):
71
+
72
+ | Mode | Settings | Time (s) |
73
+ | ------------------- | ----------------------------------------------- | -------- |
74
+ | Serial | `batch_size=1`, `max_concurrency=1` | ~141 |
75
+ | Batching | default `batch_size`, `max_concurrency=1` | ~15 |
76
+ | Concurrent batching | default `batch_size`, default `max_concurrency` | ~6 |
77
+
78
+ Batching alone removes most HTTP overhead, and letting batching overlap with concurrency cuts total runtime to a few seconds while still yielding one output per input.
79
+
80
+ <img alt="image" src="https://github.com/user-attachments/assets/8ace9bcd-bcae-4023-a37e-13082cd645e5" />
81
+
82
+ ## Contents
83
+
84
+ - [Why openaivec?](#why-openaivec)
85
+ - [Core Workflows](#core-workflows)
86
+ - [Using with Apache Spark UDFs](#using-with-apache-spark-udfs)
87
+ - [Building Prompts](#building-prompts)
88
+ - [Using with Microsoft Fabric](#using-with-microsoft-fabric)
89
+ - [Contributing](#contributing)
90
+ - [Additional Resources](#additional-resources)
91
+ - [Community](#community)
92
+
93
+ ## Why openaivec?
94
+
95
+ - Drop-in `.ai` and `.aio` accessors keep pandas analysts in familiar tooling.
96
+ - OpenAI batch-optimized: `BatchingMapProxy`/`AsyncBatchingMapProxy` coalesce requests, dedupe prompts, and keep column order stable.
97
+ - Smart batching (`BatchingMapProxy`/`AsyncBatchingMapProxy`) dedupes prompts, preserves order, and releases waiters on failure.
98
+ - Reasoning support mirrors the OpenAI SDK; structured outputs accept Pydantic `response_format`.
99
+ - Built-in caches and retries remove boilerplate; helpers reuse caches across pandas, Spark, and async flows.
100
+ - Spark UDFs and Microsoft Fabric guides move notebooks into production-scale ETL.
101
+ - Prompt tooling (`FewShotPromptBuilder`, `improve`) and the task library ship curated prompts with validated outputs.
102
+
103
+ # Overview
104
+
105
+ Vectorized OpenAI batch processing so you handle many inputs per call instead of one-by-one. Batching proxies dedupe inputs, enforce ordered outputs, and unblock waiters even on upstream errors. Cache helpers (`responses_with_cache`, Spark UDF builders) plug into the same layer so expensive prompts are reused across pandas, Spark, and async flows. Reasoning models honor SDK semantics. Requires Python 3.10+.
106
+
107
+ ## Core Workflows
108
+
109
+ ### Direct API usage
110
+
111
+ For maximum control over batch processing:
112
+
113
+ ```python
114
+ import os
115
+ from openai import OpenAI
116
+ from openaivec import BatchResponses
117
+
118
+ # Initialize the batch client
119
+ client = BatchResponses.of(
120
+ client=OpenAI(),
121
+ model_name="gpt-5.1",
122
+ system_message="Please answer only with 'xx family' and do not output anything else.",
123
+ # batch_size defaults to None (automatic optimization)
124
+ )
125
+
126
+ result = client.parse(
127
+ ["panda", "rabbit", "koala"],
128
+ reasoning={"effort": "none"},
129
+ )
130
+ print(result) # Expected output: ['bear family', 'rabbit family', 'koala family']
131
+ ```
132
+
133
+ 📓 **[Complete tutorial →](https://microsoft.github.io/openaivec/examples/pandas/)**
134
+
135
+ ### pandas integration (recommended)
136
+
137
+ The easiest way to get started with your DataFrames:
138
+
139
+ ```python
140
+ import os
141
+ import pandas as pd
142
+ from openaivec import pandas_ext
143
+
144
+ # Authentication Option 1: Environment variables (automatic detection)
145
+ os.environ["OPENAI_API_KEY"] = "your-api-key-here"
146
+ # Or for Azure OpenAI:
147
+ # os.environ["AZURE_OPENAI_API_KEY"] = "your-azure-key"
148
+ # os.environ["AZURE_OPENAI_BASE_URL"] = "https://YOUR-RESOURCE-NAME.services.ai.azure.com/openai/v1/"
149
+ # os.environ["AZURE_OPENAI_API_VERSION"] = "preview"
150
+
151
+ # Authentication Option 2: Custom client (optional)
152
+ # from openai import OpenAI, AsyncOpenAI
153
+ # pandas_ext.set_client(OpenAI())
154
+ # pandas_ext.set_async_client(AsyncOpenAI())
155
+
156
+ # Configure model (optional - defaults to gpt-5.1; use deployment name for Azure)
157
+ pandas_ext.set_responses_model("gpt-5.1")
158
+
159
+ # Create your data
160
+ df = pd.DataFrame({"name": ["panda", "rabbit", "koala"]})
161
+
162
+ # Add AI-powered columns
163
+ result = df.assign(
164
+ family=lambda df: df.name.ai.responses(
165
+ "What animal family? Answer with 'X family'",
166
+ reasoning={"effort": "none"},
167
+ ),
168
+ habitat=lambda df: df.name.ai.responses(
169
+ "Primary habitat in one word",
170
+ reasoning={"effort": "none"},
171
+ ),
172
+ fun_fact=lambda df: df.name.ai.responses(
173
+ "One interesting fact in 10 words or less",
174
+ reasoning={"effort": "none"},
175
+ ),
176
+ )
177
+ ```
178
+
179
+ | name | family | habitat | fun_fact |
180
+ | ------ | ---------------- | ------- | -------------------------- |
181
+ | panda | bear family | forest | Eats bamboo 14 hours daily |
182
+ | rabbit | rabbit family | meadow | Can see nearly 360 degrees |
183
+ | koala | marsupial family | tree | Sleeps 22 hours per day |
184
+
185
+ 📓 **[Interactive pandas examples →](https://microsoft.github.io/openaivec/examples/pandas/)**
186
+
187
+ ### Using with reasoning models
188
+
189
+ Reasoning models (o1-preview, o1-mini, o3-mini, etc.) work without special flags. `reasoning` mirrors the OpenAI SDK.
190
+
191
+ ```python
192
+ pandas_ext.set_responses_model("o1-mini") # Set your reasoning model
193
+
194
+ result = df.assign(
195
+ analysis=lambda df: df.text.ai.responses(
196
+ "Analyze this text step by step",
197
+ reasoning={"effort": "none"} # Optional: mirrors the OpenAI SDK argument
198
+ )
199
+ )
200
+ ```
201
+
202
+ You can omit `reasoning` to use the model defaults or tune it per request with the same shape (`dict` with effort) as the OpenAI SDK.
203
+
204
+ ### Using pre-configured tasks
205
+
206
+ For common text processing operations, openaivec provides ready-to-use tasks that eliminate the need to write custom prompts:
207
+
208
+ ```python
209
+ from openaivec.task import nlp, customer_support
210
+
211
+ text_df = pd.DataFrame({
212
+ "text": [
213
+ "Great product, fast delivery!",
214
+ "Need help with billing issue",
215
+ "How do I reset my password?"
216
+ ]
217
+ })
218
+
219
+ results = text_df.assign(
220
+ sentiment=lambda df: df.text.ai.task(
221
+ nlp.SENTIMENT_ANALYSIS,
222
+ reasoning={"effort": "none"},
223
+ ),
224
+ intent=lambda df: df.text.ai.task(
225
+ customer_support.INTENT_ANALYSIS,
226
+ reasoning={"effort": "none"},
227
+ ),
228
+ )
229
+
230
+ # Extract structured results into separate columns
231
+ extracted_results = results.ai.extract("sentiment")
232
+ ```
233
+
234
+ **Task categories:** Text analysis (`nlp.SENTIMENT_ANALYSIS`, `nlp.MULTILINGUAL_TRANSLATION`, `nlp.NAMED_ENTITY_RECOGNITION`, `nlp.KEYWORD_EXTRACTION`); Content classification (`customer_support.INTENT_ANALYSIS`, `customer_support.URGENCY_ANALYSIS`, `customer_support.INQUIRY_CLASSIFICATION`).
235
+
236
+ ### Asynchronous processing with `.aio`
237
+
238
+ High-throughput workloads use the `.aio` accessor for async versions of all operations:
239
+
240
+ ```python
241
+ import asyncio
242
+ import pandas as pd
243
+ from openaivec import pandas_ext
244
+
245
+ pandas_ext.set_responses_model("gpt-5.1")
246
+
247
+ df = pd.DataFrame({"text": [
248
+ "This product is amazing!",
249
+ "Terrible customer service",
250
+ "Good value for money",
251
+ "Not what I expected"
252
+ ] * 250}) # 1000 rows for demonstration
253
+
254
+ async def process_data():
255
+ return await df["text"].aio.responses(
256
+ "Analyze sentiment and classify as positive/negative/neutral",
257
+ reasoning={"effort": "none"}, # Required for gpt-5.1
258
+ max_concurrency=12 # Allow up to 12 concurrent requests
259
+ )
260
+
261
+ sentiments = asyncio.run(process_data())
262
+ ```
263
+
264
+ **Performance benefits:** Parallel processing with automatic batching/deduplication, built-in rate limiting and error handling, and memory-efficient streaming for large datasets.
265
+
266
+ ## Using with Apache Spark UDFs
267
+
268
+ Scale to enterprise datasets with distributed processing.
269
+
270
+ 📓 **[Spark tutorial →](https://microsoft.github.io/openaivec/examples/spark/)**
271
+
272
+ First, obtain a Spark session and configure authentication:
273
+
274
+ ```python
275
+ from pyspark.sql import SparkSession
276
+ from openaivec.spark import setup, setup_azure
277
+
278
+ spark = SparkSession.builder.getOrCreate()
279
+
280
+ # Option 1: Using OpenAI
281
+ setup(
282
+ spark,
283
+ api_key="your-openai-api-key",
284
+ responses_model_name="gpt-5.1", # Optional: set default model
285
+ embeddings_model_name="text-embedding-3-small" # Optional: set default model
286
+ )
287
+
288
+ # Option 2: Using Azure OpenAI
289
+ # setup_azure(
290
+ # spark,
291
+ # api_key="your-azure-openai-api-key",
292
+ # base_url="https://YOUR-RESOURCE-NAME.services.ai.azure.com/openai/v1/",
293
+ # api_version="preview",
294
+ # responses_model_name="my-gpt4-deployment", # Optional: set default deployment
295
+ # embeddings_model_name="my-embedding-deployment" # Optional: set default deployment
296
+ # )
297
+ ```
298
+
299
+ Create and register UDFs using the provided helpers:
300
+
301
+ ```python
302
+ from openaivec.spark import responses_udf, task_udf, embeddings_udf, count_tokens_udf, similarity_udf, parse_udf
303
+ from pydantic import BaseModel
304
+
305
+ spark.udf.register(
306
+ "extract_brand",
307
+ responses_udf(
308
+ instructions="Extract the brand name from the product. Return only the brand name.",
309
+ reasoning={"effort": "none"}, # Recommended with gpt-5.1
310
+ )
311
+ )
312
+
313
+ class Translation(BaseModel):
314
+ en: str
315
+ fr: str
316
+ ja: str
317
+
318
+ spark.udf.register(
319
+ "translate_struct",
320
+ responses_udf(
321
+ instructions="Translate the text to English, French, and Japanese.",
322
+ response_format=Translation,
323
+ reasoning={"effort": "none"}, # Recommended with gpt-5.1
324
+ )
325
+ )
326
+
327
+ spark.udf.register("embed_text", embeddings_udf())
328
+ spark.udf.register("count_tokens", count_tokens_udf())
329
+ spark.udf.register("compute_similarity", similarity_udf())
330
+ ```
331
+
332
+ ### Spark performance tips
333
+
334
+ - Duplicate detection automatically caches repeated inputs per partition for UDFs.
335
+ - `batch_size=None` auto-optimizes; set 32–128 for fixed sizes if needed.
336
+ - `max_concurrency` is per executor; total concurrency = executors × max_concurrency. Start with 4–12.
337
+ - Monitor rate limits and adjust concurrency to your OpenAI tier.
338
+
339
+ ## Building Prompts
340
+
341
+ Few-shot prompts improve LLM quality. `FewShotPromptBuilder` structures purpose, cautions, and examples; `improve()` iterates with OpenAI to remove contradictions.
342
+
343
+ ```python
344
+ from openaivec import FewShotPromptBuilder
345
+
346
+ prompt = (
347
+ FewShotPromptBuilder()
348
+ .purpose("Return the smallest category that includes the given word")
349
+ .caution("Never use proper nouns as categories")
350
+ .example("Apple", "Fruit")
351
+ .example("Car", "Vehicle")
352
+ .improve(max_iter=1) # optional
353
+ .build()
354
+ )
355
+ ```
356
+
357
+ 📓 **[Advanced prompting techniques →](https://microsoft.github.io/openaivec/examples/prompt/)**
358
+
359
+ ## Using with Microsoft Fabric
360
+
361
+ [Microsoft Fabric](https://www.microsoft.com/en-us/microsoft-fabric/) is a unified, cloud-based analytics platform. Add `openaivec` from PyPI in your Fabric environment, select it in your notebook, and use `openaivec.spark` like standard Spark.
362
+
363
+ ## Contributing
364
+
365
+ We welcome contributions! Please:
366
+
367
+ 1. Fork and branch from `main`.
368
+ 2. Add or update tests when you change code.
369
+ 3. Run formatting and tests before opening a PR.
370
+
371
+ Install dev deps:
372
+
373
+ ```bash
374
+ uv sync --all-extras --dev
375
+ ```
376
+
377
+ Lint and format:
378
+
379
+ ```bash
380
+ uv run ruff check . --fix
381
+ ```
382
+
383
+ Quick test pass:
384
+
385
+ ```bash
386
+ uv run pytest -m "not slow and not requires_api"
387
+ ```
388
+
389
+ ## Additional Resources
390
+
391
+ 📓 **[Customer feedback analysis →](https://microsoft.github.io/openaivec/examples/customer_analysis/)** - Sentiment analysis & prioritization
392
+ 📓 **[Survey data transformation →](https://microsoft.github.io/openaivec/examples/survey_transformation/)** - Unstructured to structured data
393
+ 📓 **[Asynchronous processing examples →](https://microsoft.github.io/openaivec/examples/aio/)** - High-performance async workflows
394
+ 📓 **[Auto-generate FAQs from documents →](https://microsoft.github.io/openaivec/examples/generate_faq/)** - Create FAQs using AI
395
+ 📓 **[All examples →](https://microsoft.github.io/openaivec/examples/pandas/)** - Complete collection of tutorials and use cases
396
+
397
+ ## Community
398
+
399
+ Join our Discord community for support and announcements: https://discord.gg/hXCS9J6Qek
@@ -0,0 +1,39 @@
1
+ openaivec/__init__.py,sha256=0RsOGIt4TMgPdjppWiz89W1gb1X4qM-4nWqFFi-eK8w,555
2
+ openaivec/_di.py,sha256=Cl1ZoNBlQsJL1bpzoMDl08uT9pZFVSlqOdLbS3_MwPE,11462
3
+ openaivec/_embeddings.py,sha256=2JWFUZdHR1dvPdWPT4nVSZo0_TAz4gr8oLR3EhhtUyE,8200
4
+ openaivec/_log.py,sha256=LHNs6AbJzM4weaRARZFroigxR6D148d7WSIMLk1IhbU,1439
5
+ openaivec/_model.py,sha256=ICu9T2puXBMIkTOZdO7XStHMdSSHe4LmLVovsNfXb64,2744
6
+ openaivec/_prompt.py,sha256=_fPATuWKaAdFD48Kuu0UQorlChA9mNZCDJx88bu_BuY,20626
7
+ openaivec/_provider.py,sha256=h-h2LwnaTDg-WquhD908upOSbMaMxV5OxoWWxfCdBTs,7952
8
+ openaivec/_responses.py,sha256=82P_iO3uB0IBL0BZY51ncR02lGxoVzLDjCybTvliMR8,20661
9
+ openaivec/_serialize.py,sha256=u2Om94Sc_QgJkTlW2BAGw8wd6gYDhc6IRqvS-qevFSs,8399
10
+ openaivec/_util.py,sha256=XfueAycVCQvgRLS7wF7e306b53lebORvZOBzbQjy4vE,6438
11
+ openaivec/pandas_ext.py,sha256=_y48qlG-npZsCCJJL1yev-yEU1YBZT83EiVl-lH0__o,87305
12
+ openaivec/spark.py,sha256=XosDAcbzhnaIGyHBJ-p_ZBVJALroOXOFTjWWNRpSG3o,35022
13
+ openaivec/_cache/__init__.py,sha256=IYUH5GKsJXuCX-k3XtT259rEz49EZm9KW2TIOTGW4uQ,314
14
+ openaivec/_cache/optimize.py,sha256=3nS8VehbS7iGC1tPDDQh-iAgyKHbVYmMbCRBWM77U_U,3827
15
+ openaivec/_cache/proxy.py,sha256=aVjH_hmJIIso6SetV_-Ct3VaOSG-n9Dpil7TttnbYkE,30556
16
+ openaivec/_schema/__init__.py,sha256=XUj3Jv6ZVDjyYzSmH6Q5lmDj-hBMfUg_eBNeZACXR6Q,368
17
+ openaivec/_schema/infer.py,sha256=VyvORgmpkcPa8pITClOJYjNzF4VzgSWe_n-9kFJVUjE,15644
18
+ openaivec/_schema/spec.py,sha256=7ZaC59w2Edemnao57XeZVO4qmSOA-Kus6TchZC3Dd5o,14821
19
+ openaivec/task/__init__.py,sha256=E82gfwhLOn1S8rgNZZAci3-H7bDXdGFM-cl1fpeN7_o,6154
20
+ openaivec/task/customer_support/__init__.py,sha256=KWfGyXPdZyfGdRH17x7hPpJJ1N2EP9PPhZx0fvBAwSI,884
21
+ openaivec/task/customer_support/customer_sentiment.py,sha256=ixSIPKZkqAtp4h2SaCDItNT4WNWSbuWVv4CQEY2insg,7375
22
+ openaivec/task/customer_support/inquiry_classification.py,sha256=O94-4csaqJmbpSOYX0Dvay6N3hbAbLhrWDRS-BG5qTM,9401
23
+ openaivec/task/customer_support/inquiry_summary.py,sha256=MqdrVsS5TmcArtU_G_C-ETse93-LxjsRBXTiizha6xU,6695
24
+ openaivec/task/customer_support/intent_analysis.py,sha256=fFvjfebe3luvshr9E63TSoKf5zgFeU3l2lSLBLOVOGM,7311
25
+ openaivec/task/customer_support/response_suggestion.py,sha256=Ewi0C_ytzKOZdQMRzkuXTuT8epFfeCekmh_c7F7vkqE,8105
26
+ openaivec/task/customer_support/urgency_analysis.py,sha256=tqQ4JvZpT4DN_A3Wn7DkLl1iwnRgV83yIICipQB-AqI,11330
27
+ openaivec/task/nlp/__init__.py,sha256=QoQ0egEK9IEh5hdrE07rZ_KCmC0gy_2FPrWJYRWiipY,512
28
+ openaivec/task/nlp/dependency_parsing.py,sha256=ijDXFRNC9h9Tn7kaDS9ecijdLkanoP-WIqA-QrtUFwY,2803
29
+ openaivec/task/nlp/keyword_extraction.py,sha256=TGcW-wXJwnUNT2p_tGyapyDCgzCPKGYLc2iNYq9dN8o,2790
30
+ openaivec/task/nlp/morphological_analysis.py,sha256=7mfpLPKnE5WWFKRwhpfh1PuvT-LcbRH7jiuUCLBcpYU,2379
31
+ openaivec/task/nlp/named_entity_recognition.py,sha256=iGvN8Z5iYynyOWgsBMxy_ztoivYKRsw-sBR8_SuwUcM,3015
32
+ openaivec/task/nlp/sentiment_analysis.py,sha256=P1AFazqmlE9Dy0OShNOXcY8X5rvsGg7X6CRysdqXORI,3063
33
+ openaivec/task/nlp/translation.py,sha256=IgTy0PQZVF_Q6qis60STim7Vd7rYPVTfTfwP_U1kAKk,6603
34
+ openaivec/task/table/__init__.py,sha256=kJz15WDJXjyC7UIHKBvlTRhCf347PCDMH5T5fONV2sU,83
35
+ openaivec/task/table/fillna.py,sha256=nMlXvlUvyWgM9DxJDeRX3M37jxlqg0MgRet1Ds3ni5Y,6571
36
+ openaivec-1.0.10.dist-info/METADATA,sha256=xJPQaqzzlN7rkL519vee4l8ZQRQfVwl9UxkXyzXGToM,14195
37
+ openaivec-1.0.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
38
+ openaivec-1.0.10.dist-info/licenses/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141
39
+ openaivec-1.0.10.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
openaivec/embeddings.py DELETED
@@ -1,172 +0,0 @@
1
- import asyncio
2
- from dataclasses import dataclass, field
3
- from logging import Logger, getLogger
4
- from typing import List
5
-
6
- import numpy as np
7
- from numpy.typing import NDArray
8
- from openai import AsyncOpenAI, OpenAI, RateLimitError
9
-
10
- from .log import observe
11
- from .util import backoff, backoff_async, map, map_async
12
-
13
- __all__ = [
14
- "BatchEmbeddings",
15
- "AsyncBatchEmbeddings",
16
- ]
17
-
18
- _LOGGER: Logger = getLogger(__name__)
19
-
20
-
21
- @dataclass(frozen=True)
22
- class BatchEmbeddings:
23
- """Thin wrapper around the OpenAI /embeddings endpoint.
24
-
25
- Attributes:
26
- client: An already‑configured ``openai.OpenAI`` client.
27
- model_name: The model identifier, e.g. ``"text-embedding-3-small"``.
28
- """
29
-
30
- client: OpenAI
31
- model_name: str
32
-
33
- @observe(_LOGGER)
34
- @backoff(exception=RateLimitError, scale=15, max_retries=8)
35
- def _embed_chunk(self, inputs: List[str]) -> List[NDArray[np.float32]]:
36
- """Embed one minibatch of sentences.
37
-
38
- This private helper is the unit of work used by the map/parallel
39
- utilities. Exponential back‑off is applied automatically when
40
- ``openai.RateLimitError`` is raised.
41
-
42
- Args:
43
- inputs (List[str]): Input strings to be embedded. Duplicates are allowed; the
44
- implementation may decide to de‑duplicate internally.
45
-
46
- Returns:
47
- List of embedding vectors with the same ordering as *sentences*.
48
- """
49
- responses = self.client.embeddings.create(input=inputs, model=self.model_name)
50
- return [np.array(d.embedding, dtype=np.float32) for d in responses.data]
51
-
52
- @observe(_LOGGER)
53
- def create(self, inputs: List[str], batch_size: int) -> List[NDArray[np.float32]]:
54
- """See ``VectorizedEmbeddings.create`` for contract details.
55
-
56
- The call is internally delegated to either ``map_unique_minibatch`` or
57
- its parallel counterpart depending on *is_parallel*.
58
-
59
- Args:
60
- inputs (List[str]): A list of input strings. Duplicates are allowed; the
61
- implementation may decide to de‑duplicate internally.
62
- batch_size (int): Maximum number of sentences to be sent to the underlying
63
- model in one request.
64
-
65
- Returns:
66
- A list of ``np.ndarray`` objects (dtype ``float32``) where each entry
67
- is the embedding of the corresponding sentence in *sentences*.
68
-
69
- Raises:
70
- openai.RateLimitError: Propagated if retries are exhausted.
71
- """
72
- return map(inputs, self._embed_chunk, batch_size)
73
-
74
-
75
- @dataclass(frozen=True)
76
- class AsyncBatchEmbeddings:
77
- """Thin wrapper around the OpenAI /embeddings endpoint using async operations.
78
-
79
- This class provides an asynchronous interface for generating embeddings using
80
- OpenAI models. It manages concurrency, handles rate limits automatically,
81
- and efficiently processes batches of inputs, including de-duplication.
82
-
83
- Example:
84
- ```python
85
- import asyncio
86
- import numpy as np
87
- from openai import AsyncOpenAI
88
- from openaivec.aio.embeddings import AsyncBatchEmbeddings
89
-
90
- # Assuming openai_async_client is an initialized AsyncOpenAI client
91
- openai_async_client = AsyncOpenAI() # Replace with your actual client initialization
92
-
93
- embedder = AsyncBatchEmbeddings(
94
- client=openai_async_client,
95
- model_name="text-embedding-3-small",
96
- max_concurrency=8 # Limit concurrent requests
97
- )
98
- texts = ["This is the first document.", "This is the second document.", "This is the first document."]
99
-
100
- # Asynchronous call
101
- async def main():
102
- embeddings = await embedder.create(texts, batch_size=128)
103
- # embeddings will be a list of numpy arrays (float32)
104
- # The embedding for the third text will be identical to the first
105
- # due to automatic de-duplication.
106
- print(f"Generated {len(embeddings)} embeddings.")
107
- print(f"Shape of first embedding: {embeddings[0].shape}")
108
- assert np.array_equal(embeddings[0], embeddings[2])
109
-
110
- # Run the async function
111
- asyncio.run(main())
112
- ```
113
-
114
- Attributes:
115
- client: An already‑configured ``openai.AsyncOpenAI`` client.
116
- model_name: The model identifier, e.g. ``"text-embedding-3-small"``.
117
- max_concurrency: Maximum number of concurrent requests to the OpenAI API.
118
- """
119
-
120
- client: AsyncOpenAI
121
- model_name: str
122
- max_concurrency: int = 8 # Default concurrency limit
123
- _semaphore: asyncio.Semaphore = field(init=False, repr=False)
124
-
125
- def __post_init__(self):
126
- # Initialize the semaphore after the object is created
127
- # Use object.__setattr__ because the dataclass is frozen
128
- object.__setattr__(self, "_semaphore", asyncio.Semaphore(self.max_concurrency))
129
-
130
- @observe(_LOGGER)
131
- @backoff_async(exception=RateLimitError, scale=15, max_retries=8)
132
- async def _embed_chunk(self, inputs: List[str]) -> List[NDArray[np.float32]]:
133
- """Embed one minibatch of sentences asynchronously, respecting concurrency limits.
134
-
135
- This private helper handles the actual API call for a batch of inputs.
136
- Exponential back-off is applied automatically when ``openai.RateLimitError``
137
- is raised.
138
-
139
- Args:
140
- inputs (List[str]): Input strings to be embedded. Duplicates are allowed.
141
-
142
- Returns:
143
- List of embedding vectors (``np.ndarray`` with dtype ``float32``)
144
- in the same order as *inputs*.
145
-
146
- Raises:
147
- openai.RateLimitError: Propagated if retries are exhausted.
148
- """
149
- # Acquire semaphore before making the API call
150
- async with self._semaphore:
151
- responses = await self.client.embeddings.create(input=inputs, model=self.model_name)
152
- return [np.array(d.embedding, dtype=np.float32) for d in responses.data]
153
-
154
- @observe(_LOGGER)
155
- async def create(self, inputs: List[str], batch_size: int) -> List[NDArray[np.float32]]:
156
- """Asynchronous public API: generate embeddings for a list of inputs.
157
-
158
- Uses ``openaivec.util.map_async`` to efficiently handle batching and de-duplication.
159
-
160
- Args:
161
- inputs (List[str]): A list of input strings. Duplicates are handled efficiently.
162
- batch_size (int): Maximum number of unique inputs per API call.
163
-
164
- Returns:
165
- A list of ``np.ndarray`` objects (dtype ``float32``) where each entry
166
- is the embedding of the corresponding string in *inputs*.
167
-
168
- Raises:
169
- openai.RateLimitError: Propagated if retries are exhausted during API calls.
170
- """
171
-
172
- return await map_async(inputs, self._embed_chunk, batch_size)
openaivec/model.py DELETED
@@ -1,67 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Type, TypeVar
3
-
4
- from pydantic import BaseModel
5
-
6
- ResponseFormat = TypeVar("ResponseFormat", bound=BaseModel | str)
7
-
8
-
9
- @dataclass(frozen=True)
10
- class PreparedTask:
11
- """A data class representing a complete task configuration for OpenAI API calls.
12
-
13
- This class encapsulates all the necessary parameters for executing a task,
14
- including the instructions to be sent to the model, the expected response
15
- format using Pydantic models, and sampling parameters for controlling
16
- the model's output behavior.
17
-
18
- Attributes:
19
- instructions (str): The prompt or instructions to send to the OpenAI model.
20
- This should contain clear, specific directions for the task.
21
- response_format (Type[ResponseFormat]): A Pydantic model class or str type that defines the expected
22
- structure of the response. Can be either a BaseModel subclass or str.
23
- temperature (float): Controls randomness in the model's output.
24
- Range: 0.0 to 1.0. Lower values make output more deterministic.
25
- Defaults to 0.0.
26
- top_p (float): Controls diversity via nucleus sampling. Only tokens
27
- comprising the top_p probability mass are considered.
28
- Range: 0.0 to 1.0. Defaults to 1.0.
29
-
30
- Example:
31
- Creating a custom task:
32
-
33
- ```python
34
- from pydantic import BaseModel
35
-
36
- class TranslationResponse(BaseModel):
37
- translated_text: str
38
- source_language: str
39
- target_language: str
40
-
41
- custom_task = PreparedTask(
42
- instructions="Translate the following text to French:",
43
- response_format=TranslationResponse,
44
- temperature=0.1,
45
- top_p=0.9
46
- )
47
- ```
48
-
49
- Note:
50
- This class is frozen (immutable) to ensure task configurations
51
- cannot be accidentally modified after creation.
52
- """
53
-
54
- instructions: str
55
- response_format: Type[ResponseFormat]
56
- temperature: float = 0.0
57
- top_p: float = 1.0
58
-
59
-
60
- @dataclass(frozen=True)
61
- class ResponsesModelName:
62
- value: str
63
-
64
-
65
- @dataclass(frozen=True)
66
- class EmbeddingsModelName:
67
- value: str