import json import os from typing import Literal import datetime from ollama import chat, ChatResponse, Client from openai import OpenAI from pydantic import BaseModel, Field # Configure ollama client with URL from environment or default to localhost ollama_client = Client(host=os.getenv("OLLAMA_URL", "http://localhost:11434")) # This uses inferred filters — which means using LLM to create the metadata filters class FilterOperation(BaseModel): op: Literal["$gt", "$gte", "$eq", "$ne", "$lt", "$lte", "$in", "$nin"] value: str | list[str] class FilterQuery(BaseModel): field_name: Literal["created_date, tags"] op: FilterOperation class AndQuery(BaseModel): op: Literal["$and", "$or"] subqueries: list[FilterQuery] class GeneratedQuery(BaseModel): fields: list[str] extracted_metadata_fields: str class Time(BaseModel): time: int PROMPT = """ You are an information specialist that processes user queries. The current year is 2025. The user queries are all about a cat, Simba, and its records. The types of records are listed below. Using the query, extract the the date range the user is trying to query. You should return it as a JSON. The date tag is created_date. Return the date in epoch time. If the created_date cannot be ascertained, set it to epoch time start. You have several operators at your disposal: - $gt: greater than - $gte: greater than or equal - $eq: equal - $ne: not equal - $lt: less than - $lte: less than or equal to - $in: in - $nin: not in Logical operators: - $and, $or ### Example 1 Query: "Who is Simba's current vet?" Metadata fields: "{"created_date"}" Extracted metadata fields: {"created_date: {"$gt": "2025-01-01"}} ### Example 2 Query: "How many teeth has Simba had removed?" Metadata fields: {} Extracted metadata fields: {} ### Example 3 Query: "How many times has Simba been to the vet this year?" Metadata fields: {"created_date"} Extracted metadata fields: {"created_date": {"gt": "2025-01-01"}} document_types: - aftercare - bill - insurance claim - medical records Only return the extracted metadata fields. Make sure the extracted metadata fields are valid JSON """ USE_OPENAI = os.getenv("OPENAI_API_KEY", None) != None class QueryGenerator: def __init__(self) -> None: pass def date_to_epoch(self, date_str: str) -> float: split_date = date_str.split("-") date = datetime.datetime( int(split_date[0]), int(split_date[1]), int(split_date[2]), 0, 0, 0, ) return date.timestamp() def get_query(self, input: str): if USE_OPENAI: client = OpenAI() response = client.responses.parse( model="gpt-4o", input=[ {"role": "system", "content": PROMPT}, {"role": "user", "content": input}, ], text_format=GeneratedQuery, ) print(response.output) query = json.loads(response.output_parsed.extracted_metadata_fields) else: response: ChatResponse = ollama_client.chat( model="gemma3n:e4b", messages=[ {"role": "system", "content": PROMPT}, {"role": "user", "content": input}, ], format=GeneratedQuery.model_json_schema(), ) query = json.loads( json.loads(response["message"]["content"])["extracted_metadata_fields"] ) date_key = list(query["created_date"].keys())[0] query["created_date"][date_key] = self.date_to_epoch( query["created_date"][date_key] ) if "$" not in date_key: query["created_date"]["$" + date_key] = query["created_date"][date_key] return query if __name__ == "__main__": qg = QueryGenerator() print(qg.get_query("How heavy is Simba?"))