diego2317 commited on
Commit
d71452d
·
verified ·
1 Parent(s): f92db4e

Create response_manager.py

Browse files
Files changed (1) hide show
  1. utils/response_manager.py +129 -0
utils/response_manager.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import openai
3
+ import logging
4
+ from typing import Optional
5
+ import asyncio
6
+
7
+ class ResponseManager:
8
+ """
9
+ This class initializes the OpenAI client and provides methods to create responses,
10
+ maintain conversation history, and handle user queries.
11
+ """
12
+
13
+ def __init__(self,
14
+ vector_store_id: Optional[str] = None,
15
+ api_key: Optional[str] = None,
16
+ meta_prompt_file: Optional[str] = None,
17
+ model: str = "gpt-4.1-nano",
18
+ temperature: float = 0,
19
+ max_output_tokens: int = 600,
20
+ max_num_results: int = 5):
21
+ """
22
+ Initialize the ResponseManager with optional parameters for configuration.
23
+ :param vector_store_id: The ID of the vector store to use for file search.
24
+ :param api_key: The OpenAI API key for authentication.
25
+ :param meta_prompt_file: Path to the meta prompt file (default: 'config/meta_prompt.txt').
26
+ :param model: The OpenAI model to use (default: 'gpt-4o-mini').
27
+ :param temperature: The temperature for response generation (default: 0).
28
+ :param max_output_tokens: The maximum number of output tokens (default: 800).
29
+ :param max_num_results: The maximum number of search results to return (default: 15).
30
+ """
31
+ # Load vector_store_id and api_key from environment variables if not provided
32
+ self.vector_store_id = vector_store_id or os.getenv('USS_DOCUMENTATION_VECTOR_STORE')
33
+ if not self.vector_store_id:
34
+ logging.error("VECTOR_STORE_ID is not provided or set in the environment.")
35
+ raise ValueError("VECTOR_STORE_ID is required.")
36
+
37
+ self.api_key = api_key or os.getenv('SETTING_UP_API_KEY')
38
+ if not self.api_key:
39
+ logging.error("OPENAI_API_KEY is not provided or set in the environment.")
40
+ raise ValueError("OPENAI_API_KEY is required.")
41
+
42
+ # Initialize other attributes
43
+ self.meta_prompt_file = meta_prompt_file or 'config/meta_prompt.txt'
44
+ self.previous_response_id = None
45
+
46
+ # Initialize the OpenAI client
47
+ self.client = openai.OpenAI(api_key=self.api_key)
48
+
49
+ # Load the meta prompt from the specified file
50
+ self.meta_prompt = self._load_meta_prompt(self.meta_prompt_file)
51
+
52
+ # Set default parameters for response generation
53
+ self.model = model
54
+ self.temperature = temperature
55
+ self.max_output_tokens = max_output_tokens
56
+ self.max_num_results = max_num_results
57
+
58
+ def _load_meta_prompt(self, meta_prompt_file: str) -> str:
59
+ """
60
+ Load the meta prompt from the specified file.
61
+ :param meta_prompt_file: Path to the meta prompt file.
62
+ :return: The meta prompt as a string.
63
+ """
64
+ if not os.path.exists(meta_prompt_file):
65
+ logging.error(f"Meta prompt file '{meta_prompt_file}' not found.")
66
+ raise FileNotFoundError(f"Meta prompt file '{meta_prompt_file}' not found.")
67
+ with open(meta_prompt_file, 'r', encoding='utf-8') as file:
68
+ meta_prompt = file.read().strip()
69
+ logging.info(f"Meta prompt loaded successfully from '{meta_prompt_file}'.")
70
+ return meta_prompt
71
+
72
+ async def generate_response(self, query: str, history: list) -> list:
73
+ """
74
+ Generate a response to a user query using the OpenAI API.
75
+ This method interacts with the OpenAI API to create a response based on the user's query.
76
+ It supports optional parameters for model configuration and handles errors gracefully.
77
+ Args:
78
+ query (str): The user query to respond to.
79
+ history (list): The conversation history from the chatbot.
80
+ Returns:
81
+ list: A list of dictionaries representing the conversation, including the generated response.
82
+ """
83
+ # Prepare the input for the API call
84
+ input_data = [{"role": "developer", "content": self.meta_prompt}] if self.previous_response_id is None else []
85
+ input_data.append({"role": "user", "content": query})
86
+
87
+ # Validate the query
88
+ if not query.strip():
89
+ logging.warning("Empty or invalid query received.")
90
+ warning_message = "Please enter a valid query."
91
+ input_data.append({"role": "assistant", "content": warning_message})
92
+ return history + input_data
93
+
94
+ try:
95
+ logging.info("Sending request to OpenAI API...")
96
+ loop = asyncio.get_running_loop()
97
+ response = await loop.run_in_executor(
98
+ None, # default executor
99
+ lambda: self.client.responses.create(
100
+ model=self.model,
101
+ previous_response_id=self.previous_response_id,
102
+ input=input_data,
103
+ tools=[{
104
+ "type": "file_search",
105
+ "vector_store_ids": [self.vector_store_id],
106
+ "max_num_results": self.max_num_results
107
+ }],
108
+ truncation="auto",
109
+ temperature=self.temperature,
110
+ max_output_tokens=self.max_output_tokens
111
+ )
112
+ )
113
+ self.previous_response_id = response.id
114
+ logging.info("Response received successfully.")
115
+ input_data.append({"role": "assistant", "content": response.output_text})
116
+ return history + input_data
117
+
118
+ except Exception as e:
119
+ logging.error(f"An error occurred while generating a response: {e}")
120
+ error_message = "Sorry, I couldn't generate a response at this time. Please try again later."
121
+ input_data.append({"role": "assistant", "content": error_message})
122
+ return history + input_data
123
+
124
+ def reset_conversation(self):
125
+ """
126
+ Reset the conversation state internally maintained by OpenAI Response API.
127
+ """
128
+ self.previous_response_id = None
129
+ logging.info("Previous response id reset to None.")