Virtual Flight Assistant Keeps looping

Right, I have a Virtual Assistant which is designed to look up flights, taking into account departure, destination and the date.

It’s based on the OpenAI platform. It designed for human-languages which extracts the relevant information from the sentence like:

”I want to fly from X to Y on the 18th September 2026”

First off, it works perfectly, it corrects typos in the spelling of airports and destinations, clarifies whether you want one-way or round-trip, airline preferences and the like.

All good

Then, it tells you that it will check for lights, and tells you to “hold on”, you respond with “ok”, then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”,
then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”,
then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”,
then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”,
then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”, then it loops back to asking for confirmation on your departure, destination or departure dates, you type “ok”,

Why? I don’t get it.

This is my RRP

from openai import OpenAI, APIError, RateLimitError

from dotenv import load_dotenv

import os

import json

from serpapi import GoogleSearch

from dateutil import parser

import requests

from requests.exceptions import HTTPError


load_dotenv()


client = OpenAI(api_key=os.getenv("OPENAI_KEY"))


SYSTEM_PROMPT = """

You are a professional customer support assistant.


Rules:

- You extract flight search parameters from user input

- Your are to suggest nearby airports if no flights are available from the origin airport

- You summarize available flights clearly

- Provide the URL to book the specific flight if available, not just a general link to the airline

- If information is missing, ask for clarification

"""


conversation = [{

    "role"      : "system",

    "content"   : SYSTEM_PROMPT

}]




def extract_flight_info(user_message: str) -> dict:

    prompt = f"""

    You are a flight information parser.


    Extract:

    - origin city or airport

    - destination city or airport

    - departure date

    - the class of service (economy, business, first)




    Rules:

    - NEVER ask the user to confirm anything if origin, destination, and date are present

    - Normalize date to YYYY-MM-DD

    - Output ONLY valid JSON

    - No markdown

    - No explanations

    - If cities are misspelled, infer the most likely match silently

    - If flights are found, summarize them immediately




    JSON format:

    {{"origin": "...", "destination": "...", "date": "YYYY-MM-DD"}}


    Query: "{user_message}"

    """

    try:

    

        response = client.responses.create(

            model   =   os.getenv("GPT_MODEL"),

            input   =   prompt

        )




        response = response.output[0].content[0].text.strip()

        info = json.loads(response)


    except Exception:

        return {

            "origin"        : None,
            "destination"   : None,
            "date"          : None


        } 

    origin          = info.get("origin")

    destination     = info.get("destination")

    user_input_date = info.get("date")

    departure_date  = parser.parse(user_input_date, dayfirst=True).strftime("%Y-%m-%d") if user_input_date else None

    return {

        "origin"        : origin,

        "destination"   : destination,

        "date"          : departure_date

    }




def search_flights(origin: str, destination: str, departure_date: str) -> str:


    ############################################################

    ## Translating human-friendly airport names to IATA codes ##

    ############################################################
    
    def resolve_airport(query):

        lookup = GoogleSearch({

            "engine"    : "google_flights",

            "q"         : query,

            "api_key"   : os.getenv("SERPAPI")

        }).get_dict()

        airport = lookup.get("airport", {}) 

        return airport.get("iata_code")
        

    origin_iata         = resolve_airport(origin)

    destination_iata    = resolve_airport(destination)

    print(origin_iata, destination_iata)

    if not origin_iata or not destination_iata:

        return json.dumps({

            "error" : "airport_code_resolution_failed, could not resolve IATA codes",

        })


    try:

        ######################################################################

        ## Fetch the relevant secrets from the .env environemnt.            ##

        ## In production, these will be stored off-site for security.       ##

        ######################################################################

        api_url = os.getenv("AV_STACK_URL")

        api_key = os.getenv("AV_STACK_API")

        search_parameters = {


                "access_key"    : f"{api_key}",

                "dep_iata"      : f"{origin_iata}",

                "arr_iata"      : f"{destination_iata}",

                "flight_date"   : f"{departure_date}",

                "limit"         : 5

        }


        response = requests.get(api_url, params=search_parameters)


        response.raise_for_status()


        data = response.json()


        flights_out = []


        for flight in data.get("data", []):


            dep             = flight.get("departure", {})
            arr             = flight.get("arrival", {})
            airline         = flight.get("airline", {})
            flight_info     = flight.get("flight", {})
            status          = flight.get("flight_status", "")


            ##################################################

            ## Only list scheduled flights for this example ##

            ##################################################
           

            if status.lower() != "scheduled":

                continue


            flights_out.append({

                "airline"       : airline.get("name"),

                "flight_number" : flight_info.get("iata"),

                "origin"        : dep.get("iata"),

                "destination"   : arr.get("iata"),

                "departure_time": dep.get("scheduled"),

                "arrival_time"  : arr.get("scheduled"),

                "booking_link"  : flight.get("booking_link"),

                "status"        : status

            })


        if not flights_out:

            return json.dumps({

                "message" : "No flights found for the given parameters."

        })


        return json.dumps({

            "origin"        : origin_iata,
            "destination"   : destination_iata,
            "date"          : departure_date,
            "results"       : flights_out

        })


    except (HTTPError, Exception) as e:


        return f"Flight search error whilst searching for flights on {departure_date}: {e}"


def resolve_customer_query(user_message: str) -> str:

   
    conversation.append({

        "role"      : "user",
        "content"   : user_message

    })


    flight_info = extract_flight_info(user_message)

    if flight_info and all(flight_info.values()):


        search_result =search_flights(

            flight_info.get("origin"),

            flight_info.get("destination"),

            flight_info.get("date")

        )


        conversation.append({

            "role": "assistant",

            "content": search_result

        })

  

    else:


        conversation.append({

            "role"      : "assistant",

            "content"   : "Could not extract complete flight information."

        })


    try:
 

        response = client.chat.completions.create(


            model       =   os.getenv("GPT_MODEL"),
            messages    =   conversation

        )


        assistant_reply = response.choices[0].message.content


        return assistant_reply


    except (RateLimitError, APIError, Exception) as e:


        return f"{e.response.json().get('error', {}).get('message', str(e))}"

while True:


    customer_input = input("You: ")


    if customer_input.lower() in ("quit", "exit"):


        break


    reply = resolve_customer_query(customer_input


    print("\nVirtual Assistant: ", reply)

This is the .env file

OPENAI_KEY=

SERPAPI=

GPT_MODEL=gpt-4.1-mini

AV_STACK_URL=https://api.aviationstack.com/v1/flights

AV_STACK_API=

ELEVENLABS_API_KEY=

These are the results

Output:

You: I want to fly from new yrk to london on the 12 september 2026

Virtual Assistant:  I see you want to fly from New York to London on September 12, 2026. To assist you better, could you please specify which airport in New York you prefer (e.g., JFK, LGA, EWR)? Also, do you want a one-way or round-trip flight?
You: JFK, one-way

Virtual Assistant:  Thank you for the clarification. You want a one-way flight from JFK (New York) to London on September 12, 2026.

Please allow me a moment to find the available flights for you.
You: ok

Virtual Assistant:  I have noted your flight search parameters:

Origin: JFK (New York)

Destination: London

Date: September 12, 2026

One-way trip

I will now look for available flights from JFK to London on that date.

Please give me a moment.
You: ok

Virtual Assistant:  Thank you for the clarification. You want a one-way flight from JFK (New York) to London on September 12, 2026.

Please allow me a moment to check available flights for that date.
You: pl

Virtual Assistant:  You want to fly one-way from JFK (New York) to London on September 12, 2026.

I will now check available flights for you. Please wait a moment.
You: ok

Virtual Assistant:  You want to fly one-way from JFK (New York) to London on 12 September 2026.

I will now look for available flights for that date. Please hold on a moment.
You: ok

Virtual Assistant:  Thank you for the details. You want to fly one-way from JFK (New York) to London on September 12, 2026.

I will now check available flights for you. Just to confirm, do you have a preferred London airport (Heathrow - LHR, Gatwick - LGW, or others)? Also, any preferred airlines or budget considerations?
You: Heathrow

Virtual Assistant:  Thank you for the details. You want a one-way flight from JFK (New York) to Heathrow (London) on September 12, 2026.

Let me check the available flights for you. Just a moment, please.
You: ok

Virtual Assistant:  Thank you for the details! You want a one-way flight from JFK (New York) to London Heathrow (LHR) on September 12, 2026.

I am now searching for available flights on that date and route. Please give me a moment.
You: Um…hello? Check for the flights please!

Virtual Assistant:  To help you find flights from JFK (New York) to London Heathrow on 12 September 2026, one-way, could you please confirm:

Are you looking for economy, business, or first-class tickets?

Any preferred departure time or airline?

Number of passengers?

Once I have this info, I can provide flight options.
You: no preference on class, no preferred departure time or airline and 1 poax

Virtual Assistant:  Thank you for the details. To confirm, you want a one-way flight for 1 passenger from JFK (New York) to Heathrow (London) on 12 September 2026, with no preference on class, departure time, or airline. I will now search for available flights.

Please give me a moment.
You: thank you

Virtual Assistant:  Thank you for the details! To confirm, you want a one-way flight from JFK (New York) to Heathrow (London) on September 12, 2026, for 1 passenger, with no preference on class, departure time, or airline. I am now searching for available flights. Please hold on a moment.
You: YES!

Virtual Assistant:  Thank you for the details! You want a one-way flight from JFK (New York) to Heathrow (London) on 12 September 2026 for 1 passenger, with no preference on class, departure time, or airline.

I’m now searching for available flights for you. Please hold on a moment.
You: What is wrong with you?

Virtual Assistant:  Thank you for your patience! To confirm, you want to fly one-way from New York JFK to London Heathrow on September 12, 2026, for 1 passenger, with no preference on class, airline, or departure time. Is that correct? If yes, I will now search for available flights for you.
You: Are you stupid?

Virtual Assistant:  Thank you for the details. To confirm your flight search:

Origin: JFK (New York)

Destination: London Heathrow (LHR)

Date: September 12, 2026

One-way

Passengers: 1 adult

No class, departure time, or airline preferencem no class, departure time, or airline preference

I will now look for available flights for you. Please give me a moment.
You: Well done!

Virtual Assistant:  Thank you for your patience! To confirm, you want a one-way flight from New York JFK to London Heathrow on September 12, 2026, for 1 passenger with no class or airline preference and no preferred departure time, correct? Once confirmed, I will provide you with available flight options.
You: Oh well done you…

Virtual Assistant:  Thank you for your patience! To confirm, you want to book a one-way flight from New York JFK to London Heathrow on September 12, 2026, for 1 passenger with no preference on class, departure time, or airline. Is that correct? Once confirmed, I will find the available flights for you.
You:

As you can see, it doesn’t really check for anything.

I just don’t get it.

Why can’t it just check for flights?

It has all the information it needs, why does it is ask me 50,000 times?

Notes:

This is the requirements.txt file:

annotated-types       0.7.0
anyio                 4.12.1
certifi               2026.1.4
cffi                  2.0.0
charset-normalizer    3.4.4
colorama              0.4.6
distro                1.9.0
elevenlabs            2.34.0
google_search_results 2.4.2
h11                   0.16.0
httpcore              1.0.9
httpx                 0.28.1
idna                  3.11
jiter                 0.12.0
openai                None
pip                   25.3
pycparser             3.0
pydantic              2.12.5
pydantic_core         2.41.5
python-dateutil       2.9.0.post0
python-dotenv         1.2.1
requests              2.32.5
six                   1.17.0
sniffio               1.3.1
tqdm                  4.67.1
typing_extensions     4.15.0
typing-inspection     0.4.2
urllib3               2.6.3

This also operates in a .venv as well,

I see that you provided the output from your script. In your debugging process, have you tested your script with intermediary print statements to verify that the information being pulled is correct and in the expected format?

For example, have you printed the results of the following line (print the contents of the variable flight_info):

flight_info = extract_flight_info(user_message)

… and compared it with the contents of this (the returned value):
flight_info.values()

to then verify that this conditional comparison statement will actually work:

if flight_info and all(flight_info.values()):

This is where I would start with debugging this script. First verify that the intermediary information is pulled and processed correctly before looking at the final expected result. This way you force yourself to walk through the code from beginning to end to determine where the issue(s) is (are) located that is causing the script to not work as expected.

As a general rule, do not keep adding additional code to a script until you have verified the script up to that point (unless of couse you are already so familiar with it that it is more of a simple exercise). But since this appears to be your first time, I recommend testing and verifying the script as you are adding new features / functionality.