File size: 4,483 Bytes
e454383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import re
import json
from openai import OpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.document_loaders import PyPDFLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import ChatOpenAI

class AiService:
    def __init__(self, model="gpt-4.1-mini"):
        self.OPENAI_MODEL = model
        self.embeddings = OpenAIEmbeddings(
            model="text-embedding-3-small"
        )
        self.openai = OpenAI()

    def generate_response(self, question_history=[], docs = [], extra_context: str = "", json_structure=None, instructions: str = None):
        # simplified $SELECTION_PLACEHOLDER$
        original_question = question_history[-1]["content"]

        # attach supporting docs
        if docs:
            print(f"Found {len(docs)} supporting documents")
            fragments = [str(d["payload"]) for d in docs]
            question_history[-1]["content"] += "\n\nSupporting documents:\n" + "\n\n".join(fragments)

        # attach extra context
        if extra_context:
            question_history[-1]["content"] += "\n\nExtra context:\n" + extra_context

        try:
            # common parameters
            params = {
                "instructions": instructions,
                "input": question_history,
                "model": self.OPENAI_MODEL,
                "temperature": 0.0,
                "top_p": 0.25
            }

            if json_structure:
                params["text_format"] = json_structure
                result = self.openai.responses.parse(**params)
                content = result.output_parsed
            else:
                result = self.openai.responses.create(**params)
                content = re.sub(r"\$", r"\\$", result.output_text)

            return content

        except Exception as e:
            print(f"Error during API request: {e}")
            return ""

        finally:
            # restore original question text
            question_history[-1]["content"] = original_question
    
    def generate_single_response(self, query, system_message, json_output=False, json_structure=None):
        question_history = [{"role": "system", "content": system_message}, {"role": "user", "content": query}]
        return self.generate_response(question_history, json_structure=json_structure)


    def json_response_cleaner(self, response):
        response = response.replace("\n", "").replace(
            "\t", "").replace("\\", "")
        return json.loads(response)

    def init_messages(self, system_message):
        return [{"role": "system", "content": system_message}]

    def add_user_message(self, messages, user_message):
        messages.append({"role": "user", "content": user_message})
        return messages

    def add_assistant_message(self, messages, assistant_message):
        messages.append({"role": "assistant", "content": assistant_message})
        return messages

    def search_pdf(self, pdf_path, query, schema, output_format):
        """
        Search through a PDF document and extract structured information.
        
        Args:
            pdf_path (str): Path to the PDF file
            query (str): Search query
            schema (dict): Schema defining the required output structure
        
        Returns:
            dict: Extracted structured information
        """
        # Load and split the PDF
        loader = PyPDFLoader(pdf_path)
        pages = loader.load()
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=100
        )
        splits = text_splitter.split_documents(pages)

        combined_content = "\n".join([chunk.page_content for chunk in splits])

        prompt = ChatPromptTemplate.from_template(
            """Extract the requested information from the following text, just write the answer to the question do not include that how the document discusses it or some other form of this. DIRECTLY ANSWER THE QUESTION.:
            
            {text}
            
            {schema}
            
            Query: {query}"""
        )

        messages = prompt.format_messages(
            text=combined_content,
            schema=schema,
            query=query
        )

        llm = ChatOpenAI(temperature=0, model=self.OPENAI_MODEL).with_structured_output(output_format)
        response = llm.invoke(messages)
        return response