fromtypingimport(Any,List,Optional,Tuple,Type,TypedDict,Union,)fromlangchain_core.documentsimportDocumentfromlangchain_core.runnablesimportRunnableConfig,RunnableSerializable,ensure_configfromlangchain_ai21.ai21_baseimportAI21BaseANSWER_NOT_IN_CONTEXT_RESPONSE="Answer not in context"ContextType=Union[str,List[Union[Document,str]]]
[docs]classContextualAnswerInput(TypedDict):"""Input for the ContextualAnswers runnable."""context:ContextTypequestion:str
[docs]classAI21ContextualAnswers(RunnableSerializable[ContextualAnswerInput,str],AI21Base):"""Runnable for the AI21 Contextual Answers API."""classConfig:"""Configuration for this pydantic object."""arbitrary_types_allowed=True@propertydefInputType(self)->Type[ContextualAnswerInput]:"""Get the input type for this runnable."""returnContextualAnswerInput@propertydefOutputType(self)->Type[str]:"""Get the input type for this runnable."""returnstr
def_call_contextual_answers(self,input:ContextualAnswerInput,response_if_no_answer_found:str,)->str:context,question=self._convert_input(input)response=self.client.answer.create(context=context,question=question)ifresponse.answerisNone:returnresponse_if_no_answer_foundreturnresponse.answerdef_convert_input(self,input:ContextualAnswerInput)->Tuple[str,str]:context,question=self._extract_context_and_question(input)context=self._parse_context(context)returncontext,questiondef_extract_context_and_question(self,input:ContextualAnswerInput,)->Tuple[ContextType,str]:context=input.get("context")question=input.get("question")ifnotcontextornotquestion:raiseValueError(f"Input must contain a 'context' and 'question' fields. Got {input}")ifnotisinstance(context,list)andnotisinstance(context,str):raiseValueError(f"Expected input to be a list of strings or Documents."f" Received {type(input)}")returncontext,questiondef_parse_context(self,context:ContextType)->str:ifisinstance(context,str):returncontextdocs=[item.page_contentifisinstance(item,Document)elseitemforitemincontext]return"\n".join(docs)