Skip to content

Commit 4cbc9b9

Browse files
committed
fix: review suggestions from @yangm2
1 parent 9abfb17 commit 4cbc9b9

File tree

3 files changed

+66
-79
lines changed

3 files changed

+66
-79
lines changed

backend/scripts/generate_conversation/chat.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,21 @@
55
# "pandas",
66
# ]
77
# ///
8-
from openai import OpenAI
98
import os
109
import ast
1110
import argparse
1211
from pathlib import Path
1312
import pandas as pd
1413
from typing import Self
1514

15+
from openai.types.responses.response_input_param import Message
16+
1617
if Path("../../.env").exists():
1718
from dotenv import load_dotenv
1819

1920
load_dotenv(override=True)
2021

21-
from tenantfirstaid.chat import API_KEY, BASE_URL, DEFAULT_INSTRUCTIONS, ChatManager
22+
from tenantfirstaid.chat import DEFAULT_INSTRUCTIONS, ChatManager
2223

2324
BOT_INSTRUCTIONS = DEFAULT_INSTRUCTIONS
2425

@@ -36,15 +37,14 @@ class ChatView:
3637
client: Self
3738

3839
def __init__(self, starting_message, user_facts, city, state):
39-
self.client = OpenAI(
40-
api_key=API_KEY,
41-
base_url=BASE_URL,
42-
)
4340
self.chat_manager = ChatManager()
41+
self.client = self.chat_manager.get_client()
4442
self.city = city
4543
self.state = state
4644

47-
self.input_messages = [{"role": "user", "content": starting_message}]
45+
self.input_messages: list[Message] = [
46+
Message(role="user", content=starting_message)
47+
]
4848
self.starting_message = starting_message # Store the starting message
4949

5050
self.openai_tools = []
@@ -60,11 +60,11 @@ def _reverse_message_roles(self, messages):
6060
for message in messages:
6161
if message["role"] == "user":
6262
reversed_messages.append(
63-
{"role": "assistant", "content": message["content"]}
63+
Message(role="assistant", content=message["content"])
6464
)
6565
elif message["role"] == "assistant":
6666
reversed_messages.append(
67-
{"role": "user", "content": message["content"]}
67+
Message(role="user", content=message["content"])
6868
)
6969
else:
7070
reversed_messages.append(message)
@@ -83,7 +83,7 @@ def bot_response(self):
8383
stream=False,
8484
)
8585
self.input_messages.append(
86-
{"role": "assistant", "content": response.output_text}
86+
Message(role="assistant", content=response.output_text)
8787
)
8888
self.input_messages = self._reverse_message_roles(self.input_messages)
8989
return response.output_text
@@ -92,7 +92,7 @@ def bot_response(self):
9292
tries += 1
9393
# If all attempts fail, return a failure message
9494
failure_message = "I'm sorry, I am unable to generate a response at this time. Please try again later."
95-
self.input_messages.append({"role": "assistant", "content": failure_message})
95+
self.input_messages.append(Message(role="assistant", content=failure_message))
9696
return failure_message
9797

9898
def user_response(self):
@@ -108,15 +108,15 @@ def user_response(self):
108108
stream=False,
109109
)
110110
self.input_messages.append(
111-
{"role": "user", "content": response.output_text}
111+
Message(role="user", content=response.output_text)
112112
)
113113
return response.output_text
114114
except Exception as e:
115115
print(f"Error generating user response: {e}")
116116
tries += 1
117117
# If all attempts fail, return a failure message
118118
failure_message = "I'm sorry, I am unable to generate a user response at this time. Please try again later."
119-
self.input_messages.append({"role": "user", "content": failure_message})
119+
self.input_messages.append(Message(role="user", content=failure_message))
120120
return failure_message
121121

122122
def generate_conversation(self, num_turns=5):

backend/tenantfirstaid/chat.py

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
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
28
from flask import request, stream_with_context, Response
39
from flask.views import View
410
import os
511

6-
from .session import TenantSessionMessage
7-
812
API_KEY = os.getenv("OPENAI_API_KEY", os.getenv("GITHUB_API_KEY"))
913
BASE_URL = os.getenv("MODEL_ENDPOINT", "https://api.openai.com/v1")
1014
MODEL = os.getenv("MODEL_NAME", "o3")
1115
MODEL_REASONING_EFFORT = os.getenv("MODEL_REASONING_EFFORT", "medium")
1216

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.
1418
Please give shorter answers.
1519
Please only ask one question at a time so that the user isn't confused.
1620
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):
5559
# This filters out other cities in the same state.
5660
# The user is gated into selecting a city in Oregon so we don't worry about
5761
# whether the relevant documents exist or not.
62+
# TODO: use CompoundFilter and ComparisonFilter from openai.types.shared
5863
filters = (
5964
{
6065
"type": "or",
@@ -111,17 +116,17 @@ def prepare_openai_tools(self, city: str, state: str):
111116
)
112117

113118
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+
)
120125
]
121126

122127
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:
125130
instructions = self.prepare_developer_instructions(city, state)
126131
tools = self.prepare_openai_tools(city, state)
127132

@@ -130,21 +135,16 @@ def generate_chat_response(
130135
model=MODEL,
131136
input=messages,
132137
instructions=instructions,
133-
reasoning={"effort": MODEL_REASONING_EFFORT},
138+
reasoning=Reasoning(effort=MODEL_REASONING_EFFORT),
134139
stream=stream,
135140
include=["file_search_call.results"],
136-
tools=tools if tools else None,
141+
tools=tools,
137142
)
138143

139144
return response_stream
140145

141146

142147
class ChatView(View):
143-
client = OpenAI(
144-
api_key=API_KEY,
145-
base_url=BASE_URL,
146-
)
147-
148148
def __init__(self, tenant_session):
149149
self.tenant_session = tenant_session
150150
self.chat_manager = ChatManager()
@@ -154,42 +154,32 @@ def dispatch_request(self):
154154
user_msg = data["message"]
155155

156156
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))
158158

159159
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)
193183

194184
return Response(
195185
stream_with_context(generate()),

backend/tenantfirstaid/session.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@
66
from valkey import Valkey
77
import simplejson as json
88
from typing import Any, Dict
9-
10-
11-
class TenantSessionMessage(TypedDict):
12-
role: str # 'user' or 'assistant'
13-
content: str # The content of the message
9+
from openai.types.responses.response_input_param import Message
1410

1511

1612
class TenantSessionData(TypedDict):
1713
city: str
1814
state: str
19-
messages: list[TenantSessionMessage] # List of messages with role and content
15+
messages: list[Message] # List of messages with role and content
16+
17+
18+
new_session_data = {
19+
"city": "null",
20+
"state": "or",
21+
"messages": [],
22+
}
2023

2124

2225
# The class to manage tenant sessions using Valkey and Flask sessions
@@ -70,13 +73,7 @@ def set(self, value: TenantSessionData):
7073
self.db_con.set(session_id, json.dumps(value))
7174

7275
def getNewSessionData(self) -> TenantSessionData:
73-
return TenantSessionData(
74-
{
75-
"city": "",
76-
"state": "",
77-
"messages": [],
78-
}
79-
)
76+
return TenantSessionData(new_session_data)
8077

8178

8279
# The Flask view to initialize a session
@@ -92,7 +89,7 @@ def dispatch_request(self):
9289
state = data["state"]
9390

9491
# Initialize the session with city and state
95-
initial_data = TenantSessionData({"city": city, "state": state, "messages": []})
92+
initial_data = TenantSessionData(city=city, state=state, messages=[])
9693
self.tenant_session.set(initial_data)
9794

9895
return Response(

0 commit comments

Comments
 (0)