1
1
from openai import OpenAI
2
+ from openai .types .shared import Reasoning
3
+ from openai .types .responses import (
4
+ FileSearchToolParam ,
5
+ ResponseStreamEvent ,
6
+ )
7
+ from openai .types .responses .response_input_param import Message
2
8
from flask import request , stream_with_context , Response
3
9
from flask .views import View
4
10
import os
5
11
6
- from .session import TenantSessionMessage
7
-
8
12
API_KEY = os .getenv ("OPENAI_API_KEY" , os .getenv ("GITHUB_API_KEY" ))
9
13
BASE_URL = os .getenv ("MODEL_ENDPOINT" , "https://api.openai.com/v1" )
10
14
MODEL = os .getenv ("MODEL_NAME" , "o3" )
11
15
MODEL_REASONING_EFFORT = os .getenv ("MODEL_REASONING_EFFORT" , "medium" )
12
16
13
- DEFAULT_INSTRUCTIONS = """Pretend you're a legal expert who giving advice about eviction notices in Oregon.
17
+ DEFAULT_INSTRUCTIONS = """Pretend you're a legal expert who is giving advice about eviction notices in Oregon.
14
18
Please give shorter answers.
15
19
Please only ask one question at a time so that the user isn't confused.
16
20
If the user is being evicted for non-payment of rent and they are too poor to pay the rent and you have confirmed in various ways that the notice is valid and there is a valid court hearing date, then tell them to call Oregon Law Center at 5131234567.
@@ -55,6 +59,7 @@ def prepare_openai_tools(self, city: str, state: str):
55
59
# This filters out other cities in the same state.
56
60
# The user is gated into selecting a city in Oregon so we don't worry about
57
61
# whether the relevant documents exist or not.
62
+ # TODO: use CompoundFilter and ComparisonFilter from openai.types.shared
58
63
filters = (
59
64
{
60
65
"type" : "or" ,
@@ -111,17 +116,17 @@ def prepare_openai_tools(self, city: str, state: str):
111
116
)
112
117
113
118
return [
114
- {
115
- " type" : "file_search" ,
116
- " vector_store_ids" : [VECTOR_STORE_ID ],
117
- " max_num_results" : os .getenv ("NUM_FILE_SEARCH_RESULTS" , 10 ),
118
- " filters" : filters ,
119
- }
119
+ FileSearchToolParam (
120
+ type = "file_search" ,
121
+ vector_store_ids = [VECTOR_STORE_ID ],
122
+ max_num_results = os .getenv ("NUM_FILE_SEARCH_RESULTS" , 10 ),
123
+ filters = filters ,
124
+ )
120
125
]
121
126
122
127
def generate_chat_response (
123
- self , messages : list [TenantSessionMessage ], city : str , state : str , stream = False
124
- ):
128
+ self , messages : list [Message ], city : str , state : str , stream = False
129
+ ) -> ResponseStreamEvent :
125
130
instructions = self .prepare_developer_instructions (city , state )
126
131
tools = self .prepare_openai_tools (city , state )
127
132
@@ -130,21 +135,16 @@ def generate_chat_response(
130
135
model = MODEL ,
131
136
input = messages ,
132
137
instructions = instructions ,
133
- reasoning = { " effort" : MODEL_REASONING_EFFORT } ,
138
+ reasoning = Reasoning ( effort = MODEL_REASONING_EFFORT ) ,
134
139
stream = stream ,
135
140
include = ["file_search_call.results" ],
136
- tools = tools if tools else None ,
141
+ tools = tools ,
137
142
)
138
143
139
144
return response_stream
140
145
141
146
142
147
class ChatView (View ):
143
- client = OpenAI (
144
- api_key = API_KEY ,
145
- base_url = BASE_URL ,
146
- )
147
-
148
148
def __init__ (self , tenant_session ):
149
149
self .tenant_session = tenant_session
150
150
self .chat_manager = ChatManager ()
@@ -154,42 +154,32 @@ def dispatch_request(self):
154
154
user_msg = data ["message" ]
155
155
156
156
current_session = self .tenant_session .get ()
157
- current_session ["messages" ].append ({ " role" : " user" , " content" : user_msg } )
157
+ current_session ["messages" ].append (Message ( role = " user" , content = user_msg ) )
158
158
159
159
def generate ():
160
- try :
161
- # Use the new Responses API with streaming
162
- response_stream = self .chat_manager .generate_chat_response (
163
- current_session ["messages" ],
164
- current_session ["city" ],
165
- current_session ["state" ],
166
- stream = True ,
167
- )
168
-
169
- assistant_chunks = []
170
- for chunk in response_stream :
171
- if hasattr (chunk , "delta" ):
172
- token = chunk .delta or ""
173
- assistant_chunks .append (token )
174
- yield token
175
-
176
- # Join the complete response
177
- assistant_msg = "" .join (assistant_chunks )
178
-
179
- current_session ["messages" ].append (
180
- {"role" : "assistant" , "content" : assistant_msg }
181
- )
182
-
183
- except Exception as e :
184
- error_msg = f"Error generating response: { e } "
185
- print (error_msg )
186
- current_session ["messages" ].append (
187
- {"role" : "assistant" , "content" : error_msg }
188
- )
189
- yield f"Error: { str (e )} "
190
-
191
- finally :
192
- self .tenant_session .set (current_session )
160
+ # Use the new Responses API with streaming
161
+ response_stream = self .chat_manager .generate_chat_response (
162
+ current_session ["messages" ],
163
+ current_session ["city" ],
164
+ current_session ["state" ],
165
+ stream = True ,
166
+ )
167
+
168
+ assistant_chunks = []
169
+ for chunk in response_stream :
170
+ if hasattr (chunk , "delta" ):
171
+ token = chunk .delta or ""
172
+ assistant_chunks .append (token )
173
+ yield token
174
+
175
+ # Join the complete response
176
+ assistant_msg = "" .join (assistant_chunks )
177
+
178
+ current_session ["messages" ].append (
179
+ Message (role = "assistant" , content = assistant_msg )
180
+ )
181
+
182
+ self .tenant_session .set (current_session )
193
183
194
184
return Response (
195
185
stream_with_context (generate ()),
0 commit comments