mrfirdauss commited on
Commit
7020122
·
1 Parent(s): ba507e3

feat: refactor to oop

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +112 -92
src/streamlit_app.py CHANGED
@@ -6,101 +6,121 @@ import pandas as pd
6
  import streamlit as st
7
  from openai import OpenAI
8
  import pickle
9
- # import logging
10
- # logging.basicConfig(filename="/app/logs/app.log", level=logging.INFO)
11
-
12
- client = OpenAI()
13
-
14
- df = pickle.load(open("fraudTrainData.pkl", "rb"))
15
-
16
- st.title("Financial Agent")
17
-
18
- st.session_state["openai_model"] = "gpt-5-mini-2025-08-07"
19
-
20
- if "messages" not in st.session_state:
21
- st.session_state.messages = []
22
-
23
- for message in st.session_state.messages:
24
- with st.chat_message(message["role"]):
25
- st.markdown(message["content"])
26
-
27
- def streamAnswer(instructions, input):
28
- chunk = client.responses.create(
29
- model=st.session_state["openai_model"],
30
- instructions=instructions,
31
- input=input,
32
- stream=True,
33
- # if contextType == "both" || contextType == "pdf"add vector store tools file search
34
- tools=[{
35
- "type": "file_search",
36
- "vector_store_ids": ['vs_68bf713eea2c81919ac08298a05d6704']
37
- }]
38
- )
39
-
40
- for chunk in chunk:
41
- if chunk.type == 'response.output_text.delta':
42
- yield chunk.delta
43
-
44
- if prompt := st.chat_input("What is up?"):
45
- st.session_state.messages.append({"role": "user", "content": prompt})
46
- with st.chat_message("user"):
47
- st.markdown(prompt)
48
-
49
- response = client.responses.parse(
50
- model=st.session_state["openai_model"],
51
- instructions=REFINERY_PROMPT.format(
52
- df_head=df.head().to_markdown(),
53
- df_columns=df.columns.tolist(),
54
- df_sample=df.sample(5).to_markdown()
55
- ),
56
- input=[
57
- {"role": m["role"], "content": m["content"]}
58
- for m in st.session_state.messages
59
- ],
60
- stream=False,
61
- text_format=ResponseState
62
- )
63
-
64
- context_prompt = ""
65
- # logging.info(response)
66
- responseState : ResponseState = response.output_parsed
67
- if responseState.isNeedContext:
68
- contextType = responseState.contextType
69
- st.session_state.messages.append({"role": "assistant", "content": responseState.response})
70
- # with st.chat_message("assistant"):
71
- # st.markdown(responseState.response)
72
- if contextType == "data" or contextType == "both":
73
- local_scope = {
74
- "df": df,
75
- "np": np,
76
- "pd": pd,
77
- "plt": plt
78
- }
79
- exec(responseState.code, {}, local_scope)
80
- fig = plt.gcf() # get current active figure
81
- if fig.get_axes(): # check if plot was created
 
82
  with st.chat_message("assistant"):
83
  st.pyplot(fig)
84
- plt.close(fig) # prevent duplicate rendering later
 
85
  context_prompt = "## CONTEXT DATAFRAME.\n"
86
- context_prompt += local_scope.get("result", "")
87
- # logging.info("context from data: " + context_prompt)
88
- # elif format == "pdf" or format == "both":
89
- # context_prompt = "Provide the relevant information from the PDF documents to answer the user's question."
90
- # st.session_state.messages.append({"role": "user", "content": context_prompt})
91
- # with st.chat_message("user"):
92
- # st.markdown(context_prompt)
93
- answer = ""
 
 
94
  with st.chat_message("assistant"):
95
- answer = st.write_stream(streamAnswer(
96
- instructions=FINAL_PROMPT,
97
- input=[
98
- {"role": m["role"], "content": m["content"]}
99
- for m in st.session_state.messages
100
- ] + [{"role": "user", "content": context_prompt}]
101
- ))
 
 
 
 
 
 
102
  st.session_state.messages.append({"role": "assistant", "content": answer})
103
- else: #only write the response
104
- st.session_state.messages.append({"role": "assistant", "content": responseState.response})
105
  with st.chat_message("assistant"):
106
- st.markdown(responseState.response)
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import streamlit as st
7
  from openai import OpenAI
8
  import pickle
9
+
10
+
11
+ class FinancialAgentApp:
12
+ def __init__(self):
13
+ self.client = OpenAI()
14
+ self.df = pickle.load(open("fraudTrainData.pkl", "rb"))
15
+ self.model_name = "gpt-5-mini-2025-08-07"
16
+
17
+ if "messages" not in st.session_state:
18
+ st.session_state.messages = []
19
+ st.session_state["openai_model"] = self.model_name
20
+
21
+ def render_header(self):
22
+ st.title("Financial Agent")
23
+
24
+ def render_messages(self):
25
+ """Render previous chat messages."""
26
+ for message in st.session_state.messages:
27
+ with st.chat_message(message["role"]):
28
+ st.markdown(message["content"])
29
+
30
+ def stream_answer(self, instructions, input_messages):
31
+ """Stream OpenAI response as a generator."""
32
+ response_stream = self.client.responses.create(
33
+ model=self.model_name,
34
+ instructions=instructions,
35
+ input=input_messages,
36
+ stream=True,
37
+ tools=[{
38
+ "type": "file_search",
39
+ "vector_store_ids": ['vs_68bf713eea2c81919ac08298a05d6704']
40
+ }]
41
+ )
42
+ for chunk in response_stream:
43
+ if chunk.type == 'response.output_text.delta':
44
+ yield chunk.delta
45
+
46
+ def process_prompt(self, prompt):
47
+ """Main pipeline for processing a new user input."""
48
+ st.session_state.messages.append({"role": "user", "content": prompt})
49
+ with st.chat_message("user"):
50
+ st.markdown(prompt)
51
+
52
+ # Step 1: Run refinery prompt
53
+ response = self.client.responses.parse(
54
+ model=self.model_name,
55
+ instructions=REFINERY_PROMPT.format(
56
+ df_head=self.df.head().to_markdown(),
57
+ df_columns=self.df.columns.tolist(),
58
+ df_sample=self.df.sample(5).to_markdown()
59
+ ),
60
+ input=[{"role": m["role"], "content": m["content"]} for m in st.session_state.messages],
61
+ stream=False,
62
+ text_format=ResponseState
63
+ )
64
+
65
+ response_state: ResponseState = response.output_parsed
66
+
67
+ # Step 2: Check if context is needed
68
+ if response_state.isNeedContext:
69
+ context_prompt = self.handle_context(response_state)
70
+ self.generate_final_answer(context_prompt)
71
+ else:
72
+ self.display_final_answer(response_state.response)
73
+
74
+ def handle_context(self, response_state: ResponseState) -> str:
75
+ """Handle additional context (data, PDF, etc.)."""
76
+ context_prompt = ""
77
+ if response_state.contextType in ("data", "both"):
78
+ local_scope = {"df": self.df, "np": np, "pd": pd, "plt": plt}
79
+ exec(response_state.code, {}, local_scope)
80
+
81
+ fig = plt.gcf()
82
+ if fig.get_axes(): # if a chart was generated
83
  with st.chat_message("assistant"):
84
  st.pyplot(fig)
85
+ plt.close(fig)
86
+
87
  context_prompt = "## CONTEXT DATAFRAME.\n"
88
+ context_prompt += str(local_scope.get("result", ""))
89
+
90
+ # Placeholder for PDF or other context handling
91
+ # elif response_state.contextType in ("pdf", "both"):
92
+ # context_prompt = "Provide the relevant information from the PDF documents."
93
+
94
+ return context_prompt
95
+
96
+ def generate_final_answer(self, context_prompt: str):
97
+ """Generate and stream the final answer with context."""
98
  with st.chat_message("assistant"):
99
+ answer = st.write_stream(
100
+ self.stream_answer(
101
+ instructions=FINAL_PROMPT,
102
+ input=[
103
+ {"role": m["role"], "content": m["content"]}
104
+ for m in st.session_state.messages
105
+ ] + [{"role": "user", "content": context_prompt}]
106
+ )
107
+ )
108
+ st.session_state.messages.append({"role": "assistant", "content": answer})
109
+
110
+ def display_final_answer(self, answer: str):
111
+ """Display a non-streamed assistant answer."""
112
  st.session_state.messages.append({"role": "assistant", "content": answer})
 
 
113
  with st.chat_message("assistant"):
114
+ st.markdown(answer)
115
+
116
+ def run(self):
117
+ """Run the app."""
118
+ self.render_header()
119
+ self.render_messages()
120
+
121
+ if prompt := st.chat_input("What is up?"):
122
+ self.process_prompt(prompt)
123
+
124
+ if __name__ == "__main__":
125
+ app = FinancialAgentApp()
126
+ app.run()