ayushsinghal1510 commited on
Commit
4fa6db6
Β·
verified Β·
1 Parent(s): 05c33a5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +169 -162
src/streamlit_app.py CHANGED
@@ -10,22 +10,30 @@ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
10
  from reportlab.lib.units import inch
11
  from reportlab.lib import colors
12
 
13
- config: dict = {'api-url': 'https://chat.voxio.in/agents'}
14
  API_KEY = 'vk_JZgdwJHVmqsWeNvO9b2QvcThfUxl16moNr3wxoDyf2QER97rpi5w3XJCL0H9NRKE'
15
 
16
- st.set_page_config(layout='wide')
17
 
18
- for key, default in [
19
- ('messages', []),
20
- ('session_id', None),
21
- ('waiting_for_var', None),
22
- ('actions', []),
23
- ('end_diagnosis_reached', False),
24
- ('summary', ''),
25
- ('llm_response', ''),
26
- ]:
27
- if key not in st.session_state:
28
- st.session_state[key] = default
 
 
 
 
 
 
 
 
29
 
30
 
31
  def generate_pdf(summary: str, feedback: str) -> BytesIO:
@@ -34,202 +42,201 @@ def generate_pdf(summary: str, feedback: str) -> BytesIO:
34
  topMargin=0.75*inch, bottomMargin=0.75*inch,
35
  leftMargin=inch, rightMargin=inch)
36
  styles = getSampleStyleSheet()
37
-
38
- title_style = ParagraphStyle('Title', parent=styles['Heading1'],
39
- fontSize=22, textColor=colors.HexColor('#1a56db'),
40
- spaceAfter=6, alignment=1)
41
- meta_style = ParagraphStyle('Meta', parent=styles['Normal'],
42
- fontSize=9, textColor=colors.grey, alignment=1,
43
- spaceAfter=20)
44
- h2_style = ParagraphStyle('H2', parent=styles['Heading2'],
45
- fontSize=14, textColor=colors.HexColor('#1a56db'),
46
- spaceBefore=16, spaceAfter=8)
47
- body_style = ParagraphStyle('Body', parent=styles['Normal'],
48
- fontSize=11, leading=17)
49
-
50
- story = [
51
- Paragraph("Session Evaluation Report", title_style),
52
- Paragraph(f"Generated: {datetime.now().strftime('%d %B %Y, %H:%M')}", meta_style),
53
- Paragraph("Summary", h2_style),
54
- ]
55
- for line in (summary or "No summary available.").split('\n'):
56
  if line.strip():
57
- story.append(Paragraph(line.strip(), body_style))
58
- story.append(Spacer(1, 4))
59
-
60
- story.append(Spacer(1, 8))
61
- story.append(Paragraph("Feedback", h2_style))
62
- for line in (feedback or "No feedback available.").split('\n'):
63
  if line.strip():
64
- story.append(Paragraph(line.strip(), body_style))
65
- story.append(Spacer(1, 4))
66
 
67
  doc.build(story)
68
  buf.seek(0)
69
  return buf
70
 
71
 
72
- def process_stream(response):
73
- for line in response.iter_lines():
74
- if not line:
75
- continue
76
- try:
77
- data: dict = json.loads(line)
78
- except json.JSONDecodeError:
79
- continue
80
-
81
- # Handle errors first β€” these are the only early exits
82
- if 'error' in data:
83
- st.error(f'Server Error: {data["error"]}')
84
- st.session_state.messages.append({'role': 'error', 'content': data['error']})
85
- continue
86
- if 'detail' in data:
87
- st.error(f'API Error: {data["detail"]}')
88
- st.session_state.messages.append({'role': 'error', 'content': str(data['detail'])})
89
- continue
90
-
91
- # ── Process every field independently β€” NO early continue ──────────────
92
-
93
- # 1. Spoken NPC content β€” always capture this first
94
- if data.get('speak'):
95
- st.session_state.messages.append({
96
- 'role': 'assistant',
97
- 'content': data['speak']
98
- })
99
-
100
- # 2. Input gate β€” agent is waiting for trainee response
101
- if data.get('waiting_for_input'):
102
- st.session_state.waiting_for_var = data.get('required_variable')
103
-
104
- # 3. Actions (accumulate across turns)
105
- if data.get('actions'):
106
- for a in data['actions']:
107
- if a and a not in st.session_state.actions:
108
- st.session_state.actions.append(a)
109
-
110
- # 4. Session end flag
111
- if str(data.get('end_diagnosis', '')).lower() in ['yes', 'true', '1']:
112
- st.session_state.end_diagnosis_reached = True
113
-
114
- # 5. Summary from API
115
- if data.get('summary'):
116
- st.session_state.summary = data['summary']
117
-
118
- # 6. LLM evaluation block
119
- if data.get('llm_response'):
120
- st.session_state.llm_response = data['llm_response']
121
-
122
-
123
- def reset_session():
124
- for key in ('session_id', 'waiting_for_var', 'summary', 'llm_response'):
125
- st.session_state[key] = None if key in ('session_id', 'waiting_for_var') else ''
126
- st.session_state.messages = []
127
- st.session_state.actions = []
128
- st.session_state.end_diagnosis_reached = False
129
 
 
130
 
131
- # ── Sidebar ────────────────────────────────────────────────────────────────────
132
- with st.sidebar:
133
- st.title("βš™οΈ Session Settings")
134
 
135
- if st.session_state.session_id:
136
- st.info('πŸ”— Session active')
137
 
138
- if st.session_state.actions:
139
- st.divider()
140
- st.caption("ACTIONS TRIGGERED")
141
- for action in st.session_state.actions:
142
- st.success(f"βœ… `{action}`")
143
 
144
- if st.session_state.end_diagnosis_reached:
145
- st.warning("⏹️ Session ended by agent")
146
 
147
- st.divider()
148
- if st.button('End Session', type='primary'):
149
- reset_session()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  st.rerun()
151
- else:
 
152
  st.write("No active session.")
153
 
154
- # PDF report section β€” appears once end_diagnosis fires
155
- if st.session_state.end_diagnosis_reached and (
156
- st.session_state.summary or st.session_state.llm_response
157
- ):
158
  st.divider()
159
- st.subheader("πŸ“„ Evaluation Report")
160
- pdf_bytes = generate_pdf(st.session_state.summary, st.session_state.llm_response)
161
  st.download_button(
162
  label="πŸ“₯ Download PDF",
163
  data=pdf_bytes,
164
  file_name=f"report_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf",
165
  mime="application/pdf",
166
  )
167
- with st.expander("πŸ‘οΈ Preview Report"):
168
- if st.session_state.summary:
169
- st.markdown("### Summary")
170
  st.markdown(st.session_state.summary)
171
- if st.session_state.llm_response:
172
- st.markdown("### Feedback")
173
- st.markdown(st.session_state.llm_response)
174
 
175
 
176
- # ── Start Session ──────────────────────────────────────────────────────────────
177
- if not st.session_state.session_id:
178
- if st.button("πŸš€ Start Session", type="primary"):
179
- new_id = str(uuid4())
180
- payload = {"session_id": new_id, "api_key": API_KEY}
181
- st.session_state.session_id = new_id
 
 
 
 
 
 
 
 
 
 
182
 
183
- with st.spinner('Initializing…'):
184
- try:
185
- with requests.post(
186
- f'{config["api-url"]}/start_session',
187
- json=payload, stream=True
188
- ) as r:
189
  if r.status_code == 200:
190
  process_stream(r)
191
  st.rerun()
192
- else:
 
193
  st.error(f"Error {r.status_code}: {r.text}")
194
  st.session_state.session_id = None
195
- except Exception as e:
 
 
196
  st.error(f"Connection Error: {e}")
197
  st.session_state.session_id = None
198
 
 
199
 
200
- # ── Chat Display ───────────────────────────────────────────────────────────────
201
- for msg in st.session_state.messages:
202
- with st.chat_message(msg['role']):
203
- st.write(msg['content'])
204
 
 
205
 
206
- # ── Input ──────────────────────────────────────────────────────────────────────
207
- if st.session_state.session_id:
208
- if st.session_state.waiting_for_var:
209
- with st.chat_message("assistant"):
210
- st.write(f"Waiting for your response…")
211
 
212
- if user_text := st.chat_input("Enter response..."):
213
- st.session_state.messages.append({'role': 'user', 'content': user_text})
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  payload = {
216
- 'session_id': st.session_state.session_id,
217
- 'user_input': {st.session_state.waiting_for_var: user_text}
218
- if st.session_state.waiting_for_var
219
- else user_text
220
  }
 
221
  st.session_state.waiting_for_var = None
222
 
223
- with st.spinner('Processing…'):
224
- try:
 
 
225
  with requests.post(
226
- f'{config["api-url"]}/process_input',
227
- json=payload, stream=True
228
- ) as r:
229
- if r.status_code == 200:
 
 
 
230
  process_stream(r)
231
  st.rerun()
232
- else:
 
233
  st.error("Server Error processing input.")
234
- except Exception as e:
 
235
  st.error(f"Connection Error: {e}")
 
10
  from reportlab.lib.units import inch
11
  from reportlab.lib import colors
12
 
13
+ config : dict = {'api-url' : 'https://chat.voxio.in/agents'}
14
  API_KEY = 'vk_JZgdwJHVmqsWeNvO9b2QvcThfUxl16moNr3wxoDyf2QER97rpi5w3XJCL0H9NRKE'
15
 
16
+ st.set_page_config(layout = 'wide')
17
 
18
+ if 'messages' not in st.session_state :
19
+ st.session_state.messages = []
20
+
21
+ if 'session_id' not in st.session_state :
22
+ st.session_state.session_id = None
23
+
24
+ if 'waiting_for_var' not in st.session_state :
25
+ st.session_state.waiting_for_var = None
26
+
27
+ # ── NEW: only these two additions ─────────────────────────────────────────────
28
+ if 'actions' not in st.session_state :
29
+ st.session_state.actions = []
30
+
31
+ if 'llm_response' not in st.session_state :
32
+ st.session_state.llm_response = None
33
+
34
+ if 'summary' not in st.session_state :
35
+ st.session_state.summary = None
36
+ # ─────────────────────────────────────────────────────────────────────────────
37
 
38
 
39
  def generate_pdf(summary: str, feedback: str) -> BytesIO:
 
42
  topMargin=0.75*inch, bottomMargin=0.75*inch,
43
  leftMargin=inch, rightMargin=inch)
44
  styles = getSampleStyleSheet()
45
+ h1 = ParagraphStyle('H1', parent=styles['Heading1'], fontSize=20,
46
+ textColor=colors.HexColor('#1a56db'), spaceAfter=6)
47
+ body = ParagraphStyle('Body', parent=styles['Normal'], fontSize=11, leading=17)
48
+
49
+ story = []
50
+ story.append(Paragraph("# Summary", h1))
51
+ story.append(Spacer(1, 6))
52
+ for line in (summary or '').split('\n'):
 
 
 
 
 
 
 
 
 
 
 
53
  if line.strip():
54
+ story.append(Paragraph(line.strip(), body))
55
+ story.append(Spacer(1, 20))
56
+ story.append(Paragraph("# Feedback", h1))
57
+ story.append(Spacer(1, 6))
58
+ for line in (feedback or '').split('\n'):
 
59
  if line.strip():
60
+ story.append(Paragraph(line.strip(), body))
 
61
 
62
  doc.build(story)
63
  buf.seek(0)
64
  return buf
65
 
66
 
67
+ def process_stream(response) :
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ for line in response.iter_lines() :
70
 
71
+ if line :
 
 
72
 
73
+ try :
 
74
 
75
+ data : dict = json.loads(line)
 
 
 
 
76
 
77
+ if 'error' in data :
 
78
 
79
+ st.error(f'Server Error: {data["error"]}')
80
+ st.session_state.messages.append({'role' : 'error' , 'content' : data['error']})
81
+
82
+ elif 'detail' in data :
83
+
84
+ st.error(f'API Error: {data["detail"]}')
85
+ st.session_state.messages.append({'role' : 'error' , 'content' : str(data['detail'])})
86
+
87
+ elif data.get('waiting_for_input') :
88
+
89
+ req_var = data.get('required_variable')
90
+ st.session_state.waiting_for_var = req_var
91
+
92
+ else :
93
+
94
+ content = data.get('out' , data)
95
+ st.session_state.messages.append({'role' : 'assistant' , 'content' : str(content)})
96
+
97
+ # ── NEW: capture actions, summary, llm_response ────────
98
+ if data.get('actions') :
99
+ for a in data['actions'] :
100
+ if a and a not in st.session_state.actions :
101
+ st.session_state.actions.append(a)
102
+
103
+ if data.get('summary') :
104
+ st.session_state.summary = data['summary']
105
+
106
+ if data.get('llm_response') :
107
+ st.session_state.llm_response = data['llm_response']
108
+ # ─────────────────────────────────────────────────────────
109
+
110
+ except json.JSONDecodeError :
111
+ st.error(f'Failed to decode JSON line: {line}')
112
+
113
+
114
+ with st.sidebar :
115
+
116
+ st.title("Settings")
117
+
118
+ if st.session_state.session_id :
119
+
120
+ st.info(f'Active Session: `{st.session_state.session_id}`')
121
+
122
+ # ── NEW: show actions ──────────────────────────────────────────────
123
+ if st.session_state.actions :
124
+ st.divider()
125
+ for a in st.session_state.actions :
126
+ st.warning(f'⚑ Action: `{a}`')
127
+ # ──────────────────────────────────────────────────────────────────
128
+
129
+ if st.button('End Session' , type = 'primary') :
130
+
131
+ st.session_state.session_id = None
132
+ st.session_state.messages = []
133
+ st.session_state.waiting_for_var = None
134
+ st.session_state.actions = []
135
+ st.session_state.llm_response = None
136
+ st.session_state.summary = None
137
  st.rerun()
138
+
139
+ else :
140
  st.write("No active session.")
141
 
142
+ # ── NEW: PDF download once llm_response arrives ────────────────────────
143
+ if st.session_state.llm_response :
 
 
144
  st.divider()
145
+ st.subheader("πŸ“„ Report Ready")
146
+ pdf_bytes = generate_pdf(st.session_state.summary or '', st.session_state.llm_response)
147
  st.download_button(
148
  label="πŸ“₯ Download PDF",
149
  data=pdf_bytes,
150
  file_name=f"report_{datetime.now().strftime('%Y%m%d_%H%M')}.pdf",
151
  mime="application/pdf",
152
  )
153
+ with st.expander("πŸ‘οΈ Preview") :
154
+ if st.session_state.summary :
155
+ st.markdown("## Summary")
156
  st.markdown(st.session_state.summary)
157
+ st.markdown("## Feedback")
158
+ st.markdown(st.session_state.llm_response)
159
+ # ──────────────────────────────────────────────────────────────────────
160
 
161
 
162
+ if not st.session_state.session_id :
163
+
164
+ if st.button("πŸš€ Start Session" , type = "primary") :
165
+
166
+ payload = {
167
+ "session_id" : str(uuid4()) ,
168
+ "api_key" : API_KEY
169
+ }
170
+
171
+ st.session_state.session_id = payload['session_id']
172
+
173
+ with st.spinner('Initializing Workflow...') :
174
+
175
+ try :
176
+
177
+ with requests.post(f'{config["api-url"]}/start_session', json=payload, stream=True) as r:
178
 
 
 
 
 
 
 
179
  if r.status_code == 200:
180
  process_stream(r)
181
  st.rerun()
182
+
183
+ else :
184
  st.error(f"Error {r.status_code}: {r.text}")
185
  st.session_state.session_id = None
186
+
187
+ except Exception as e :
188
+
189
  st.error(f"Connection Error: {e}")
190
  st.session_state.session_id = None
191
 
192
+ chat_container = st.container()
193
 
194
+ with chat_container :
 
 
 
195
 
196
+ for msg in st.session_state.messages :
197
 
198
+ with st.chat_message(msg['role']) :
 
 
 
 
199
 
200
+ if msg['role'] == 'assistant' :
201
+ st.write(msg['content'])
202
+
203
+ else :
204
+ st.write(msg['content'])
205
+
206
+ if st.session_state.session_id and st.session_state.waiting_for_var :
207
+
208
+ with st.chat_message("assistant") :
209
+
210
+ st.write(f"I need a value for: **{st.session_state.waiting_for_var}**")
211
+
212
+ if user_text := st.chat_input("Enter response...") :
213
+
214
+ st.session_state.messages.append({'role' : 'user' , 'content' : user_text})
215
 
216
  payload = {
217
+ 'session_id' : st.session_state.session_id ,
218
+ 'user_input' : {st.session_state.waiting_for_var : user_text}
 
 
219
  }
220
+
221
  st.session_state.waiting_for_var = None
222
 
223
+ with st.spinner('Processing...') :
224
+
225
+ try :
226
+
227
  with requests.post(
228
+ f'{config["api-url"]}/process_input' ,
229
+ json = payload ,
230
+ stream = True
231
+ ) as r :
232
+
233
+ if r.status_code == 200 :
234
+
235
  process_stream(r)
236
  st.rerun()
237
+
238
+ else :
239
  st.error("Server Error processing input.")
240
+
241
+ except Exception as e :
242
  st.error(f"Connection Error: {e}")