openaivec 0.14.9__py3-none-any.whl → 0.14.12__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.
openaivec/pandas_ext.py CHANGED
@@ -216,8 +216,12 @@ class OpenAIVecSeriesAccessor:
216
216
  top_p=top_p,
217
217
  )
218
218
 
219
- # Forward any extra kwargs to the underlying Responses API.
220
- return pd.Series(client.parse(self._obj.tolist(), **api_kwargs), index=self._obj.index, name=self._obj.name)
219
+ # Forward any extra kwargs to the underlying Responses API, excluding proxy-specific ones.
220
+ proxy_params = {"show_progress", "batch_size"}
221
+ filtered_kwargs = {k: v for k, v in api_kwargs.items() if k not in proxy_params}
222
+ return pd.Series(
223
+ client.parse(self._obj.tolist(), **filtered_kwargs), index=self._obj.index, name=self._obj.name
224
+ )
221
225
 
222
226
  def responses(
223
227
  self,
@@ -437,7 +441,95 @@ class OpenAIVecSeriesAccessor:
437
441
  **api_kwargs,
438
442
  )
439
443
 
440
- def infer_schema(self, purpose: str, max_examples: int = 100) -> InferredSchema:
444
+ def parse_with_cache(
445
+ self,
446
+ instructions: str,
447
+ cache: BatchingMapProxy[str, ResponseFormat],
448
+ response_format: ResponseFormat = None,
449
+ max_examples: int = 100,
450
+ temperature: float | None = 0.0,
451
+ top_p: float = 1.0,
452
+ **api_kwargs,
453
+ ) -> pd.Series:
454
+ """Parse Series values using an LLM with a provided cache.
455
+ This method allows you to parse the Series content into structured data
456
+ using an LLM, optionally inferring a schema based on the provided purpose.
457
+
458
+ Args:
459
+ instructions (str): System prompt for the LLM.
460
+ cache (BatchingMapProxy[str, BaseModel]): Explicit cache instance for
461
+ batching and deduplication control.
462
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
463
+ for structured output. If None, schema is inferred.
464
+ max_examples (int): Maximum number of examples to use for schema inference.
465
+ Defaults to 100.
466
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
467
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
468
+ Additional Keyword Args:
469
+ Arbitrary OpenAI Responses API parameters (e.g. `frequency_penalty`, `presence_penalty`,
470
+ `seed`, etc.) are forwarded verbatim to the underlying client.
471
+ Returns:
472
+ pandas.Series: Series with parsed structured data as instances of
473
+ `response_format` or inferred schema model.
474
+ """
475
+
476
+ schema: InferredSchema | None = None
477
+ if response_format is None:
478
+ schema = self.infer_schema(purpose=instructions, max_examples=max_examples, **api_kwargs)
479
+
480
+ return self.responses_with_cache(
481
+ instructions=schema.inference_prompt if schema else instructions,
482
+ cache=cache,
483
+ response_format=response_format or schema.model,
484
+ temperature=temperature,
485
+ top_p=top_p,
486
+ **api_kwargs,
487
+ )
488
+
489
+ def parse(
490
+ self,
491
+ instructions: str,
492
+ response_format: ResponseFormat = None,
493
+ max_examples: int = 100,
494
+ batch_size: int | None = None,
495
+ show_progress: bool = False,
496
+ temperature: float | None = 0.0,
497
+ top_p: float = 1.0,
498
+ **api_kwargs,
499
+ ) -> pd.Series:
500
+ """Parse Series values using an LLM with optional schema inference.
501
+
502
+ This method allows you to parse the Series content into structured data
503
+ using an LLM, optionally inferring a schema based on the provided purpose.
504
+
505
+ Args:
506
+ instructions (str): System prompt for the LLM.
507
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
508
+ for structured output. If None, schema is inferred.
509
+ max_examples (int): Maximum number of examples to use for schema inference.
510
+ Defaults to 100.
511
+ batch_size (int | None): Number of requests to process in parallel.
512
+ Defaults to None (automatic optimization).
513
+ show_progress (bool): Whether to display a progress bar during processing.
514
+ Defaults to False.
515
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
516
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
517
+
518
+ Returns:
519
+ pandas.Series: Series with parsed structured data as instances of
520
+ `response_format` or inferred schema model.
521
+ """
522
+ return self.parse_with_cache(
523
+ instructions=instructions,
524
+ cache=BatchingMapProxy(batch_size=batch_size, show_progress=show_progress),
525
+ response_format=response_format,
526
+ max_examples=max_examples,
527
+ temperature=temperature,
528
+ top_p=top_p,
529
+ **api_kwargs,
530
+ )
531
+
532
+ def infer_schema(self, purpose: str, max_examples: int = 100, **api_kwargs) -> InferredSchema:
441
533
  """Infer a structured data schema from Series content using AI.
442
534
 
443
535
  This method analyzes a sample of the Series values to automatically infer
@@ -488,7 +580,7 @@ class OpenAIVecSeriesAccessor:
488
580
  inferer = CONTAINER.resolve(SchemaInferer)
489
581
 
490
582
  input: SchemaInferenceInput = SchemaInferenceInput(
491
- examples=self._obj.sample(n=min(max_examples, len(self._obj))).tolist(), purpose=purpose
583
+ examples=self._obj.sample(n=min(max_examples, len(self._obj))).tolist(), purpose=purpose, **api_kwargs
492
584
  )
493
585
  return inferer.infer_schema(input)
494
586
 
@@ -538,90 +630,6 @@ class OpenAIVecSeriesAccessor:
538
630
  extracted.columns = [f"{self._obj.name}_{col}" for col in extracted.columns]
539
631
  return extracted
540
632
 
541
- def auto_extract(
542
- self,
543
- purpose: str,
544
- max_examples: int = 100,
545
- batch_size: int | None = None,
546
- show_progress: bool = False,
547
- **api_kwargs,
548
- ) -> pd.DataFrame:
549
- """Automatically infer schema and extract structured data in one step.
550
-
551
- This convenience method combines schema inference and data extraction into
552
- a single operation. It first analyzes a sample of the Series to infer an
553
- appropriate schema based on the stated purpose, then immediately applies
554
- that schema to extract structured data from all values in the Series.
555
-
556
- Args:
557
- purpose (str): Plain language description of what information to extract
558
- and how it will be used (e.g., "Extract product features for search",
559
- "Parse customer feedback for sentiment analysis"). This guides both
560
- schema inference and field selection.
561
- max_examples (int): Maximum number of examples to use for schema inference.
562
- A larger sample may produce more accurate schemas but increases
563
- inference time. Defaults to 100.
564
- batch_size (int | None): Number of requests to process in parallel during
565
- extraction. Defaults to None (automatic optimization). Set to a specific
566
- value to control API usage and performance.
567
- show_progress (bool): Whether to display a progress bar during extraction.
568
- Useful for large datasets. Defaults to False.
569
- **api_kwargs: Additional OpenAI API parameters (e.g., `temperature`, `top_p`,
570
- `frequency_penalty`, `presence_penalty`, `seed`) forwarded to the task execution.
571
-
572
- Returns:
573
- pd.DataFrame: A DataFrame with extracted structured data. Each inferred
574
- field becomes a column, with the same index as the original Series.
575
- Column names and types are determined by the inferred schema.
576
-
577
- Example:
578
- ```python
579
- # Extract structured data from product reviews
580
- reviews = pd.Series([
581
- "Great laptop! 16GB RAM, fast SSD, battery lasts 10 hours",
582
- "Decent phone. 128GB storage, camera is okay, screen is bright",
583
- "Gaming desktop with RTX 4090, 32GB RAM, runs everything smoothly"
584
- ])
585
-
586
- # One-step extraction
587
- extracted = reviews.ai.auto_extract(
588
- purpose="Extract product specifications and performance metrics",
589
- show_progress=True
590
- )
591
- # Result: DataFrame with columns like 'ram', 'storage', 'battery_life', etc.
592
-
593
- # Extract sentiment and issues from support tickets
594
- tickets = pd.Series([
595
- "Account locked, can't reset password, very frustrated",
596
- "Billing error, charged twice for subscription",
597
- "Great support! Issue resolved quickly"
598
- ])
599
-
600
- features = tickets.ai.auto_extract(
601
- purpose="Extract issue type and customer sentiment for support analytics"
602
- )
603
- ```
604
-
605
- Note:
606
- This method is ideal for exploratory data analysis when you don't have
607
- a predefined schema. For production use cases with stable schemas,
608
- consider using `infer_schema()` once and reusing the schema with `task()`.
609
- The inferred schema is not returned, so if you need to inspect or save it,
610
- use `infer_schema()` and `task()` separately.
611
- """
612
- schema = self._obj.ai.infer_schema(purpose=purpose, max_examples=max_examples)
613
-
614
- return pd.DataFrame(
615
- {
616
- "inferred": self._obj.ai.task(
617
- task=schema.task,
618
- batch_size=batch_size,
619
- show_progress=show_progress,
620
- **api_kwargs,
621
- ),
622
- }
623
- ).ai.extract("inferred")
624
-
625
633
 
626
634
  @pd.api.extensions.register_dataframe_accessor("ai")
627
635
  class OpenAIVecDataFrameAccessor:
@@ -822,6 +830,95 @@ class OpenAIVecDataFrameAccessor:
822
830
  **api_kwargs,
823
831
  )
824
832
 
833
+ def parse_with_cache(
834
+ self,
835
+ instructions: str,
836
+ cache: BatchingMapProxy[str, ResponseFormat],
837
+ response_format: ResponseFormat = None,
838
+ max_examples: int = 100,
839
+ temperature: float | None = 0.0,
840
+ top_p: float = 1.0,
841
+ **api_kwargs,
842
+ ) -> pd.Series:
843
+ """Parse DataFrame rows using an LLM with a provided cache.
844
+
845
+ This method allows you to parse each DataFrame row (serialized as JSON)
846
+ into structured data using an LLM, optionally inferring a schema based
847
+ on the provided purpose.
848
+
849
+ Args:
850
+ instructions (str): System prompt for the LLM.
851
+ cache (BatchingMapProxy[str, ResponseFormat]): Explicit cache instance for
852
+ batching and deduplication control.
853
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
854
+ for structured output. If None, schema is inferred.
855
+ max_examples (int): Maximum number of examples to use for schema inference.
856
+ Defaults to 100.
857
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
858
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
859
+
860
+ Additional Keyword Args:
861
+ Arbitrary OpenAI Responses API parameters (e.g. `frequency_penalty`, `presence_penalty`,
862
+ `seed`, etc.) are forwarded verbatim to the underlying client.
863
+
864
+ Returns:
865
+ pandas.Series: Series with parsed structured data as instances of
866
+ `response_format` or inferred schema model.
867
+ """
868
+ return _df_rows_to_json_series(self._obj).ai.parse_with_cache(
869
+ instructions=instructions,
870
+ cache=cache,
871
+ response_format=response_format,
872
+ max_examples=max_examples,
873
+ temperature=temperature,
874
+ top_p=top_p,
875
+ **api_kwargs,
876
+ )
877
+
878
+ def parse(
879
+ self,
880
+ instructions: str,
881
+ response_format: ResponseFormat = None,
882
+ max_examples: int = 100,
883
+ batch_size: int | None = None,
884
+ show_progress: bool = False,
885
+ temperature: float | None = 0.0,
886
+ top_p: float = 1.0,
887
+ **api_kwargs,
888
+ ) -> pd.Series:
889
+ """Parse DataFrame rows using an LLM with optional schema inference.
890
+
891
+ This method allows you to parse each DataFrame row (serialized as JSON)
892
+ into structured data using an LLM, optionally inferring a schema based
893
+ on the provided purpose.
894
+
895
+ Args:
896
+ instructions (str): System prompt for the LLM.
897
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
898
+ for structured output. If None, schema is inferred.
899
+ max_examples (int): Maximum number of examples to use for schema inference.
900
+ Defaults to 100.
901
+ batch_size (int | None): Number of requests to process in parallel.
902
+ Defaults to None (automatic optimization).
903
+ show_progress (bool): Whether to display a progress bar during processing.
904
+ Defaults to False.
905
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
906
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
907
+
908
+ Returns:
909
+ pandas.Series: Series with parsed structured data as instances of
910
+ `response_format` or inferred schema model.
911
+ """
912
+ return self.parse_with_cache(
913
+ instructions=instructions,
914
+ cache=BatchingMapProxy(batch_size=batch_size, show_progress=show_progress),
915
+ response_format=response_format,
916
+ max_examples=max_examples,
917
+ temperature=temperature,
918
+ top_p=top_p,
919
+ **api_kwargs,
920
+ )
921
+
825
922
  def infer_schema(self, purpose: str, max_examples: int = 100) -> InferredSchema:
826
923
  """Infer a structured data schema from DataFrame rows using AI.
827
924
 
@@ -988,100 +1085,6 @@ class OpenAIVecDataFrameAccessor:
988
1085
 
989
1086
  return df
990
1087
 
991
- def auto_extract(
992
- self,
993
- purpose: str,
994
- max_examples: int = 100,
995
- batch_size: int | None = None,
996
- show_progress: bool = False,
997
- **api_kwargs,
998
- ) -> pd.DataFrame:
999
- """Automatically infer schema and add extracted fields to the DataFrame.
1000
-
1001
- This convenience method combines schema inference and data extraction to
1002
- automatically add new columns to the existing DataFrame. It analyzes a
1003
- sample of the DataFrame rows to infer an appropriate schema based on the
1004
- stated purpose, then extracts structured data and joins it with the
1005
- original DataFrame.
1006
-
1007
- Args:
1008
- purpose (str): Plain language description of what information to extract
1009
- and how it will be used (e.g., "Extract customer sentiment metrics",
1010
- "Parse product attributes for analytics"). This guides both schema
1011
- inference and field selection.
1012
- max_examples (int): Maximum number of rows to use for schema inference.
1013
- A larger sample may produce more accurate schemas but increases
1014
- inference time. Defaults to 100.
1015
- batch_size (int | None): Number of requests to process in parallel during
1016
- extraction. Defaults to None (automatic optimization). Set to a specific
1017
- value to control API usage and performance.
1018
- show_progress (bool): Whether to display a progress bar during extraction.
1019
- Useful for large datasets. Defaults to False.
1020
- **api_kwargs: Additional OpenAI API parameters (e.g., `temperature`, `top_p`,
1021
- `frequency_penalty`, `presence_penalty`, `seed`) forwarded to the task execution.
1022
-
1023
- Returns:
1024
- pd.DataFrame: The original DataFrame with new columns added from the
1025
- inferred structured data. Each inferred field becomes a new column.
1026
- The original columns and index are preserved.
1027
-
1028
- Example:
1029
- ```python
1030
- # Add sentiment and issue type to support tickets
1031
- df = pd.DataFrame({
1032
- 'ticket_id': [1, 2, 3],
1033
- 'description': [
1034
- "Can't login, password reset not working",
1035
- "Billing error, charged twice last month",
1036
- "Great service, issue resolved quickly!"
1037
- ],
1038
- 'date': ['2024-01-01', '2024-01-02', '2024-01-03']
1039
- })
1040
-
1041
- # Add inferred fields to existing DataFrame
1042
- enriched_df = df.ai.auto_extract(
1043
- purpose="Extract issue type and sentiment for support dashboard",
1044
- show_progress=True
1045
- )
1046
- # Result: Original df with new columns like 'issue_type', 'sentiment', etc.
1047
-
1048
- # Add product specifications to inventory data
1049
- inventory = pd.DataFrame({
1050
- 'sku': ['A001', 'B002', 'C003'],
1051
- 'description': [
1052
- "Laptop 16GB RAM, 512GB SSD, Intel i7",
1053
- "Phone 128GB, 5G, dual camera",
1054
- "Tablet 10-inch, WiFi only, 64GB"
1055
- ]
1056
- })
1057
-
1058
- enriched_inventory = inventory.ai.auto_extract(
1059
- purpose="Extract technical specifications for inventory system"
1060
- )
1061
- ```
1062
-
1063
- Note:
1064
- This method is ideal for enriching existing DataFrames with additional
1065
- structured fields extracted from text columns. The schema is inferred
1066
- from the entire DataFrame content (converted to JSON format). For
1067
- production use cases with stable schemas, consider using `infer_schema()`
1068
- once and reusing the schema with `task()`.
1069
- """
1070
- # Infer schema from DataFrame rows
1071
- schema = self._obj.ai.infer_schema(purpose=purpose, max_examples=max_examples)
1072
-
1073
- # Extract structured data using the inferred schema
1074
- inferred_series = self._obj.ai.task(
1075
- task=schema.task,
1076
- batch_size=batch_size,
1077
- show_progress=show_progress,
1078
- **api_kwargs,
1079
- )
1080
-
1081
- return self._obj.assign(
1082
- inferred=inferred_series,
1083
- ).ai.extract("inferred")
1084
-
1085
1088
  def similarity(self, col1: str, col2: str) -> pd.Series:
1086
1089
  """Compute cosine similarity between two columns containing embedding vectors.
1087
1090
 
@@ -1176,7 +1179,11 @@ class AsyncOpenAIVecSeriesAccessor:
1176
1179
  temperature=temperature,
1177
1180
  top_p=top_p,
1178
1181
  )
1179
- results = await client.parse(self._obj.tolist(), **api_kwargs)
1182
+
1183
+ # Forward any extra kwargs to the underlying Responses API, excluding proxy-specific ones.
1184
+ proxy_params = {"show_progress", "batch_size", "max_concurrency"}
1185
+ filtered_kwargs = {k: v for k, v in api_kwargs.items() if k not in proxy_params}
1186
+ results = await client.parse(self._obj.tolist(), **filtered_kwargs)
1180
1187
  return pd.Series(results, index=self._obj.index, name=self._obj.name)
1181
1188
 
1182
1189
  async def responses(
@@ -1457,96 +1464,107 @@ class AsyncOpenAIVecSeriesAccessor:
1457
1464
  **api_kwargs,
1458
1465
  )
1459
1466
 
1460
- async def auto_extract(
1467
+ async def parse_with_cache(
1461
1468
  self,
1462
- purpose: str,
1469
+ instructions: str,
1470
+ cache: AsyncBatchingMapProxy[str, ResponseFormat],
1471
+ response_format: ResponseFormat = None,
1463
1472
  max_examples: int = 100,
1464
- batch_size: int | None = None,
1465
- max_concurrency: int = 8,
1466
- show_progress: bool = False,
1473
+ temperature: float | None = 0.0,
1474
+ top_p: float = 1.0,
1467
1475
  **api_kwargs,
1468
- ) -> pd.DataFrame:
1469
- """Automatically infer schema and extract structured data in one step (asynchronously).
1476
+ ) -> pd.Series:
1477
+ """Parse Series values using an LLM with a provided cache (asynchronously).
1470
1478
 
1471
- This convenience method combines schema inference and data extraction into
1472
- a single operation. It first analyzes a sample of the Series to infer an
1473
- appropriate schema based on the stated purpose, then immediately applies
1474
- that schema to extract structured data from all values in the Series.
1479
+ This method allows you to parse the Series content into structured data
1480
+ using an LLM, optionally inferring a schema based on the provided purpose.
1475
1481
 
1476
1482
  Args:
1477
- purpose (str): Plain language description of what information to extract
1478
- and how it will be used (e.g., "Extract product features for search",
1479
- "Parse customer feedback for sentiment analysis"). This guides both
1480
- schema inference and field selection.
1483
+ instructions (str): System prompt for the LLM.
1484
+ cache (AsyncBatchingMapProxy[str, ResponseFormat]): Explicit cache instance for
1485
+ batching and deduplication control.
1486
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
1487
+ for structured output. If None, schema is inferred.
1481
1488
  max_examples (int): Maximum number of examples to use for schema inference.
1482
- A larger sample may produce more accurate schemas but increases
1483
- inference time. Defaults to 100.
1484
- batch_size (int | None): Number of requests to process in parallel during
1485
- extraction. Defaults to None (automatic optimization). Set to a specific
1486
- value to control API usage and performance.
1487
- max_concurrency (int): Maximum number of concurrent requests during
1488
- extraction. Defaults to 8.
1489
- show_progress (bool): Whether to display a progress bar during extraction.
1490
- Useful for large datasets. Defaults to False.
1491
- **api_kwargs: Additional OpenAI API parameters (e.g., `temperature`, `top_p`,
1492
- `frequency_penalty`, `presence_penalty`, `seed`) forwarded to the task execution.
1489
+ Defaults to 100.
1490
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
1491
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
1492
+
1493
+ Additional Keyword Args:
1494
+ Arbitrary OpenAI Responses API parameters (e.g. `frequency_penalty`, `presence_penalty`,
1495
+ `seed`, etc.) are forwarded verbatim to the underlying client.
1493
1496
 
1494
1497
  Returns:
1495
- pd.DataFrame: A DataFrame with extracted structured data. Each inferred
1496
- field becomes a column, with the same index as the original Series.
1497
- Column names and types are determined by the inferred schema.
1498
+ pandas.Series: Series with parsed structured data as instances of
1499
+ `response_format` or inferred schema model.
1498
1500
 
1499
- Example:
1500
- ```python
1501
- # Extract structured data from product reviews
1502
- reviews = pd.Series([
1503
- "Great laptop! 16GB RAM, fast SSD, battery lasts 10 hours",
1504
- "Decent phone. 128GB storage, camera is okay, screen is bright",
1505
- "Gaming desktop with RTX 4090, 32GB RAM, runs everything smoothly"
1506
- ])
1501
+ Note:
1502
+ This is an asynchronous method and must be awaited.
1503
+ """
1504
+ schema: InferredSchema | None = None
1505
+ if response_format is None:
1506
+ # Use synchronous schema inference
1507
+ schema = self._obj.ai.infer_schema(purpose=instructions, max_examples=max_examples)
1507
1508
 
1508
- # One-step extraction (must be awaited)
1509
- extracted = await reviews.aio.auto_extract(
1510
- purpose="Extract product specifications and performance metrics",
1511
- max_concurrency=4,
1512
- show_progress=True
1513
- )
1514
- # Result: DataFrame with columns like 'ram', 'storage', 'battery_life', etc.
1509
+ return await self.responses_with_cache(
1510
+ instructions=schema.inference_prompt if schema else instructions,
1511
+ cache=cache,
1512
+ response_format=response_format or schema.model,
1513
+ temperature=temperature,
1514
+ top_p=top_p,
1515
+ **api_kwargs,
1516
+ )
1515
1517
 
1516
- # Extract sentiment and issues from support tickets
1517
- tickets = pd.Series([
1518
- "Account locked, can't reset password, very frustrated",
1519
- "Billing error, charged twice for subscription",
1520
- "Great support! Issue resolved quickly"
1521
- ])
1518
+ async def parse(
1519
+ self,
1520
+ instructions: str,
1521
+ response_format: ResponseFormat = None,
1522
+ max_examples: int = 100,
1523
+ batch_size: int | None = None,
1524
+ max_concurrency: int = 8,
1525
+ show_progress: bool = False,
1526
+ temperature: float | None = 0.0,
1527
+ top_p: float = 1.0,
1528
+ **api_kwargs,
1529
+ ) -> pd.Series:
1530
+ """Parse Series values using an LLM with optional schema inference (asynchronously).
1522
1531
 
1523
- features = await tickets.aio.auto_extract(
1524
- purpose="Extract issue type and customer sentiment for support analytics",
1525
- batch_size=32
1526
- )
1527
- ```
1532
+ This method allows you to parse the Series content into structured data
1533
+ using an LLM, optionally inferring a schema based on the provided purpose.
1534
+
1535
+ Args:
1536
+ instructions (str): System prompt for the LLM.
1537
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
1538
+ for structured output. If None, schema is inferred.
1539
+ max_examples (int): Maximum number of examples to use for schema inference.
1540
+ Defaults to 100.
1541
+ batch_size (int | None): Number of requests to process in parallel.
1542
+ Defaults to None (automatic optimization).
1543
+ max_concurrency (int): Maximum number of concurrent requests. Defaults to 8.
1544
+ show_progress (bool): Whether to display a progress bar during processing.
1545
+ Defaults to False.
1546
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
1547
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
1548
+
1549
+ Returns:
1550
+ pandas.Series: Series with parsed structured data as instances of
1551
+ `response_format` or inferred schema model.
1528
1552
 
1529
1553
  Note:
1530
- This is an asynchronous method and must be awaited. This method is ideal
1531
- for exploratory data analysis when you don't have a predefined schema.
1532
- For production use cases with stable schemas, consider using the synchronous
1533
- `infer_schema()` once and reusing the schema with `task()`. The inferred
1534
- schema is not returned, so if you need to inspect or save it, use
1535
- `infer_schema()` and `task()` separately.
1554
+ This is an asynchronous method and must be awaited.
1536
1555
  """
1537
- # Use synchronous infer_schema since it's not async
1538
- schema = self._obj.ai.infer_schema(purpose=purpose, max_examples=max_examples)
1539
-
1540
- inferred_series = await self._obj.aio.task(
1541
- task=schema.task,
1542
- batch_size=batch_size,
1543
- max_concurrency=max_concurrency,
1544
- show_progress=show_progress,
1556
+ return await self.parse_with_cache(
1557
+ instructions=instructions,
1558
+ cache=AsyncBatchingMapProxy(
1559
+ batch_size=batch_size, max_concurrency=max_concurrency, show_progress=show_progress
1560
+ ),
1561
+ response_format=response_format,
1562
+ max_examples=max_examples,
1563
+ temperature=temperature,
1564
+ top_p=top_p,
1545
1565
  **api_kwargs,
1546
1566
  )
1547
1567
 
1548
- return pd.DataFrame({"inferred": inferred_series}).ai.extract("inferred")
1549
-
1550
1568
 
1551
1569
  @pd.api.extensions.register_dataframe_accessor("aio")
1552
1570
  class AsyncOpenAIVecDataFrameAccessor:
@@ -1775,6 +1793,105 @@ class AsyncOpenAIVecDataFrameAccessor:
1775
1793
  **api_kwargs,
1776
1794
  )
1777
1795
 
1796
+ async def parse_with_cache(
1797
+ self,
1798
+ instructions: str,
1799
+ cache: AsyncBatchingMapProxy[str, ResponseFormat],
1800
+ response_format: ResponseFormat = None,
1801
+ max_examples: int = 100,
1802
+ temperature: float | None = 0.0,
1803
+ top_p: float = 1.0,
1804
+ **api_kwargs,
1805
+ ) -> pd.Series:
1806
+ """Parse DataFrame rows using an LLM with a provided cache (asynchronously).
1807
+
1808
+ This method allows you to parse each DataFrame row (serialized as JSON)
1809
+ into structured data using an LLM, optionally inferring a schema based
1810
+ on the provided purpose.
1811
+
1812
+ Args:
1813
+ instructions (str): System prompt for the LLM.
1814
+ cache (AsyncBatchingMapProxy[str, ResponseFormat]): Explicit cache instance for
1815
+ batching and deduplication control.
1816
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
1817
+ for structured output. If None, schema is inferred.
1818
+ max_examples (int): Maximum number of examples to use for schema inference.
1819
+ Defaults to 100.
1820
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
1821
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
1822
+
1823
+ Additional Keyword Args:
1824
+ Arbitrary OpenAI Responses API parameters (e.g. `frequency_penalty`, `presence_penalty`,
1825
+ `seed`, etc.) are forwarded verbatim to the underlying client.
1826
+
1827
+ Returns:
1828
+ pandas.Series: Series with parsed structured data as instances of
1829
+ `response_format` or inferred schema model.
1830
+
1831
+ Note:
1832
+ This is an asynchronous method and must be awaited.
1833
+ """
1834
+ return await _df_rows_to_json_series(self._obj).aio.parse_with_cache(
1835
+ instructions=instructions,
1836
+ cache=cache,
1837
+ response_format=response_format,
1838
+ max_examples=max_examples,
1839
+ temperature=temperature,
1840
+ top_p=top_p,
1841
+ **api_kwargs,
1842
+ )
1843
+
1844
+ async def parse(
1845
+ self,
1846
+ instructions: str,
1847
+ response_format: ResponseFormat = None,
1848
+ max_examples: int = 100,
1849
+ batch_size: int | None = None,
1850
+ max_concurrency: int = 8,
1851
+ show_progress: bool = False,
1852
+ temperature: float | None = 0.0,
1853
+ top_p: float = 1.0,
1854
+ **api_kwargs,
1855
+ ) -> pd.Series:
1856
+ """Parse DataFrame rows using an LLM with optional schema inference (asynchronously).
1857
+
1858
+ This method allows you to parse each DataFrame row (serialized as JSON)
1859
+ into structured data using an LLM, optionally inferring a schema based
1860
+ on the provided purpose.
1861
+
1862
+ Args:
1863
+ instructions (str): System prompt for the LLM.
1864
+ response_format (type[BaseModel] | None): Pydantic model or built-in type
1865
+ for structured output. If None, schema is inferred.
1866
+ max_examples (int): Maximum number of examples to use for schema inference.
1867
+ Defaults to 100.
1868
+ batch_size (int | None): Number of requests to process in parallel.
1869
+ Defaults to None (automatic optimization).
1870
+ max_concurrency (int): Maximum number of concurrent requests. Defaults to 8.
1871
+ show_progress (bool): Whether to display a progress bar during processing.
1872
+ Defaults to False.
1873
+ temperature (float | None): Sampling temperature. Defaults to 0.0.
1874
+ top_p (float): Nucleus sampling parameter. Defaults to 1.0.
1875
+
1876
+ Returns:
1877
+ pandas.Series: Series with parsed structured data as instances of
1878
+ `response_format` or inferred schema model.
1879
+
1880
+ Note:
1881
+ This is an asynchronous method and must be awaited.
1882
+ """
1883
+ return await self.parse_with_cache(
1884
+ instructions=instructions,
1885
+ cache=AsyncBatchingMapProxy(
1886
+ batch_size=batch_size, max_concurrency=max_concurrency, show_progress=show_progress
1887
+ ),
1888
+ response_format=response_format,
1889
+ max_examples=max_examples,
1890
+ temperature=temperature,
1891
+ top_p=top_p,
1892
+ **api_kwargs,
1893
+ )
1894
+
1778
1895
  async def pipe(self, func: Callable[[pd.DataFrame], Awaitable[T] | T]) -> T:
1779
1896
  """Apply a function to the DataFrame, supporting both synchronous and asynchronous functions.
1780
1897
 
@@ -1954,103 +2071,3 @@ class AsyncOpenAIVecDataFrameAccessor:
1954
2071
  df.at[actual_index, target_column_name] = result.output
1955
2072
 
1956
2073
  return df
1957
-
1958
- async def auto_extract(
1959
- self,
1960
- purpose: str,
1961
- max_examples: int = 100,
1962
- batch_size: int | None = None,
1963
- max_concurrency: int = 8,
1964
- show_progress: bool = False,
1965
- **api_kwargs,
1966
- ) -> pd.DataFrame:
1967
- """Automatically infer schema and add extracted fields to the DataFrame (asynchronously).
1968
-
1969
- This convenience method combines schema inference and data extraction to
1970
- automatically add new columns to the existing DataFrame. It analyzes a
1971
- sample of the DataFrame rows to infer an appropriate schema based on the
1972
- stated purpose, then extracts structured data and joins it with the
1973
- original DataFrame.
1974
-
1975
- Args:
1976
- purpose (str): Plain language description of what information to extract
1977
- and how it will be used (e.g., "Extract customer sentiment metrics",
1978
- "Parse product attributes for analytics"). This guides both schema
1979
- inference and field selection.
1980
- max_examples (int): Maximum number of rows to use for schema inference.
1981
- A larger sample may produce more accurate schemas but increases
1982
- inference time. Defaults to 100.
1983
- batch_size (int | None): Number of requests to process in parallel during
1984
- extraction. Defaults to None (automatic optimization). Set to a specific
1985
- value to control API usage and performance.
1986
- max_concurrency (int): Maximum number of concurrent requests during
1987
- extraction. Defaults to 8.
1988
- show_progress (bool): Whether to display a progress bar during extraction.
1989
- Useful for large datasets. Defaults to False.
1990
- **api_kwargs: Additional OpenAI API parameters (e.g., `temperature`, `top_p`,
1991
- `frequency_penalty`, `presence_penalty`, `seed`) forwarded to the task execution.
1992
-
1993
- Returns:
1994
- pd.DataFrame: The original DataFrame with new columns added from the
1995
- inferred structured data. Each inferred field becomes a new column.
1996
- The original columns and index are preserved.
1997
-
1998
- Example:
1999
- ```python
2000
- # Add sentiment and issue type to support tickets
2001
- df = pd.DataFrame({
2002
- 'ticket_id': [1, 2, 3],
2003
- 'description': [
2004
- "Can't login, password reset not working",
2005
- "Billing error, charged twice last month",
2006
- "Great service, issue resolved quickly!"
2007
- ],
2008
- 'date': ['2024-01-01', '2024-01-02', '2024-01-03']
2009
- })
2010
-
2011
- # Add inferred fields to existing DataFrame (must be awaited)
2012
- enriched_df = await df.aio.auto_extract(
2013
- purpose="Extract issue type and sentiment for support dashboard",
2014
- max_concurrency=4,
2015
- show_progress=True
2016
- )
2017
- # Result: Original df with new columns like 'issue_type', 'sentiment', etc.
2018
-
2019
- # Add product specifications to inventory data
2020
- inventory = pd.DataFrame({
2021
- 'sku': ['A001', 'B002', 'C003'],
2022
- 'description': [
2023
- "Laptop 16GB RAM, 512GB SSD, Intel i7",
2024
- "Phone 128GB, 5G, dual camera",
2025
- "Tablet 10-inch, WiFi only, 64GB"
2026
- ]
2027
- })
2028
-
2029
- enriched_inventory = await inventory.aio.auto_extract(
2030
- purpose="Extract technical specifications for inventory system",
2031
- batch_size=32
2032
- )
2033
- ```
2034
-
2035
- Note:
2036
- This is an asynchronous method and must be awaited. This method is ideal
2037
- for enriching existing DataFrames with additional structured fields
2038
- extracted from text columns. The schema is inferred synchronously from
2039
- the DataFrame content. For production use cases with stable schemas,
2040
- consider using `infer_schema()` once and reusing the schema with `task()`.
2041
- """
2042
- # Infer schema from DataFrame rows (synchronous)
2043
- schema = self._obj.ai.infer_schema(purpose=purpose, max_examples=max_examples)
2044
-
2045
- # Extract structured data using the inferred schema (asynchronous)
2046
- inferred_series = await self._obj.aio.task(
2047
- task=schema.task,
2048
- batch_size=batch_size,
2049
- max_concurrency=max_concurrency,
2050
- show_progress=show_progress,
2051
- **api_kwargs,
2052
- )
2053
-
2054
- return self._obj.assign(
2055
- inferred=inferred_series,
2056
- ).ai.extract("inferred")