arize-phoenix 1.9.1rc2__py3-none-any.whl → 2.0.0__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.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arize-phoenix
3
- Version: 1.9.1rc2
3
+ Version: 2.0.0
4
4
  Summary: ML Observability in your notebook
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -55,7 +55,7 @@ Requires-Dist: strawberry-graphql[debug-server]==0.208.2; extra == 'dev'
55
55
  Provides-Extra: experimental
56
56
  Requires-Dist: tenacity; extra == 'experimental'
57
57
  Provides-Extra: llama-index
58
- Requires-Dist: llama-index>=0.9.14; extra == 'llama-index'
58
+ Requires-Dist: llama-index==0.9.14; extra == 'llama-index'
59
59
  Description-Content-Type: text/markdown
60
60
 
61
61
  <p align="center">
@@ -1,6 +1,7 @@
1
- phoenix/__init__.py,sha256=QB9EbwlNjt7WAQhba0vhPsnO0dyEVYbdrRbKP9ndWMw,1376
1
+ phoenix/__init__.py,sha256=PMI2WOSvZVHGPpuhM_CPM29ejrA1b-XOHI8jJXHWHeE,1373
2
2
  phoenix/config.py,sha256=ErvGg22SSiuqPJtIX1WZE5KcM2lt6XOGZ__HwRg3JqA,2390
3
3
  phoenix/datetime_utils.py,sha256=D955QLrkgrrSdUM6NyqbCeAu2SMsjhR5rHVQEsVUdng,2773
4
+ phoenix/exceptions.py,sha256=igIWGAg3m8jm5YwQDeCY1p8ml_60A7zaGVXJ1yZhY9s,44
4
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
5
6
  phoenix/services.py,sha256=slL4Uu___QQSKEssgD738-WAld-kzVQnpW92uKLxV4E,4886
6
7
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -9,7 +10,7 @@ phoenix/core/evals.py,sha256=tBHVgEEQW6zsNAAQCYIN-BbVHy5Q-hgF5UpQy1SmkwE,6538
9
10
  phoenix/core/model.py,sha256=vQ6RxpUPlncezJvur5u6xBN0Lkrk2gW0cTyb-qqaSqA,4713
10
11
  phoenix/core/model_schema.py,sha256=rR9VdhL_oXxbprDTPQJBXs5hw5sMPQmzx__m6Kwsxug,50394
11
12
  phoenix/core/model_schema_adapter.py,sha256=3GkyzqUST4fYi-Bgs8qAam5hwMCdQRZTDLjZ9Bnzdm4,8268
12
- phoenix/core/traces.py,sha256=unJ4x-LRBPexCzZPk3ImLcqiXT60u76-ABbgi_eXTgk,14314
13
+ phoenix/core/traces.py,sha256=uNhtCpgXP9L0ahOoP9ZOBmLnubyUTkICiDB4XB-h5GY,14312
13
14
  phoenix/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
15
  phoenix/datasets/dataset.py,sha256=scKVZ7zc6Dpc_ntt-pWhzY-KWqOJEwKePuyNnKSVTGE,30515
15
16
  phoenix/datasets/errors.py,sha256=cGp9vxnw4SewFoWBV3ZGMkhE0Kh73lPIv3Ppz_H_RoA,8261
@@ -17,24 +18,25 @@ phoenix/datasets/fixtures.py,sha256=0_PacL3dw49zulKpFpPdhvxJxeGmHTguqIyf2VXkBkk,
17
18
  phoenix/datasets/schema.py,sha256=bF1d2Md6NyqQZuC4Ym5A52f2_IcazkyxGFZ11HPqSg0,6668
18
19
  phoenix/datasets/validation.py,sha256=dZ9lCFUV0EY7HCkQkQBrs-GLAEIZdpOqUxwD5l4dp88,8294
19
20
  phoenix/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- phoenix/experimental/evals/__init__.py,sha256=dplCn-3MhT1EkiJd-FCPpipYnHG1jJvvikCrhVrRcS8,1446
21
- phoenix/experimental/evals/evaluators.py,sha256=ZLhuGRVs8S7Z6YRjgtU-7WLJ7pZKD5xTg0tuP6HCPz0,8849
21
+ phoenix/experimental/evals/__init__.py,sha256=90k7hxxghhqDCftoAWsdOiUsJqYwNuJBXjhbpb3Na4I,1499
22
+ phoenix/experimental/evals/evaluators.py,sha256=JEEow9CM3u9GkVey8KEora8e7cbmhJgazd5wh35_LPE,10311
22
23
  phoenix/experimental/evals/retrievals.py,sha256=o3fqrsYbYZjyGj_jWkN_9VQVyXjLkDKDw5Ws7l8bwdI,3828
23
24
  phoenix/experimental/evals/functions/__init__.py,sha256=3FMGrjmgxegXAwgDV_RpaN-73cFVyBiO8YwZvml5P9c,156
24
- phoenix/experimental/evals/functions/classify.py,sha256=S711OPnamxE_8hVUUU2dcY4pb5zjGIVNY2-kLBpW9_E,29326
25
- phoenix/experimental/evals/functions/generate.py,sha256=ju-ZbhgMWw4P7yEligYpRa7yraNsL3En8hoVao_U3X4,3555
25
+ phoenix/experimental/evals/functions/classify.py,sha256=Q0FMOpU6WFr4m3dtBpJlNyrj2ExTYMB-XjR1EreeeXg,18731
26
+ phoenix/experimental/evals/functions/executor.py,sha256=TSw2lVhkl6-VBYcXSlUl3E0U4OuJWnhwhed7NmFgbF8,13376
27
+ phoenix/experimental/evals/functions/generate.py,sha256=sdr6TeXn5JLEKM0NqYtvq01Lq48Q7uatb0fsq5zQgVY,5310
26
28
  phoenix/experimental/evals/functions/processing.py,sha256=F4xtLsulLV4a8CkuLldRddsCim75dSTIShEJUYN6I6w,1823
27
29
  phoenix/experimental/evals/models/__init__.py,sha256=j1N7DhiOPbcaemtVBONcQ0miNnGQwEXz4u3P3Vwe6-4,320
28
30
  phoenix/experimental/evals/models/base.py,sha256=aSE3Al3MsLvzNKuN2e-z6O-RB5mgpisH4UQqwNQcqp0,7734
29
31
  phoenix/experimental/evals/models/bedrock.py,sha256=CRPmBuSLc_nRnKKWLHhGMxdWEISIKUJM1tzIlOQ_qWM,7927
30
32
  phoenix/experimental/evals/models/litellm.py,sha256=jrRlph22xWxMXMUabUWjIO2e-sHxQzlQwSM-SnAACFQ,4714
31
33
  phoenix/experimental/evals/models/openai.py,sha256=Kl2uES3HRcZGFqblfBQZ6D1BpDffuLZDAqVTjhrSXXQ,17101
32
- phoenix/experimental/evals/models/rate_limiters.py,sha256=aQkgEyeDxWS1yFAX_eagKK2eKuTY0WKD74jFDx9Hgrw,9279
34
+ phoenix/experimental/evals/models/rate_limiters.py,sha256=5GVN0RQKt36Przg3-9jLgocRmyg-tbeO-cdbuLIx89w,10160
33
35
  phoenix/experimental/evals/models/vertexai.py,sha256=NfBpQq0l7XzP-wDEDsK27IRiQBzA1GXEdfwlAf8leX4,5609
34
- phoenix/experimental/evals/templates/__init__.py,sha256=5dXgCvQrHPCvYIOwKUHaEYOzQpHh6fjhe1dUMC2yi2A,1470
36
+ phoenix/experimental/evals/templates/__init__.py,sha256=-KFIVh1xQLPcJP8Mv_tieIndxE02mg_c2QaibAuHJuE,1432
35
37
  phoenix/experimental/evals/templates/default_templates.py,sha256=8BetD8Xufc2f62CPZ9mbysyvDofnbFPalwB0u-KckuE,20614
36
- phoenix/experimental/evals/templates/template.py,sha256=NThw-12f0I-UkwulFJ_ER3T-W5vc2xee0T-joKWT-_U,6178
37
- phoenix/experimental/evals/utils/__init__.py,sha256=xdryDIwSLKLF0Ps132dxr3BFisIFAveMAgAyFBbym-c,1505
38
+ phoenix/experimental/evals/templates/template.py,sha256=VAX_ZeV3vNWCODipMy7EtaYdQ0c7WA6H2Mx0i1axXf0,6005
39
+ phoenix/experimental/evals/utils/__init__.py,sha256=PnCsNppI9KRFrQpsKWbLN58FNXsnUA3qqjLwNhoe_6Q,3715
38
40
  phoenix/experimental/evals/utils/threads.py,sha256=ksI-egarPnlxit0qKKjtjZ2L82qGLxqxZ6s92O0eBA4,1005
39
41
  phoenix/metrics/README.md,sha256=5gekqTU-5gGdMwvcfNp2Wlu8p1ul9kGY_jq0XXQusoI,1964
40
42
  phoenix/metrics/__init__.py,sha256=sLp7td1GIt_0Z8dPUyP4L0-_4x9c871yAaGX30oMsvg,2433
@@ -50,9 +52,9 @@ phoenix/pointcloud/pointcloud.py,sha256=ms-h1FLC0xXb3sk256zpSuZQDE2hdOAJzRNBklP0
50
52
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
51
53
  phoenix/pointcloud/umap_parameters.py,sha256=lJsEOrbSuSiqI7g4Yt6xj7kgYxEqoep4ZHWLr6VWBqw,1760
52
54
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
- phoenix/server/app.py,sha256=BTHd3hK1uCR8FS_EN86dQ5tdvFux6vsF47x_w5l--Z0,7070
55
+ phoenix/server/app.py,sha256=SEKUBgiXCH6tCXelrzbuwuY_EbDFC8CD7J5W7BkZSzM,7125
54
56
  phoenix/server/evaluation_handler.py,sha256=HzaoD8Cv9HbEdd0nYSTZoakKsE8Ic5lVjeuBh0vnhoA,1554
55
- phoenix/server/main.py,sha256=jZipipFs3jUFPr3y_yvqdKEgtjF3TdMK7UYanYqdINQ,6650
57
+ phoenix/server/main.py,sha256=cBJ_S_6TQBlV0Uj6N6ps3xq86VIv6nYKR49OYDcborg,6775
56
58
  phoenix/server/span_handler.py,sha256=TCwzbvtKfAc3CaI2Ao7Q5cfORWtQ56cU7j-43wgbOBc,1263
57
59
  phoenix/server/thread_server.py,sha256=a9Vnzc69ZLqJbI_FUSOY3eeuYCiCq6aprPj2gS_RB-M,2097
58
60
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -119,7 +121,7 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
119
121
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
120
122
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
121
123
  phoenix/server/static/index.css,sha256=KKGpx4iwF91VGRm0YN-4cn8oC-oIqC6HecoPf0x3ZM8,1885
122
- phoenix/server/static/index.js,sha256=huKhVku8d8SJ1kbxInNmUbfwJDuWEHplVlMQE6kDIsM,3195596
124
+ phoenix/server/static/index.js,sha256=hxV2PRT6IFyBLfCFykM1Xi537pefpFiNVeJTcU4YZyI,3216221
123
125
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
124
126
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
127
  phoenix/server/templates/index.html,sha256=UKAw1N5ysyOYiFgP5Hfd4oaSqc_Y7quEtC9FGvtsIBA,1425
@@ -151,7 +153,7 @@ phoenix/trace/llama_index/callback.py,sha256=YW3qqzWZUEs9aiDx-2628Eae_rct_Yb-DDz
151
153
  phoenix/trace/llama_index/debug_callback.py,sha256=SKToD9q_QADSGTJ5lhilqRVKaUnUSRXUvURCzN4by2U,1367
152
154
  phoenix/trace/llama_index/streaming.py,sha256=5cTtr8evvcEAB88Xb4ih3WEw0xAF4x5W9PehUX9l5_0,3258
153
155
  phoenix/trace/openai/__init__.py,sha256=J3G0uqCxGdksUpaQVHds_Egv2drvh8UEqoLjiQAOveg,79
154
- phoenix/trace/openai/instrumentor.py,sha256=UKbLn7XnhGRDCOmpuvo91yUAXslpSOjzRVdMap3rV-U,23367
156
+ phoenix/trace/openai/instrumentor.py,sha256=H1T2_1uqeH2lKCKeMmirEUl6PRtHQlQTXfsLR_hwDFM,24948
155
157
  phoenix/trace/v1/__init__.py,sha256=gzPW6vBuE_Z1bymL935cuiFBty1Tl9v2RCgAKY6vfPM,200
156
158
  phoenix/trace/v1/evaluation_pb2.py,sha256=8sXvv2BW_vqD30MOMbmkeE2zpmm7ncik21kl3e-HzeQ,2254
157
159
  phoenix/trace/v1/evaluation_pb2.pyi,sha256=cCbbx06gwQmaH14s3J1X25TtaARh-k1abbxQdQCXGm8,4500
@@ -161,8 +163,8 @@ phoenix/trace/v1/utils.py,sha256=j7gunL9CuSi7Xif56oWYGx0sc7KjfJhXzWcJia4ZM-8,178
161
163
  phoenix/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
164
  phoenix/utilities/error_handling.py,sha256=7b5rpGFj9EWZ8yrZK1IHvxB89suWk3lggDayUQcvZds,1946
163
165
  phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,222
164
- arize_phoenix-1.9.1rc2.dist-info/METADATA,sha256=2mcwsD5CIJSenW4g6OymRAoIzKHlzJbgz6O9LZw0rc4,26313
165
- arize_phoenix-1.9.1rc2.dist-info/WHEEL,sha256=rKV0FgtKSxe-Q3jTBlmgn27qdhTm0_K1YKwPwAPskZ0,87
166
- arize_phoenix-1.9.1rc2.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
167
- arize_phoenix-1.9.1rc2.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
168
- arize_phoenix-1.9.1rc2.dist-info/RECORD,,
166
+ arize_phoenix-2.0.0.dist-info/METADATA,sha256=aPHvi6tNxDcZhbOnRkeFus1Zw5dvniTbkET_ythER2c,26310
167
+ arize_phoenix-2.0.0.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
168
+ arize_phoenix-2.0.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
169
+ arize_phoenix-2.0.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
170
+ arize_phoenix-2.0.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.20.0
2
+ Generator: hatchling 1.21.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
phoenix/__init__.py CHANGED
@@ -6,7 +6,7 @@ from .session.session import NotebookEnvironment, Session, active_session, close
6
6
  from .trace.fixtures import load_example_traces
7
7
  from .trace.trace_dataset import TraceDataset
8
8
 
9
- __version__ = "1.9.1rc2"
9
+ __version__ = "2.0.0"
10
10
 
11
11
  # module level doc-string
12
12
  __doc__ = """
phoenix/core/traces.py CHANGED
@@ -169,7 +169,7 @@ class Traces:
169
169
  if (
170
170
  (span := self[span_id])
171
171
  and start_time <= span.start_time < stop_time
172
- and (span.parent_id is None) == bool(root_spans_only)
172
+ and (not root_spans_only or span.parent_id is None)
173
173
  ):
174
174
  yield span
175
175
  return
phoenix/exceptions.py ADDED
@@ -0,0 +1,2 @@
1
+ class PhoenixException(Exception):
2
+ pass
@@ -1,3 +1,4 @@
1
+ from .evaluators import LLMEvaluator
1
2
  from .functions import llm_classify, llm_generate, run_relevance_eval
2
3
  from .models import BedrockModel, LiteLLMModel, OpenAIModel, VertexAIModel
3
4
  from .retrievals import compute_precisions_at_k
@@ -8,7 +9,6 @@ from .templates import (
8
9
  HALLUCINATION_PROMPT_TEMPLATE,
9
10
  HUMAN_VS_AI_PROMPT_RAILS_MAP,
10
11
  HUMAN_VS_AI_PROMPT_TEMPLATE,
11
- NOT_PARSABLE,
12
12
  QA_PROMPT_RAILS_MAP,
13
13
  QA_PROMPT_TEMPLATE,
14
14
  RAG_RELEVANCY_PROMPT_RAILS_MAP,
@@ -18,7 +18,7 @@ from .templates import (
18
18
  ClassificationTemplate,
19
19
  PromptTemplate,
20
20
  )
21
- from .utils import download_benchmark_dataset
21
+ from .utils import NOT_PARSABLE, download_benchmark_dataset
22
22
 
23
23
  __all__ = [
24
24
  "compute_precisions_at_k",
@@ -29,6 +29,7 @@ __all__ = [
29
29
  "VertexAIModel",
30
30
  "BedrockModel",
31
31
  "LiteLLMModel",
32
+ "LLMEvaluator",
32
33
  "PromptTemplate",
33
34
  "ClassificationTemplate",
34
35
  "CODE_READABILITY_PROMPT_RAILS_MAP",
@@ -1,10 +1,11 @@
1
- from typing import List, Mapping, Optional
1
+ from typing import List, Mapping, Optional, Tuple
2
2
 
3
3
  from phoenix.experimental.evals.models import set_verbosity
4
+ from phoenix.experimental.evals.utils import parse_openai_function_call, snap_to_rail
4
5
  from phoenix.utilities.logging import printif
5
6
 
6
7
  from .models import BaseEvalModel
7
- from .templates import ClassificationTemplate, PromptTemplate
8
+ from .templates import ClassificationTemplate, PromptOptions, PromptTemplate
8
9
 
9
10
  Record = Mapping[str, str]
10
11
 
@@ -20,51 +21,80 @@ class LLMEvaluator:
20
21
  self,
21
22
  model: BaseEvalModel,
22
23
  template: ClassificationTemplate,
23
- name: str,
24
- verbose: bool = False,
25
24
  ) -> None:
26
25
  """Initializer for LLMEvaluator.
27
26
 
28
27
  Args:
29
28
  model (BaseEvalModel): The LLM model to use for evaluation.
30
29
  template (ClassificationTemplate): The evaluation template.
31
- name (str): The name of the evaluator.
32
- verbose (bool, optional): Whether to print verbose output.
33
30
  """
34
31
  self._model = model
35
32
  self._template = template
36
- self.name = name
37
- self._verbose = verbose
38
33
 
39
- def evaluate(self, record: Record) -> str:
40
- """Evaluates a single record.
34
+ def evaluate(
35
+ self,
36
+ record: Record,
37
+ provide_explanation: bool = False,
38
+ verbose: bool = False,
39
+ ) -> Tuple[str, Optional[str]]:
40
+ """
41
+ Evaluates a single record.
41
42
 
42
43
  Args:
43
44
  record (Record): The record to evaluate.
44
45
 
46
+ provide_explanation (bool, optional): Whether to provide an
47
+ explanation.
48
+
49
+ verbose (bool, optional): Whether to print verbose output.
50
+
45
51
  Returns:
46
- EvaluationResult: The result of the evaluation
52
+ Tuple[str, Optional[str]]: The label and explanation (if provided).
47
53
  """
48
- prompt = self._template.format(record)
49
- with set_verbosity(self._model, self._verbose) as verbose_model:
54
+ prompt = self._template.format(
55
+ record, options=PromptOptions(provide_explanation=provide_explanation)
56
+ )
57
+ with set_verbosity(self._model, verbose) as verbose_model:
50
58
  unparsed_output = verbose_model(prompt)
51
- parsed_output = _snap_to_rail(unparsed_output, self._template.rails, self._verbose)
52
- return parsed_output
53
-
54
- async def aevaluate(self, record: Record) -> str:
55
- """Evaluates a single record.
59
+ label, explanation = _extract_label_and_explanation(
60
+ unparsed_output=unparsed_output,
61
+ template=self._template,
62
+ use_openai_function_call=False,
63
+ provide_explanation=provide_explanation,
64
+ verbose=verbose,
65
+ )
66
+ return label, explanation
67
+
68
+ async def aevaluate(
69
+ self, record: Record, provide_explanation: bool = False, verbose: bool = False
70
+ ) -> Tuple[str, Optional[str]]:
71
+ """
72
+ Evaluates a single record.
56
73
 
57
74
  Args:
58
75
  record (Record): The record to evaluate.
59
76
 
77
+ provide_explanation (bool, optional): Whether to provide an
78
+ explanation.
79
+
80
+ verbose (bool, optional): Whether to print verbose output.
81
+
60
82
  Returns:
61
- EvaluationResult: The result of the evaluation
83
+ Tuple[str, Optional[str]]: The label and explanation (if provided).
62
84
  """
63
- prompt = self._template.format(dict(record))
64
- with set_verbosity(self._model, self._verbose) as verbose_model:
85
+ prompt = self._template.format(
86
+ record, options=PromptOptions(provide_explanation=provide_explanation)
87
+ )
88
+ with set_verbosity(self._model, verbose) as verbose_model:
65
89
  unparsed_output = await verbose_model._async_generate(prompt)
66
- parsed_output = _snap_to_rail(unparsed_output, self._template.rails, self._verbose)
67
- return parsed_output
90
+ label, explanation = _extract_label_and_explanation(
91
+ unparsed_output=unparsed_output,
92
+ template=self._template,
93
+ use_openai_function_call=False,
94
+ provide_explanation=provide_explanation,
95
+ verbose=verbose,
96
+ )
97
+ return label, explanation
68
98
 
69
99
 
70
100
  class MapReducer:
@@ -202,33 +232,46 @@ class Refiner:
202
232
  return model(reduce_prompt)
203
233
 
204
234
 
205
- def _snap_to_rail(raw_string: Optional[str], rails: List[str], verbose: bool = False) -> str:
235
+ def _extract_label_and_explanation(
236
+ unparsed_output: str,
237
+ template: ClassificationTemplate,
238
+ provide_explanation: bool,
239
+ use_openai_function_call: bool,
240
+ verbose: bool,
241
+ ) -> Tuple[str, Optional[str]]:
206
242
  """
207
- Snaps a string to the nearest rail, or returns None if the string cannot be
208
- snapped to a rail.
243
+ Extracts the label and explanation from the unparsed output.
209
244
 
210
245
  Args:
211
- raw_string (str): An input to be snapped to a rail.
246
+ unparsed_output (str): The raw output to be parsed.
247
+
248
+ template (ClassificationTemplate): The template used to generate the
249
+ output.
212
250
 
213
- rails (List[str]): The target set of strings to snap to.
251
+ provide_explanation (bool): Whether the output includes an explanation.
252
+
253
+ use_openai_function_call (bool): Whether the output was generated using
254
+ function calling.
255
+
256
+ verbose (bool): If True, print verbose output to stdout.
214
257
 
215
258
  Returns:
216
- str: A string from the rails argument or "UNPARSABLE" if the input
217
- string could not be snapped.
259
+ Tuple[str, Optional[str]]: A tuple containing the label and an
260
+ explanation (if one is provided).
218
261
  """
219
- if not raw_string:
220
- return NOT_PARSABLE
221
- snap_string = raw_string.lower()
222
- rails = list(set(rail.lower() for rail in rails))
223
- rails.sort(key=len, reverse=True)
224
- found_rails = set()
225
- for rail in rails:
226
- if rail in snap_string:
227
- found_rails.add(rail)
228
- snap_string = snap_string.replace(rail, "")
229
- if len(found_rails) != 1:
230
- printif(verbose, f"- Cannot snap {repr(raw_string)} to rails")
231
- return NOT_PARSABLE
232
- rail = list(found_rails)[0]
233
- printif(verbose, f"- Snapped {repr(raw_string)} to rail: {rail}")
234
- return rail
262
+ if not use_openai_function_call:
263
+ if provide_explanation:
264
+ unrailed_label, explanation = (
265
+ template.extract_label_from_explanation(unparsed_output),
266
+ unparsed_output,
267
+ )
268
+ printif(
269
+ verbose and unrailed_label == NOT_PARSABLE,
270
+ f"- Could not parse {repr(unparsed_output)}",
271
+ )
272
+ else:
273
+ unrailed_label = unparsed_output
274
+ explanation = None
275
+ else:
276
+ unrailed_label, explanation = parse_openai_function_call(unparsed_output)
277
+ return snap_to_rail(unrailed_label, template.rails, verbose=verbose), explanation