Sathvik-kota commited on
Commit
7a51eda
·
verified ·
1 Parent(s): f07e261

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. app.py +111 -148
  2. sync_async_routing_API.py +0 -34
  3. sync_path_microservice.py +0 -6
app.py CHANGED
@@ -3,215 +3,178 @@ import requests
3
  import time
4
  import json
5
 
6
- # --- Page Config ---
7
  st.set_page_config(layout="wide")
 
8
 
9
  # ---------- Streamlit Layout ----------
10
  st.title("Banking Support Ticket System")
 
11
 
12
- # --- Use Columns for Layout ---
13
  col1, col2 = st.columns(2)
14
 
15
- # --- Left Column: Form and Clear Button ---
16
  with col1:
17
- st.subheader("Submit a Ticket")
18
- # Ticket input form
19
  with st.form(key="ticket_form"):
20
  channel = st.selectbox("Channel", ["Email", "Chat", "Phone"])
21
-
22
  # Updated selectbox for clarity
23
  severity_option = st.selectbox(
24
- "Severity (Determines Processing Path)",
25
  [
26
- "High (Sync - AI response ~5-10s)",
27
- "Medium (Async - Queued, AI response ~10-15s)",
28
- "Low (Async - Queued, AI response ~10-15s)"
29
  ]
30
  )
31
-
32
  summary = st.text_area("Summary", "Example: My credit card payment is not going through.")
33
  submit_button = st.form_submit_button(label="Submit Ticket")
34
 
35
- # Map user-friendly option to the API value
36
- severity_mapping = {
37
- "High (Sync - AI response ~5-10s)": "High",
38
- "Medium (Async - Queued, AI response ~10-15s)": "Medium",
39
- "Low (Async - Queued, AI response ~10-15s)": "Low"
40
- }
41
- severity = severity_mapping[severity_option]
42
-
43
- # --- Clear Memory Button (Moved Here) ---
44
- st.divider() # Add a visual separator above the button
45
- CLEAR_MEMORY_URL = "http://localhost:8000/clear_memory" # Orchestrator endpoint
46
-
47
- if st.button("Clear RAG Memory"):
48
- try:
49
- response = requests.post(CLEAR_MEMORY_URL, timeout=10) # Add timeout
50
- if response.status_code == 200:
51
- st.success("Successfully requested memory clear for both services.")
52
- st.json(response.json()) # Show detailed results
53
- else:
54
- st.error(f"Error clearing memory: {response.status_code} - {response.text}")
55
- except Exception as e:
56
- st.error(f"Failed to connect to clear memory endpoint: {e}")
57
- # --- End Clear Memory Button ---
58
-
59
-
60
- # --- Right Column: API Call and Results Display ---
61
- with col2:
62
- st.subheader("Results")
63
- # Use ONE main placeholder in the results column for all dynamic content
64
- results_placeholder = st.empty()
65
 
66
- # ---------- API Call Logic ----------
67
- API_URL = "http://localhost:8000/ticket" # Orchestrator
68
- RESULT_URL = "http://localhost:8000/result" # Orchestrator's result endpoint
69
 
 
 
70
  if submit_button:
71
  ticket_data = {
72
  "channel": channel,
73
  "severity": severity,
74
  "summary": summary
75
  }
 
 
76
 
77
- # --- Use the placeholder's container context manager ---
78
- with results_placeholder.container():
79
  try:
80
- # Show spinner only for Sync path, inside the container
81
- if severity == "High":
82
- with st.spinner("Processing ticket in real-time..."):
83
- start_time = time.time() # Start round-trip timer for sync only
84
- response = requests.post(API_URL, json=ticket_data, timeout=60) # Increased timeout
85
- else:
86
- # For Async, just make the request, no spinner needed here
87
- response = requests.post(API_URL, json=ticket_data, timeout=15) # Shorter timeout for async submission
88
-
89
- # --- Process Response ---
90
  if response.status_code == 200:
91
  try:
92
  res = response.json()
93
  except json.JSONDecodeError:
94
- st.error(f"Error: Could not decode JSON response. Status: {response.status_code}, Response: {response.text}")
95
  res = None
96
 
97
  if res:
98
- # --- Async Path ---
99
  if res.get("status") == "queued":
100
- st.success(f"Your ticket has been submitted (Job ID: {res['ticket_id']})")
101
- polling_placeholder = st.empty() # New placeholder JUST for polling status within this container
102
- polling_placeholder.info("Our team is reviewing. Results appear here when ready.")
103
-
 
104
  # Poll API until result is ready
105
  while True:
106
- try:
107
- result_resp = requests.get(f"{RESULT_URL}/{res['ticket_id']}", timeout=10)
108
-
109
- if result_resp.status_code == 200:
110
- try:
111
- result_data = result_resp.json()
112
- except json.JSONDecodeError:
113
- polling_placeholder.error(f"Error: Could not decode result JSON. Response: {result_resp.text}")
114
- break # Stop polling on decode error
115
-
116
- if result_data.get("status") == "completed":
117
- polling_placeholder.empty() # Clear polling message
118
- st.success("Support Update:") # Display final results
119
-
120
- result = result_data.get('result', {})
121
- st.write(f"**Decision:** {result.get('decision', 'N/A')}")
122
- st.write(f"**Reason:** {result.get('reason', 'N/A')}")
123
- st.write("**Next Actions:**")
124
- for step in result.get('next_actions', []):
125
- st.write(f"- {step}")
126
-
127
- # Display Processing Time
128
- processing_time = result.get("processing_time")
129
- if processing_time:
130
- st.write(f"**AI Processing Time:** {processing_time:.2f} seconds")
131
-
132
- # Display RAG Context
133
- retrieved_context = result.get("retrieved_context")
134
- if retrieved_context and retrieved_context != "No relevant past cases found.":
135
- with st.expander("Show RAG Context Used"):
136
- st.text(retrieved_context)
137
- elif retrieved_context: # Still show if no cases found
138
- with st.expander("Show RAG Context Used"):
139
- st.info(retrieved_context)
140
-
141
- break # Exit polling loop
142
-
143
- elif result_data.get("status") == "processing":
144
- polling_placeholder.info("Status: AI worker processing...") # Update polling status
145
- elif result_data.get("status") == "queued":
146
- polling_placeholder.info("Status: Waiting in queue...") # Update polling status
147
- elif result_data.get("status") == "error":
148
- polling_placeholder.error(f"Error processing ticket: {result_data.get('detail')}")
149
- break
150
- else: # Pending or other unknown status
151
- polling_placeholder.info(f"Status: {result_data.get('status', 'Waiting...')}") # Update polling status
152
-
153
- elif result_resp.status_code == 404:
154
- polling_placeholder.error("Error: Result endpoint not found (404).")
155
  break
156
- else:
157
- polling_placeholder.error(f"Error polling: {result_resp.status_code} - {result_resp.text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  break
159
 
160
- except requests.exceptions.Timeout:
161
- polling_placeholder.warning("Polling timed out. Still waiting...") # Update polling status
162
- except requests.exceptions.ConnectionError:
163
- polling_placeholder.error("Connection error polling.")
164
- break
165
- except Exception as poll_e:
166
- polling_placeholder.error(f"Polling error: {poll_e}")
167
  break
 
 
 
 
 
168
 
169
- time.sleep(3) # Wait longer between polls
170
-
171
- # --- Sync Path ---
172
  elif res.get("decision"):
173
- # Spinner already cleared automatically when 'with' block exits
174
  total_time = time.time() - start_time
175
- st.success("Real-time Support Response:") # Display results
176
-
 
177
  st.write(f"**Decision:** {res['decision']}")
178
  st.write(f"**Reason:** {res['reason']}")
179
  st.write("**Next Actions:**")
180
  for step in res['next_actions']:
181
  st.write(f"- {step}")
182
-
183
  # Display Processing Time
184
  processing_time = res.get("processing_time")
185
  if processing_time:
186
  st.write(f"**AI Processing Time:** {processing_time:.2f} seconds")
187
-
188
  st.write(f"**Total round-trip time:** {total_time:.2f} seconds")
189
 
190
- # Display RAG Context
191
  retrieved_context = res.get("retrieved_context")
192
- if retrieved_context and retrieved_context != "No relevant past cases found.":
193
- with st.expander("Show RAG Context Used"):
194
  st.text(retrieved_context)
195
- elif retrieved_context: # Still show if no cases found
196
- with st.expander("Show RAG Context Used"):
197
- st.info(retrieved_context)
198
-
199
-
200
- # --- Error from Orchestrator's initial call ---
201
- elif res.get("status") == "error":
202
- st.error(f"Error from backend: {res.get('detail')}")
203
  else:
204
- st.error(f"Error: Unknown response format: {res}")
205
 
206
- # --- HTTP Error from Orchestrator ---
207
  else:
208
- st.error(f"Error submitting ticket: {response.status_code} - {response.text}")
209
-
210
- # --- Connection or other request errors ---
211
- except requests.exceptions.Timeout:
212
- st.error("API request timed out.")
213
  except requests.exceptions.ConnectionError:
214
- st.error("API connection failed. Is the backend running?")
215
  except Exception as e:
216
  st.error(f"An unexpected error occurred: {e}")
217
-
 
 
 
 
 
 
 
 
 
 
3
  import time
4
  import json
5
 
6
+ # --- THIS IS THE NEW LINE ---
7
  st.set_page_config(layout="wide")
8
+ # ----------------------------
9
 
10
  # ---------- Streamlit Layout ----------
11
  st.title("Banking Support Ticket System")
12
+ st.subheader("Submit a Ticket")
13
 
14
+ # --- NEW: Create two columns ---
15
  col1, col2 = st.columns(2)
16
 
17
+ # --- Column 1: The Form ---
18
  with col1:
19
+
 
20
  with st.form(key="ticket_form"):
21
  channel = st.selectbox("Channel", ["Email", "Chat", "Phone"])
22
+
23
  # Updated selectbox for clarity
24
  severity_option = st.selectbox(
25
+ "Severity (Determines Processing Path)",
26
  [
27
+ "High (Sync - service)",
28
+ "Medium (Async - service)",
29
+ "Low (Async - service)"
30
  ]
31
  )
32
+
33
  summary = st.text_area("Summary", "Example: My credit card payment is not going through.")
34
  submit_button = st.form_submit_button(label="Submit Ticket")
35
 
36
+ # Map user-friendly option to the API value
37
+ severity_mapping = {
38
+ "High (Sync - service)": "High",
39
+ "Medium (Async - service)": "Medium",
40
+ "Low (Async - service)": "Low"
41
+ }
42
+ severity = severity_mapping[severity_option]
43
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ # ---------- API Call ----------
46
+ API_URL = "http://localhost:8000/ticket" # Orchestrator
47
+ RESULT_URL = "http://localhost:8000/result" # Orchestrator's result endpoint
48
 
49
+ # --- Column 2: The Results ---
50
+ with col2:
51
  if submit_button:
52
  ticket_data = {
53
  "channel": channel,
54
  "severity": severity,
55
  "summary": summary
56
  }
57
+
58
+ start_time = time.time() # Start round-trip timer
59
 
60
+ # --- NEW: Define the API call logic as a reusable function ---
61
+ def make_api_call():
62
  try:
63
+ response = requests.post(API_URL, json=ticket_data)
64
+
 
 
 
 
 
 
 
 
65
  if response.status_code == 200:
66
  try:
67
  res = response.json()
68
  except json.JSONDecodeError:
69
+ st.error(f"Error: Could not decode JSON response from orchestrator. Response: {response.text}")
70
  res = None
71
 
72
  if res:
73
+ # Check if ticket is async
74
  if res.get("status") == "queued":
75
+ # --- UPDATED ASYNC MESSAGE ---
76
+ st.success(f"Your ticket has been submitted to our support team (Job ID: {res['ticket_id']})")
77
+ st.info("Our team is reviewing the issue and will get back to you as soon as the problem is traced. The results will appear here automatically.")
78
+ result_placeholder = st.empty()
79
+
80
  # Poll API until result is ready
81
  while True:
82
+ result_resp = requests.get(f"{RESULT_URL}/{res['ticket_id']}")
83
+
84
+ if result_resp.status_code == 200:
85
+ try:
86
+ result_data = result_resp.json()
87
+ except json.JSONDecodeError:
88
+ result_placeholder.error(f"Error: Could not decode JSON response from result endpoint. Response: {result_resp.text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  break
90
+
91
+ if result_data.get("status") == "completed":
92
+ result_placeholder.empty() # Clear the "processing" message
93
+ st.success("Support Team Response:")
94
+
95
+ result = result_data.get('result', {})
96
+ st.write(f"**Decision:** {result.get('decision', 'N/A')}")
97
+ st.write(f"**Reason:** {result.get('reason', 'N/A')}")
98
+ st.write("**Next Actions:**")
99
+ for step in result.get('next_actions', []):
100
+ st.write(f"- {step}")
101
+
102
+ # Display Processing Time
103
+ processing_time = result.get("processing_time")
104
+ if processing_time:
105
+ st.write(f"**AI Processing Time:** {processing_time:.2f} seconds")
106
+
107
+ retrieved_context = result.get("retrieved_context")
108
+ if retrieved_context:
109
+ with st.expander("Show RAG Context"):
110
+ st.text(retrieved_context)
111
+
112
+ break # Exit polling loop
113
+
114
+ # --- UPDATED ASYNC POLLING MESSAGES ---
115
+ elif result_data.get("status") == "processing":
116
+ result_placeholder.info("Our support team is actively reviewing your ticket now...")
117
+
118
+ elif result_data.get("status") == "queued":
119
+ result_placeholder.info("Your ticket is in the queue. Our team will review it shortly.")
120
+
121
+ elif result_data.get("status") == "error":
122
+ result_placeholder.error(f"Error processing ticket: {result_data.get('detail')}")
123
  break
124
 
125
+ else:
126
+ result_placeholder.info(f"Waiting for result... (Status: {result_data.get('status')})")
127
+
128
+ elif result_resp.status_code == 404:
129
+ st.error("Error: Result endpoint not found (404). Check Orchestrator (`sync_async_routing_API.py`).")
 
 
130
  break
131
+ else:
132
+ st.error(f"Error polling for result: {result_resp.status_code} - {result_resp.text}")
133
+ break
134
+
135
+ time.sleep(2)
136
 
137
+ # Sync ticket
 
 
138
  elif res.get("decision"):
 
139
  total_time = time.time() - start_time
140
+ # --- UPDATED SYNC MESSAGE ---
141
+ st.success("Received Real-Time Support Response:")
142
+
143
  st.write(f"**Decision:** {res['decision']}")
144
  st.write(f"**Reason:** {res['reason']}")
145
  st.write("**Next Actions:**")
146
  for step in res['next_actions']:
147
  st.write(f"- {step}")
148
+
149
  # Display Processing Time
150
  processing_time = res.get("processing_time")
151
  if processing_time:
152
  st.write(f"**AI Processing Time:** {processing_time:.2f} seconds")
153
+
154
  st.write(f"**Total round-trip time:** {total_time:.2f} seconds")
155
 
 
156
  retrieved_context = res.get("retrieved_context")
157
+ if retrieved_context:
158
+ with st.expander("Show RAG Context"):
159
  st.text(retrieved_context)
160
+
 
 
 
 
 
 
 
161
  else:
162
+ st.error(f"Error: Unknown response from orchestrator: {res}")
163
 
 
164
  else:
165
+ st.error(f"Error submitting ticket: {response.status_code} - {response.text}")
166
+
 
 
 
167
  except requests.exceptions.ConnectionError:
168
+ st.error("API connection failed. Is the Orchestrator (port 8000) running?")
169
  except Exception as e:
170
  st.error(f"An unexpected error occurred: {e}")
171
+
172
+ # --- NEW: Conditional spinner logic ---
173
+ if severity == "High":
174
+ # SYNC: Show spinner while waiting
175
+ with st.spinner("Contacting support... Please wait."):
176
+ make_api_call()
177
+ else:
178
+ # ASYNC: No spinner, just make the call.
179
+ # The "queued" status from make_api_call() will appear instantly.
180
+ make_api_call()
sync_async_routing_API.py CHANGED
@@ -56,37 +56,3 @@ def get_async_result(ticket_id: str):
56
  print(f"Error connecting to async result service: {e}")
57
  # If the async service can't be reached
58
  raise HTTPException(status_code=503, detail="Async service unavailable")
59
- # --- NEW ENDPOINT TO CLEAR MEMORY IN BOTH SERVICES ---
60
- @app.post("/clear_memory")
61
- def clear_all_memory():
62
- """Calls the clear_memory endpoint on both sync and async services."""
63
- sync_url = f"{SYNC_SERVICE_URL}/clear_memory"
64
- async_url = f"{ASYNC_SERVICE_URL}/clear_memory"
65
- results = {}
66
-
67
- # Try clearing sync memory
68
- try:
69
- print(f"Attempting to clear sync memory at {sync_url}")
70
- sync_resp = requests.post(sync_url, timeout=5) # Add timeout
71
- sync_resp.raise_for_status()
72
- results["sync_clear"] = sync_resp.json()
73
- print("Sync memory clear request successful.")
74
- except Exception as e:
75
- print(f"Error clearing sync memory: {e}")
76
- results["sync_clear"] = {"status": "error", "detail": str(e)}
77
-
78
- # Try clearing async memory
79
- try:
80
- print(f"Attempting to clear async memory at {async_url}")
81
- async_resp = requests.post(async_url, timeout=5) # Add timeout
82
- async_resp.raise_for_status()
83
- results["async_clear"] = async_resp.json()
84
- print("Async memory clear request successful.")
85
- except Exception as e:
86
- print(f"Error clearing async memory: {e}")
87
- results["async_clear"] = {"status": "error", "detail": str(e)}
88
-
89
- return results
90
- # --- END NEW ENDPOINT ---
91
-
92
-
 
56
  print(f"Error connecting to async result service: {e}")
57
  # If the async service can't be reached
58
  raise HTTPException(status_code=503, detail="Async service unavailable")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
sync_path_microservice.py CHANGED
@@ -216,10 +216,4 @@ def sync_ticket(ticket: Ticket):
216
  except Exception as e:
217
  print(f"--- Error processing sync ticket: {e} ---")
218
  raise HTTPException(status_code=500, detail=f"Internal server error: {e}")
219
- @app.post("/clear_memory")
220
- def clear_sync_memory():
221
- global memory_store
222
- print(f"Clearing sync memory (current size: {len(memory_store)}).")
223
- memory_store = []
224
- return {"status": "Sync memory cleared"}
225
 
 
216
  except Exception as e:
217
  print(f"--- Error processing sync ticket: {e} ---")
218
  raise HTTPException(status_code=500, detail=f"Internal server error: {e}")
 
 
 
 
 
 
219