goctests0 commited on
Commit
35212b7
·
verified ·
1 Parent(s): 83c99ca

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +67 -3
  2. database.py +9 -0
app.py CHANGED
@@ -148,8 +148,16 @@ def patient_input():
148
  })
149
 
150
 
151
- @app.route("/provider-response", methods=["POST"])
152
- def provider_response():
 
 
 
 
 
 
 
 
153
  interaction_id = request.form.get("interaction_id")
154
  response_text = request.form.get("response_text")
155
 
@@ -163,10 +171,49 @@ def provider_response():
163
  patient_language = interaction["detected_language"]
164
  translated_response = translation.translate(response_text, "english", patient_language)
165
 
166
- audio_filename = f"response_{interaction_id}.wav"
167
  audio_path = os.path.join(AUDIO_DIR, audio_filename)
168
  tts.synthesize_speech(translated_response, patient_language, audio_path)
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  database.update_interaction_response(interaction_id, response_text, translated_response)
171
 
172
  return jsonify({
@@ -193,6 +240,11 @@ def pending_interactions():
193
  return jsonify(database.get_pending_interactions())
194
 
195
 
 
 
 
 
 
196
  @app.route("/history")
197
  def history():
198
  if "user_id" not in session:
@@ -200,6 +252,18 @@ def history():
200
  return jsonify(database.get_interactions_for_user(session["user_id"]))
201
 
202
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  @app.route("/end-session", methods=["POST"])
204
  def end_session_route():
205
  if "session_id" in session:
 
148
  })
149
 
150
 
151
+ @app.route("/preview-response", methods=["POST"])
152
+ def preview_response():
153
+ """
154
+ Runs the exact same translate + synthesize pipeline as
155
+ /provider-response below, so the provider can read and hear precisely
156
+ what the patient will receive before committing to it. Unlike
157
+ /provider-response, this never touches the database - only "Send
158
+ reply" actually saves a response. Each preview click is a real
159
+ translation + speech synthesis call, same cost as an actual send.
160
+ """
161
  interaction_id = request.form.get("interaction_id")
162
  response_text = request.form.get("response_text")
163
 
 
171
  patient_language = interaction["detected_language"]
172
  translated_response = translation.translate(response_text, "english", patient_language)
173
 
174
+ audio_filename = f"preview_{interaction_id}.wav"
175
  audio_path = os.path.join(AUDIO_DIR, audio_filename)
176
  tts.synthesize_speech(translated_response, patient_language, audio_path)
177
 
178
+ return jsonify({
179
+ "translated_response": translated_response,
180
+ "audio_url": f"/static/audio/{audio_filename}",
181
+ })
182
+
183
+
184
+ @app.route("/provider-response", methods=["POST"])
185
+ def provider_response():
186
+ interaction_id = request.form.get("interaction_id")
187
+ response_text = request.form.get("response_text")
188
+ # Optional cache-reuse fields: if the provider already generated a
189
+ # preview of this exact reply via /preview-response and didn't edit
190
+ # it afterward, the frontend passes the already-computed translation
191
+ # back here so this route can skip re-translating and re-synthesizing
192
+ # speech. Both are best-effort - if the preview audio isn't actually
193
+ # on disk, this quietly falls back to doing the full work itself,
194
+ # exactly as if these fields had never been sent.
195
+ cached_translation = request.form.get("translated_response")
196
+ reuse_audio = request.form.get("reuse_audio") == "true"
197
+
198
+ if not interaction_id or not response_text:
199
+ return jsonify({"error": "interaction_id and response_text are required"}), 400
200
+
201
+ interaction = database.get_interaction(interaction_id)
202
+ if not interaction:
203
+ return jsonify({"error": "interaction not found"}), 404
204
+
205
+ patient_language = interaction["detected_language"]
206
+ audio_filename = f"response_{interaction_id}.wav"
207
+ audio_path = os.path.join(AUDIO_DIR, audio_filename)
208
+ preview_path = os.path.join(AUDIO_DIR, f"preview_{interaction_id}.wav")
209
+
210
+ if cached_translation and reuse_audio and os.path.exists(preview_path):
211
+ translated_response = cached_translation
212
+ os.replace(preview_path, audio_path)
213
+ else:
214
+ translated_response = translation.translate(response_text, "english", patient_language)
215
+ tts.synthesize_speech(translated_response, patient_language, audio_path)
216
+
217
  database.update_interaction_response(interaction_id, response_text, translated_response)
218
 
219
  return jsonify({
 
240
  return jsonify(database.get_pending_interactions())
241
 
242
 
243
+ @app.route("/completed-interactions")
244
+ def completed_interactions():
245
+ return jsonify(database.get_completed_interactions())
246
+
247
+
248
  @app.route("/history")
249
  def history():
250
  if "user_id" not in session:
 
252
  return jsonify(database.get_interactions_for_user(session["user_id"]))
253
 
254
 
255
+ @app.route("/patient-history/<user_id>")
256
+ def patient_history(user_id):
257
+ """
258
+ All of one patient's interactions, for the provider workspace's
259
+ "conversation history" panel. Distinct from /history above: that route
260
+ always looks up the current browser's own session, which only works
261
+ for the patient viewing their own messages. The provider needs to look
262
+ up a specific patient's history by id instead.
263
+ """
264
+ return jsonify(database.get_interactions_for_user(user_id))
265
+
266
+
267
  @app.route("/end-session", methods=["POST"])
268
  def end_session_route():
269
  if "session_id" in session:
database.py CHANGED
@@ -114,6 +114,15 @@ def get_pending_interactions():
114
  return [dict(row) for row in cursor.fetchall()]
115
 
116
 
 
 
 
 
 
 
 
 
 
117
  def get_interaction(interaction_id):
118
  with get_connection() as connection:
119
  cursor = _run(connection, "SELECT * FROM interaction WHERE id = ?", (interaction_id,))
 
114
  return [dict(row) for row in cursor.fetchall()]
115
 
116
 
117
+ def get_completed_interactions():
118
+ with get_connection() as connection:
119
+ cursor = _run(
120
+ connection,
121
+ "SELECT * FROM interaction WHERE provider_response IS NOT NULL ORDER BY timestamp DESC",
122
+ )
123
+ return [dict(row) for row in cursor.fetchall()]
124
+
125
+
126
  def get_interaction(interaction_id):
127
  with get_connection() as connection:
128
  cursor = _run(connection, "SELECT * FROM interaction WHERE id = ?", (interaction_id,))