Skip to content

Commit

Permalink
File linting
Browse files Browse the repository at this point in the history
  • Loading branch information
cweems committed Mar 5, 2024
1 parent a30279d commit 1c6151d
Show file tree
Hide file tree
Showing 19 changed files with 1,106 additions and 227 deletions.
18 changes: 9 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# Your ngrok or server URL
# E.g. 123.ngrok.io or myserver.fly.dev
SERVER="yourserverdomain.com"
SERVER=

# Service API Keys
OPENAI_API_KEY="sk-XXXXXX"
DEEPGRAM_API_KEY="YOUR-DEEPGRAM-API-KEY"
XI_API_KEY="YOUR-ELEVEN-LABS-API-KEY"
OPENAI_API_KEY=
DEEPGRAM_API_KEY=
XI_API_KEY=
# Available models at a signed GET request to /v1/models
XI_MODEL_ID="eleven_turbo_v2"
XI_MODEL_ID=eleven_turbo_v2

# See https://api.elevenlabs.io/v1/voices
# for a list of all available voices
VOICE_ID="21m00Tcm4TlvDq8ikWAM"
VOICE_ID=21m00Tcm4TlvDq8ikWAM

# Optional: Configure your Twilio credentials if you want
# to make test calls using '$ npm run outbound'.
TWILIO_ACCOUNT_SID="YOUR-ACCOUNT-SID"
TWILIO_AUTH_TOKEN="YOUR-AUTH-TOKEN"
TWILIO_ACCOUNT_SID=YOUR-ACCOUNT-SID
TWILIO_AUTH_TOKEN=YOUR-AUTH-TOKEN
FROM_NUMBER='+12223334444'
APP_NUMBER='+13334445555'
YOU_NUMBER='+14445556666'
YOUR_NUMBER='+14445556666'
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,7 @@ dist
# SvelteKit build / generate output
.svelte-kit

# Ignore Fly.io configuration file
.toml

# End of https://www.toptal.com/developers/gitignore/api/node
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ Copy `.env.example` to `.env` and configure the following environment variables:
SERVER="yourserverdomain.com"

# Service API Keys
OPENAI_API_KEY="sk-XXXXXX"
DEEPGRAM_API_KEY="YOUR-DEEPGRAM-API-KEY"
XI_API_KEY="YOUR-ELEVEN-LABS-API-KEY"
OPENAI_API_KEY="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"
DEEPGRAM_API_KEY="537c7613e8b0fda84bda1024a96546687eb9c4c7"
XI_API_KEY="6e4f365b7d1dc8dc316653a0915f99ec"
# Available models at a signed GET request to /v1/models
XI_MODEL_ID="eleven_turbo_v2"

Expand Down
60 changes: 30 additions & 30 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
require("dotenv").config();
const express = require("express");
const ExpressWs = require("express-ws");
const colors = require('colors');
require('dotenv').config();
require('colors');
const express = require('express');
const ExpressWs = require('express-ws');


const { GptService } = require("./services/gpt-service");
const { StreamService } = require("./services/stream-service");
const { TranscriptionService } = require("./services/transcription-service");
const { TextToSpeechService } = require("./services/tts-service");
const { GptService } = require('./services/gpt-service');
const { StreamService } = require('./services/stream-service');
const { TranscriptionService } = require('./services/transcription-service');
const { TextToSpeechService } = require('./services/tts-service');

const app = express();
ExpressWs(app);

const PORT = process.env.PORT || 3000;

app.post("/incoming", (req, res) => {
app.post('/incoming', (req, res) => {
res.status(200);
res.type("text/xml");
res.type('text/xml');
res.end(`
<Response>
<Connect>
Expand All @@ -26,8 +26,8 @@ app.post("/incoming", (req, res) => {
`);
});

app.ws("/connection", (ws, req) => {
ws.on("error", console.error);
app.ws('/connection', (ws) => {
ws.on('error', console.error);
// Filled in from start message
let streamSid;

Expand All @@ -36,62 +36,62 @@ app.ws("/connection", (ws, req) => {
const transcriptionService = new TranscriptionService();
const ttsService = new TextToSpeechService({});

let marks = []
let interactionCount = 0
let marks = [];
let interactionCount = 0;

// Incoming from MediaStream
ws.on("message", function message(data) {
ws.on('message', function message(data) {
const msg = JSON.parse(data);
if (msg.event === "start") {
if (msg.event === 'start') {
streamSid = msg.start.streamSid;
streamService.setStreamSid(streamSid);
console.log(`Twilio -> Starting Media Stream for ${streamSid}`.underline.red);
ttsService.generate({partialResponseIndex: null, partialResponse: "Hello! I understand you're looking for a pair of AirPods, is that correct?"}, 1);
} else if (msg.event === "media") {
ttsService.generate({partialResponseIndex: null, partialResponse: 'Hello! I understand you\'re looking for a pair of AirPods, is that correct?'}, 1);
} else if (msg.event === 'media') {
transcriptionService.send(msg.media.payload);
} else if (msg.event === "mark") {
} else if (msg.event === 'mark') {
const label = msg.mark.name;
console.log(`Twilio -> Audio completed mark (${msg.sequenceNumber}): ${label}`.red)
marks = marks.filter(m => m !== msg.mark.name)
} else if (msg.event === "stop") {
console.log(`Twilio -> Media stream ${streamSid} ended.`.underline.red)
console.log(`Twilio -> Audio completed mark (${msg.sequenceNumber}): ${label}`.red);
marks = marks.filter(m => m !== msg.mark.name);
} else if (msg.event === 'stop') {
console.log(`Twilio -> Media stream ${streamSid} ended.`.underline.red);
}
});

transcriptionService.on("utterance", async (text) => {
transcriptionService.on('utterance', async (text) => {
// This is a bit of a hack to filter out empty utterances
if(marks.length > 0 && text?.length > 5) {
console.log("Twilio -> Interruption, Clearing stream".red)
console.log('Twilio -> Interruption, Clearing stream'.red);
ws.send(
JSON.stringify({
streamSid,
event: "clear",
event: 'clear',
})
);
}
});

transcriptionService.on("transcription", async (text) => {
transcriptionService.on('transcription', async (text) => {
if (!text) { return; }
console.log(`Interaction ${interactionCount} – STT -> GPT: ${text}`.yellow);
gptService.completion(text, interactionCount);
interactionCount += 1;
});

gptService.on('gptreply', async (gptReply, icount) => {
console.log(`Interaction ${icount}: GPT -> TTS: ${gptReply.partialResponse}`.green )
console.log(`Interaction ${icount}: GPT -> TTS: ${gptReply.partialResponse}`.green );
ttsService.generate(gptReply, icount);
});

ttsService.on("speech", (responseIndex, audio, label, icount) => {
ttsService.on('speech', (responseIndex, audio, label, icount) => {
console.log(`Interaction ${icount}: TTS -> TWILIO: ${label}`.blue);

streamService.buffer(responseIndex, audio);
});

streamService.on('audiosent', (markLabel) => {
marks.push(markLabel);
})
});
});

app.listen(PORT);
Expand Down
6 changes: 3 additions & 3 deletions functions/checkInventory.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
function checkInventory(functionArgs) {
const model = functionArgs.model;
console.log("GPT -> called checkInventory function");
console.log('GPT -> called checkInventory function');

if (model?.toLowerCase().includes("pro")) {
if (model?.toLowerCase().includes('pro')) {
return JSON.stringify({ stock: 10 });
} else if (model?.toLowerCase().includes("max")) {
} else if (model?.toLowerCase().includes('max')) {
return JSON.stringify({ stock: 0 });
} else {
return JSON.stringify({ stock: 100 });
Expand Down
6 changes: 3 additions & 3 deletions functions/checkPrice.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
function checkPrice(functionArgs) {
let model = functionArgs.model;
console.log("GPT -> called checkPrice function");
if (model?.toLowerCase().includes("pro")) {
console.log('GPT -> called checkPrice function');
if (model?.toLowerCase().includes('pro')) {
return JSON.stringify({ price: 249 });
} else if (model?.toLowerCase().includes("max")) {
} else if (model?.toLowerCase().includes('max')) {
return JSON.stringify({ price: 549 });
} else {
return JSON.stringify({ price: 149 });
Expand Down
74 changes: 37 additions & 37 deletions functions/function-manifest.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,89 @@
// create metadata for all the available functions to pass to completions API
const tools = [
{
type: "function",
type: 'function',
function: {
name: "checkInventory",
description: "Check the inventory of airpods, airpods pro or airpods max.",
name: 'checkInventory',
description: 'Check the inventory of airpods, airpods pro or airpods max.',
parameters: {
type: "object",
type: 'object',
properties: {
model: {
type: "string",
"enum": ["airpods", "airpods pro", "airpods max"],
description: "The model of airpods, either the airpods, airpods pro or airpods max",
type: 'string',
'enum': ['airpods', 'airpods pro', 'airpods max'],
description: 'The model of airpods, either the airpods, airpods pro or airpods max',
},
},
required: ["model"],
required: ['model'],
},
returns: {
type: "object",
type: 'object',
properties: {
stock: {
type: "integer",
description: "An integer containing how many of the model are in currently in stock."
type: 'integer',
description: 'An integer containing how many of the model are in currently in stock.'
}
}
}
},
},
{
type: "function",
type: 'function',
function: {
name: "checkPrice",
description: "Check the price of given model of airpods, airpods pro or airpods max.",
name: 'checkPrice',
description: 'Check the price of given model of airpods, airpods pro or airpods max.',
parameters: {
type: "object",
type: 'object',
properties: {
model: {
type: "string",
"enum": ["airpods", "airpods pro", "airpods max"],
description: "The model of airpods, either the airpods, airpods pro or airpods max",
type: 'string',
'enum': ['airpods', 'airpods pro', 'airpods max'],
description: 'The model of airpods, either the airpods, airpods pro or airpods max',
},
},
required: ["model"],
required: ['model'],
},
returns: {
type: "object",
type: 'object',
properties: {
price: {
type: "integer",
description: "the price of the model"
type: 'integer',
description: 'the price of the model'
}
}
}
},
},
{
type: "function",
type: 'function',
function: {
name: "placeOrder",
description: "Places an order for a set of airpods.",
name: 'placeOrder',
description: 'Places an order for a set of airpods.',
parameters: {
type: "object",
type: 'object',
properties: {
model: {
type: "string",
"enum": ["airpods", "airpods pro"],
description: "The model of airpods, either the regular or pro",
type: 'string',
'enum': ['airpods', 'airpods pro'],
description: 'The model of airpods, either the regular or pro',
},
quantity: {
type: "integer",
description: "The number of airpods they want to order",
type: 'integer',
description: 'The number of airpods they want to order',
},
},
required: ["type", "quantity"],
required: ['type', 'quantity'],
},
returns: {
type: "object",
type: 'object',
properties: {
price: {
type: "integer",
description: "The total price of the order including tax"
type: 'integer',
description: 'The total price of the order including tax'
},
orderNumber: {
type: "integer",
description: "The order number associated with the order."
type: 'integer',
description: 'The order number associated with the order.'
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions functions/placeOrder.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
function placeOrder(functionArgs) {
const {model, quantity} = functionArgs;
console.log("GPT -> called placeOrder function");
console.log('GPT -> called placeOrder function');

// generate a random order number that is 7 digits
orderNum = Math.floor(Math.random() * (9999999 - 1000000 + 1) + 1000000);
const orderNum = Math.floor(Math.random() * (9999999 - 1000000 + 1) + 1000000);

// check model and return the order number and price with 7.9% sales tax
if (model?.toLowerCase().includes("pro")) {
if (model?.toLowerCase().includes('pro')) {
return JSON.stringify({ orderNumber: orderNum, price: Math.floor(quantity * 249 * 1.079)});
} else if (model?.toLowerCase().includes("max")) {
} else if (model?.toLowerCase().includes('max')) {
return JSON.stringify({ orderNumber: orderNum, price: Math.floor(quantity * 549 * 1.079) });
}
return JSON.stringify({ orderNumber: orderNum, price: Math.floor(quantity * 179 * 1.079) });
Expand Down
Loading

0 comments on commit 1c6151d

Please sign in to comment.