From c46d5ac7c2266bf9107e5f80713b999d0eeecce2 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 04:49:59 -0500 Subject: [PATCH 1/7] feat: completes calls on hangup --- src/call.js | 8 ++++++++ src/session.js | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/call.js b/src/call.js index 4fbec1c..adde558 100644 --- a/src/call.js +++ b/src/call.js @@ -109,4 +109,12 @@ app.post("/summarize", async (req, res) => { res.send(JSON.stringify({ SessionId: sessionId, summary: summary })); }); +app.post("/status", async (req, res) => { + let callId = req.body.CallSid; + let callStatus = req.body.CallStatus; + if (callStatus === "completed") { + await completeCall(callId); + } +}); + export default app; diff --git a/src/session.js b/src/session.js index 3b2b4e7..adba470 100644 --- a/src/session.js +++ b/src/session.js @@ -21,6 +21,17 @@ export const findSessionByCallId = async (callId) => { }); }; +export const completeCall = async (callId) => { + return await db.session.update({ + where: { + callId: callId, + }, + data: { + endedAt: new Date(), + }, + }); +}; + export const transferSession = async (callId, operatorPhone) => { return await db.session.update({ where: { From ed2b6b00e50274c5b7d9b8319146102be5902ee8 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 04:53:23 -0500 Subject: [PATCH 2/7] fix: forgotten import on completeCall --- src/call.js | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/call.js diff --git a/src/call.js b/src/call.js new file mode 100644 index 0000000..943b711 --- /dev/null +++ b/src/call.js @@ -0,0 +1,123 @@ +import * as dotenv from "dotenv"; +dotenv.config(); + +import { Router, json } from "express"; +import log from "loglevel"; + +import twilio from "twilio"; +const accountSid = process.env.TWILIO_ACCOUNT_SID; +const authToken = process.env.TWILIO_AUTH_TOKEN; +const phone_number = process.env.TWILIO_PHONE_NUMBER; +const VoiceResponse = twilio.twiml.VoiceResponse; + +import { Role } from "@prisma/client"; + +import { + addMessage, + createSession, + findSessionByCallId, + transferSession, + checkOperatorReady, + postSummary, + completeCall, +} from "./session.js"; +import { chat, summarize } from "./chat.js"; + +const app = Router(); +app.use(json()); + +app.post("/receive", async (req, res) => { + let callId = req.body.CallSid; + console.log(`CallSid: ${callId}`); + const twiml = new VoiceResponse(); + + await createSession(req.body.CallSid, req.body.From); + + const gather = twiml.gather({ + action: "/call/respond", + method: "POST", + input: "speech", + language: "en-US", + speechTimeout: "auto", + model: "experimental_conversations", + }); + + gather.say("Welcome to the suicide hotline. Tell me what's going on?."); + + console.log(twiml.toString()); + + twiml.redirect("/call/receive"); + + res.type("text/xml"); + res.send(twiml.toString()); +}); + +app.post("/respond", async (req, res) => { + let callId = req.body.CallSid; + console.log(`CallSid: ${callId}`); + const twiml = new VoiceResponse(); + + let transcription = req.body.SpeechResult; + await addMessage(callId, Role.USER, transcription); + + let operatorReady = await checkOperatorReady(callId); + + if (operatorReady) { + let session = await findSessionByCallId(callId); + let operatorPhone = session.operatorPhone; + console.log(`transferring call ${callId} to ${operatorPhone}`); + + transferSession(req.body.CallSid, operatorPhone); + twiml.say("We're connecting you to a counselor now."); + + const dial = twiml.dial({}); + dial.number(operatorPhone); + res.type("text/xml"); + res.send(twiml.toString()); + return; + } + + const gather = twiml.gather({ + action: "/call/respond", + method: "POST", + input: "speech", + language: "en-US", + speechTimeout: "auto", + model: "experimental_conversations", + }); + + let response = await chat(callId); + + gather.say(response); + await addMessage(callId, Role.BOT, response); + + twiml.redirect("/call/respond"); + + res.type("text/xml"); + res.send(twiml.toString()); +}); + +app.post("/summarize", async (req, res) => { + let sessionId = req.body.SessionId; + console.log(`summarizing ${sessionId}`); + + let summary = await summarize(sessionId); + console.log(summary); + + await postSummary(sessionId, summary); + + res.type("application/json"); + res.send(JSON.stringify({ SessionId: sessionId, summary: summary })); +}); + +app.post("/status", async (req, res) => { + let callId = req.body.CallSid; + let callStatus = req.body.CallStatus; + + if (callStatus === "completed") { + console.log(`completing call ${callId}`); + await completeCall(callId); + } +}); + +export default app; From a958234388084955044a6e3aae43fb64264a9263 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 04:56:59 -0500 Subject: [PATCH 3/7] fix: fixed duplicate call.js --- src/api/call.js | 7 ++- src/call.js | 123 ------------------------------------------------ 2 files changed, 5 insertions(+), 125 deletions(-) delete mode 100644 src/call.js diff --git a/src/api/call.js b/src/api/call.js index b30d716..943b711 100644 --- a/src/api/call.js +++ b/src/api/call.js @@ -19,8 +19,9 @@ import { transferSession, checkOperatorReady, postSummary, -} from "../lib/session.js"; -import { chat, summarize } from "../lib/chat.js"; + completeCall, +} from "./session.js"; +import { chat, summarize } from "./chat.js"; const app = Router(); app.use(json()); @@ -112,7 +113,9 @@ app.post("/summarize", async (req, res) => { app.post("/status", async (req, res) => { let callId = req.body.CallSid; let callStatus = req.body.CallStatus; + if (callStatus === "completed") { + console.log(`completing call ${callId}`); await completeCall(callId); } }); diff --git a/src/call.js b/src/call.js deleted file mode 100644 index 943b711..0000000 --- a/src/call.js +++ /dev/null @@ -1,123 +0,0 @@ -import * as dotenv from "dotenv"; -dotenv.config(); - -import { Router, json } from "express"; -import log from "loglevel"; - -import twilio from "twilio"; -const accountSid = process.env.TWILIO_ACCOUNT_SID; -const authToken = process.env.TWILIO_AUTH_TOKEN; -const phone_number = process.env.TWILIO_PHONE_NUMBER; -const VoiceResponse = twilio.twiml.VoiceResponse; - -import { Role } from "@prisma/client"; - -import { - addMessage, - createSession, - findSessionByCallId, - transferSession, - checkOperatorReady, - postSummary, - completeCall, -} from "./session.js"; -import { chat, summarize } from "./chat.js"; - -const app = Router(); -app.use(json()); - -app.post("/receive", async (req, res) => { - let callId = req.body.CallSid; - console.log(`CallSid: ${callId}`); - const twiml = new VoiceResponse(); - - await createSession(req.body.CallSid, req.body.From); - - const gather = twiml.gather({ - action: "/call/respond", - method: "POST", - input: "speech", - language: "en-US", - speechTimeout: "auto", - model: "experimental_conversations", - }); - - gather.say("Welcome to the suicide hotline. Tell me what's going on?."); - - console.log(twiml.toString()); - - twiml.redirect("/call/receive"); - - res.type("text/xml"); - res.send(twiml.toString()); -}); - -app.post("/respond", async (req, res) => { - let callId = req.body.CallSid; - console.log(`CallSid: ${callId}`); - const twiml = new VoiceResponse(); - - let transcription = req.body.SpeechResult; - await addMessage(callId, Role.USER, transcription); - - let operatorReady = await checkOperatorReady(callId); - - if (operatorReady) { - let session = await findSessionByCallId(callId); - let operatorPhone = session.operatorPhone; - console.log(`transferring call ${callId} to ${operatorPhone}`); - - transferSession(req.body.CallSid, operatorPhone); - twiml.say("We're connecting you to a counselor now."); - - const dial = twiml.dial({}); - dial.number(operatorPhone); - res.type("text/xml"); - res.send(twiml.toString()); - return; - } - - const gather = twiml.gather({ - action: "/call/respond", - method: "POST", - input: "speech", - language: "en-US", - speechTimeout: "auto", - model: "experimental_conversations", - }); - - let response = await chat(callId); - - gather.say(response); - await addMessage(callId, Role.BOT, response); - - twiml.redirect("/call/respond"); - - res.type("text/xml"); - res.send(twiml.toString()); -}); - -app.post("/summarize", async (req, res) => { - let sessionId = req.body.SessionId; - console.log(`summarizing ${sessionId}`); - - let summary = await summarize(sessionId); - console.log(summary); - - await postSummary(sessionId, summary); - - res.type("application/json"); - res.send(JSON.stringify({ SessionId: sessionId, summary: summary })); -}); - -app.post("/status", async (req, res) => { - let callId = req.body.CallSid; - let callStatus = req.body.CallStatus; - - if (callStatus === "completed") { - console.log(`completing call ${callId}`); - await completeCall(callId); - } -}); - -export default app; From 1048bf1ab1307c59f948d9c024e95f5561c15ea4 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 04:58:51 -0500 Subject: [PATCH 4/7] fix: fixed broken imports with new file struc --- src/api/call.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/call.js b/src/api/call.js index 943b711..9d15e01 100644 --- a/src/api/call.js +++ b/src/api/call.js @@ -20,8 +20,8 @@ import { checkOperatorReady, postSummary, completeCall, -} from "./session.js"; -import { chat, summarize } from "./chat.js"; +} from "../lib/session.js"; +import { chat, summarize } from "../lib/chat.js"; const app = Router(); app.use(json()); From 3edd54d75cb73ffcdd2dbb704991eb4deead4068 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 05:03:26 -0500 Subject: [PATCH 5/7] feat: prompt engineering for a friendlier and more informative convo --- src/api/call.js | 4 +++- src/lib/chat.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/call.js b/src/api/call.js index 9d15e01..ebf20fe 100644 --- a/src/api/call.js +++ b/src/api/call.js @@ -42,7 +42,9 @@ app.post("/receive", async (req, res) => { model: "experimental_conversations", }); - gather.say("Welcome to the suicide hotline. Tell me what's going on?."); + gather.say( + "Welcome to the Suicide Prevention Hotline. You have reached a virtual resource where you can talk through your problems in a safe and supportive environment. Please know that you are not alone, and help is available. How are you feeling right now?" + ); console.log(twiml.toString()); diff --git a/src/lib/chat.js b/src/lib/chat.js index b832cda..b6781ca 100644 --- a/src/lib/chat.js +++ b/src/lib/chat.js @@ -29,7 +29,7 @@ export const chat = async (callId) => { { role: "system", content: - "ChatGPT, for the following conversation, please pretend to be a therapist working at a suicide prevention hotline. Respond as if I've called you. Limit your responses to 20 seconds, and don't recommend that they seek other help. Make sure you continue the conversation by ending every response with a question.", + "ChatGPT, for the following conversation, please pretend to be a therapist working at a suicide prevention hotline. Respond as if I've called you. Limit your responses to 20 seconds. Don't recommend that they seek other help. Don't ask if they've spoken to a specialist about the issue yet. Make sure you continue the conversation by ending every response with a question.", }, ]; From 8949a8502bbaef73da0e4540218b88ce5e6c29c2 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 05:08:27 -0500 Subject: [PATCH 6/7] feat: added new polly voice --- src/api/call.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/call.js b/src/api/call.js index ebf20fe..deb5b77 100644 --- a/src/api/call.js +++ b/src/api/call.js @@ -43,6 +43,7 @@ app.post("/receive", async (req, res) => { }); gather.say( + { voice: "Polly.Joanna" }, "Welcome to the Suicide Prevention Hotline. You have reached a virtual resource where you can talk through your problems in a safe and supportive environment. Please know that you are not alone, and help is available. How are you feeling right now?" ); @@ -70,7 +71,10 @@ app.post("/respond", async (req, res) => { console.log(`transferring call ${callId} to ${operatorPhone}`); transferSession(req.body.CallSid, operatorPhone); - twiml.say("We're connecting you to a counselor now."); + twiml.say( + { voice: "Polly.Joanna" }, + "We're connecting you to a counselor now." + ); const dial = twiml.dial({}); dial.number(operatorPhone); @@ -90,7 +94,7 @@ app.post("/respond", async (req, res) => { let response = await chat(callId); - gather.say(response); + gather.say({ voice: "Polly.Joanna" }, response); await addMessage(callId, Role.BOT, response); twiml.redirect("/call/respond"); From c08ac9c67070e44e2bd262e27c023fa53a3c5755 Mon Sep 17 00:00:00 2001 From: Rushil Umaretiya Date: Sun, 5 Mar 2023 05:11:35 -0500 Subject: [PATCH 7/7] feat: changed voice again --- src/api/call.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/call.js b/src/api/call.js index deb5b77..35cb6ec 100644 --- a/src/api/call.js +++ b/src/api/call.js @@ -43,7 +43,7 @@ app.post("/receive", async (req, res) => { }); gather.say( - { voice: "Polly.Joanna" }, + { voice: "Polly.Salli" }, "Welcome to the Suicide Prevention Hotline. You have reached a virtual resource where you can talk through your problems in a safe and supportive environment. Please know that you are not alone, and help is available. How are you feeling right now?" ); @@ -72,7 +72,7 @@ app.post("/respond", async (req, res) => { transferSession(req.body.CallSid, operatorPhone); twiml.say( - { voice: "Polly.Joanna" }, + { voice: "Polly.Sali" }, "We're connecting you to a counselor now." ); @@ -94,7 +94,7 @@ app.post("/respond", async (req, res) => { let response = await chat(callId); - gather.say({ voice: "Polly.Joanna" }, response); + gather.say({ voice: "Polly.Salli" }, response); await addMessage(callId, Role.BOT, response); twiml.redirect("/call/respond");