|
| 1 | +import json |
1 | 2 | import logging |
2 | 3 | from enum import Enum |
3 | 4 | from pprint import pformat |
|
9 | 10 | from haystack import Pipeline |
10 | 11 | from haystack.components.builders import ChatPromptBuilder |
11 | 12 | from haystack.core.errors import PipelineRuntimeError |
12 | | -from openinference.instrumentation import using_attributes, using_metadata |
| 13 | +from openinference.instrumentation import _tracers, using_attributes, using_metadata |
| 14 | +from opentelemetry.trace.status import Status, StatusCode |
13 | 15 | from pydantic import BaseModel |
14 | 16 |
|
15 | | -from src.common import components, haystack_utils |
| 17 | +from src.common import components, haystack_utils, phoenix_utils |
16 | 18 |
|
17 | 19 | logger = logging.getLogger(__name__) |
| 20 | +tracer = phoenix_utils.tracer_provider.get_tracer(__name__) |
18 | 21 |
|
19 | 22 |
|
20 | 23 | class ReferralType(str, Enum): |
@@ -97,37 +100,53 @@ def setup(self) -> None: |
97 | 100 | # Called for the `generate-referrals/run` endpoint |
98 | 101 | def run_api(self, query: str, user_email: str, prompt_version_id: str = "") -> dict: |
99 | 102 | with using_attributes(user_id=user_email), using_metadata({"user_id": user_email}): |
100 | | - # Retrieve the requested prompt_version_id and error if requested prompt version is not found |
101 | | - try: |
102 | | - prompt_template = haystack_utils.get_phoenix_prompt( |
103 | | - "generate_referrals", prompt_version_id |
104 | | - ) |
105 | | - except httpx.HTTPStatusError as he: |
106 | | - raise HTTPException( |
107 | | - status_code=422, |
108 | | - detail=f"The requested prompt version '{prompt_version_id}' could not be retrieved due to HTTP status {he.response.status_code}", |
109 | | - ) from he |
110 | | - |
111 | | - try: |
112 | | - response = self.pipeline.run( |
113 | | - { |
114 | | - "logger": { |
115 | | - "messages_list": [{"query": query, "user_email": user_email}], |
116 | | - }, |
117 | | - "prompt_builder": { |
118 | | - "template": prompt_template, |
119 | | - "query": query, |
120 | | - "response_json": response_schema, |
121 | | - }, |
122 | | - "llm": {"model": "gpt-5-mini", "reasoning_effort": "low"}, |
| 103 | + # Must set using_metadata context before calling tracer.start_as_current_span() |
| 104 | + assert isinstance(tracer, _tracers.OITracer), f"Got unexpected {type(tracer)}" |
| 105 | + with tracer.start_as_current_span( # pylint: disable=not-context-manager,unexpected-keyword-arg |
| 106 | + self.name, openinference_span_kind="chain" |
| 107 | + ) as span: |
| 108 | + result = self._run(query, user_email, prompt_version_id) |
| 109 | + span.set_input(query) |
| 110 | + try: |
| 111 | + resp_obj = json.loads(result["llm"]["replies"][-1].text) |
| 112 | + span.set_output([r["name"] for r in resp_obj["resources"]]) |
| 113 | + except (KeyError, IndexError): |
| 114 | + span.set_output(result["llm"]["replies"][-1].text) |
| 115 | + span.set_status(Status(StatusCode.OK)) |
| 116 | + return result |
| 117 | + |
| 118 | + def _run(self, query: str, user_email: str, prompt_version_id: str = "") -> dict: |
| 119 | + # Retrieve the requested prompt_version_id and error if requested prompt version is not found |
| 120 | + try: |
| 121 | + prompt_template = haystack_utils.get_phoenix_prompt( |
| 122 | + "generate_referrals", prompt_version_id |
| 123 | + ) |
| 124 | + except httpx.HTTPStatusError as he: |
| 125 | + raise HTTPException( |
| 126 | + status_code=422, |
| 127 | + detail=f"The requested prompt version '{prompt_version_id}' could not be retrieved due to HTTP status {he.response.status_code}", |
| 128 | + ) from he |
| 129 | + |
| 130 | + try: |
| 131 | + response = self.pipeline.run( |
| 132 | + { |
| 133 | + "logger": { |
| 134 | + "messages_list": [{"query": query, "user_email": user_email}], |
123 | 135 | }, |
124 | | - include_outputs_from={"llm", "save_result"}, |
125 | | - ) |
126 | | - logger.debug("Results: %s", pformat(response, width=160)) |
127 | | - return response |
128 | | - except PipelineRuntimeError as re: |
129 | | - logger.error("PipelineRuntimeError: %s", re, exc_info=True) |
130 | | - raise HTTPException(status_code=500, detail=str(re)) from re |
131 | | - except Exception as e: |
132 | | - logger.error("Error %s: %s", type(e), e, exc_info=True) |
133 | | - raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}") from e |
| 136 | + "prompt_builder": { |
| 137 | + "template": prompt_template, |
| 138 | + "query": query, |
| 139 | + "response_json": response_schema, |
| 140 | + }, |
| 141 | + "llm": {"model": "gpt-5-mini", "reasoning_effort": "low"}, |
| 142 | + }, |
| 143 | + include_outputs_from={"llm", "save_result"}, |
| 144 | + ) |
| 145 | + logger.debug("Results: %s", pformat(response, width=160)) |
| 146 | + return response |
| 147 | + except PipelineRuntimeError as re: |
| 148 | + logger.error("PipelineRuntimeError: %s", re, exc_info=True) |
| 149 | + raise HTTPException(status_code=500, detail=str(re)) from re |
| 150 | + except Exception as e: |
| 151 | + logger.error("Error %s: %s", type(e), e, exc_info=True) |
| 152 | + raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}") from e |
0 commit comments