11import json
22import logging
3+ import uuid
34from enum import Enum
45from pprint import pformat
5- from typing import Optional
6+ from typing import Generator , Optional
67
78import httpx
89from fastapi import HTTPException
910from hayhooks import BasePipelineWrapper
1011from haystack import Pipeline
1112from haystack .components .builders import ChatPromptBuilder
12- from haystack .dataclasses .chat_message import ChatMessage
1313from pydantic import BaseModel
1414
1515from src .app_config import config
@@ -103,17 +103,13 @@ def run_api(
103103 self , query : str , user_email : str , prompt_version_id : str = "" , suffix : str = ""
104104 ) -> dict :
105105 # Retrieve the requested prompt (with optional prompt_version_id and/or suffix)
106- try :
107- prompt_template = haystack_utils .get_phoenix_prompt (
108- "generate_referrals" , prompt_version_id = prompt_version_id , suffix = suffix
109- )
110- except httpx .HTTPStatusError as he :
111- raise HTTPException (
112- status_code = 422 ,
113- detail = f"The requested prompt version '{ prompt_version_id } ' with suffix '{ suffix } ' could not be retrieved due to HTTP status { he .response .status_code } " ,
114- ) from he
115- pipeline_run_args = self ._run_arg_data (
116- query , user_email , prompt_template , region = suffix or "centraltx"
106+
107+ pipeline_run_args = self .create_pipeline_args (
108+ query ,
109+ user_email ,
110+ prompt_version_id = prompt_version_id ,
111+ suffix = suffix ,
112+ region = suffix or "centraltx" ,
117113 )
118114
119115 def extract_output (result : dict ) -> list | str :
@@ -135,9 +131,29 @@ def extract_output(result: dict) -> list | str:
135131 logger .debug ("Results: %s" , pformat (response , width = 160 ))
136132 return response
137133
138- def _run_arg_data (
139- self , query : str , user_email : str , prompt_template : list [ChatMessage ], * , region : str
134+ def create_pipeline_args (
135+ self ,
136+ query : str ,
137+ user_email : str ,
138+ * ,
139+ region : str ,
140+ prompt_version_id : str = "" ,
141+ suffix : str = "" ,
142+ llm_model : str | None = None ,
143+ reasoning_effort : str | None = None ,
144+ streaming : bool = False ,
140145 ) -> dict :
146+ """Create pipeline run arguments with optional overrides for model, reasoning effort, and streaming."""
147+ try :
148+ prompt_template = haystack_utils .get_phoenix_prompt (
149+ "generate_referrals" , prompt_version_id = prompt_version_id , suffix = suffix
150+ )
151+ except httpx .HTTPStatusError as e :
152+ raise HTTPException (
153+ status_code = 422 ,
154+ detail = f"The requested prompt version '{ prompt_version_id } ' with suffix '{ suffix } ' could not be retrieved" ,
155+ ) from e
156+
141157 return {
142158 "logger" : {
143159 "messages_list" : [{"query" : query , "user_email" : user_email }],
@@ -148,7 +164,49 @@ def _run_arg_data(
148164 "response_json" : response_schema ,
149165 },
150166 "llm" : {
151- "model" : config .generate_referrals_model_version ,
152- "reasoning_effort" : config .generate_referrals_reasoning_level ,
167+ "model" : llm_model or config .generate_referrals_model_version ,
168+ "reasoning_effort" : reasoning_effort or config .generate_referrals_reasoning_level ,
169+ "streaming" : streaming ,
153170 },
154171 }
172+
173+ # https://docs.haystack.deepset.ai/docs/hayhooks#openai-compatibility
174+ # Called for the `{pipeline_name}/chat`, `/chat/completions`, or `/v1/chat/completions` streaming endpoint using Server-Sent Events (SSE)
175+ def run_chat_completion (self , model : str , messages : list , body : dict ) -> Generator :
176+ # Note: 'model' parameter is the pipeline name, not the LLM model
177+ assert model == self .name , f"Unexpected model/pipeline name: { model } "
178+
179+ # Extract custom parameters from the body
180+ query = body .get ("query" , "" )
181+ user_email = body .get ("user_email" , "" )
182+ suffix = body .get ("suffix" , "" )
183+
184+ if not query :
185+ raise ValueError ("query parameter is required" )
186+
187+ if not user_email :
188+ raise ValueError ("user_email parameter is required" )
189+
190+ pipeline_run_args = self .create_pipeline_args (
191+ query ,
192+ user_email ,
193+ prompt_version_id = body .get ("prompt_version_id" , "" ),
194+ suffix = body .get ("suffix" , "" ),
195+ region = suffix or "centraltx" ,
196+ llm_model = body .get ("llm_model" , None ),
197+ reasoning_effort = body .get ("reasoning_effort" , None ),
198+ streaming = True ,
199+ )
200+
201+ # Generate result_id upfront to pass to both SaveResult and the hook
202+ result_id = str (uuid .uuid4 ())
203+ pipeline_run_args ["save_result" ] = {"result_id" : result_id }
204+
205+ logger .info ("Streaming referrals: %s" , pipeline_run_args )
206+ return self .runner .stream_response (
207+ pipeline_run_args ,
208+ user_id = user_email ,
209+ metadata = {"user_id" : user_email },
210+ input_ = [query ],
211+ generator_hook = haystack_utils .create_result_id_hook (self .pipeline , result_id ),
212+ )
0 commit comments