langchain-ai / langserve

LangServe 🦜️🏓
Other
1.75k stars 184 forks source link

Use HTTPException with LangServe #667

Open DeepanshKhurana opened 1 month ago

DeepanshKhurana commented 1 month ago

Hello. Apologies if this is a duplicate, but I couldn't find anything super relevant to what I'm trying to do. I've created a reproducible example here.

The idea is that I want to be able to send a proper exception from the chain -- a 422 when something isn't relevant. Note that this is a toy example to illustrate the point, but I want to do this on a larger chain I'm working on.

When I use an HTTPException, I get the error TypeError: Type is not JSON serializable: HTTPException, which makes sense to me since the final output would take a dict, str, or JSON structure. But is there a way/workaround to make this work that I may be missing?

If the link somehow isn't accessible, here is the chain.

import json
from typing import Dict
from dotenv import load_dotenv
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.runnables import RunnableLambda
from langchain_openai import ChatOpenAI
from fastapi import HTTPException

load_dotenv()

model = ChatOpenAI(model="gpt-3.5-turbo")

class FruitModel(BaseModel):
    shape: str = Field(
        ...,
        description="The shape of the fruit",
    )
    color: str = Field(
        ...,
        description="The color of the fruit",
    )
    taste: str = Field(
        ...,
        description="The taste of the fruit"
    )

template = "You are describing a {fruit}. Please provide the name, shape, and color of the fruit as per the {format_instructions}."

parser = JsonOutputParser(pydantic_object=FruitModel)   

def post_process_result(result):
    result = json.loads(f"result")
    if not result["is_fruit"]:
        raise HTTPException(status_code=400, detail="The object is not a fruit.")
    else:
        return result

prompt=PromptTemplate(
    template=template,
    input_variables=["fruit"],
    partial_variables={
        "format_instructions": parser.get_format_instructions()
    }
)

def is_input_numeric(input):
    return {
        "input": input,
        "result": input.isnumeric()
    }

chain = RunnableLambda(is_input_numeric).with_types(input_type=str, output_type=Dict) | RunnableLambda(
    lambda x: HTTPException(
        status_code=422,
        detail=f"{x['input']} is not string."
    ) if x["result"] else RunnableLambda(
        lambda x: x["input"]
     ).with_types(
         output_type = str
     ) | prompt | model | parser
)