Skip to content

Commit

Permalink
Added static image url, added developer mode so the local code works …
Browse files Browse the repository at this point in the history
…fine
  • Loading branch information
mayurvir committed Apr 8, 2024
1 parent 1d8bd50 commit a8dcdba
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 78 deletions.
2 changes: 2 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ TWILIO_NUMBER=
TEST_RECEPIENT_NUMBER=
STRAPI_TOURISM_TOKEN=
GOOGLE_MAPS_API_KEY=your_api_key_here
SERVER_URL=http://13.201.62.138:3001
DEVELOPER_MODE_ON=0
2 changes: 2 additions & 0 deletions .github/workflows/api_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
echo "STRAPI_TOURISM_TOKEN=${{secrets.STRAPI_TOURISM_TOKEN}}" >> .env
echo "GOOGLE_MAPS_API_KEY=${{secrets.GOOGLE_MAPS_API_KEY}}" >> .env
echo "SERVER_URL=${{secrets.SERVER_URL}}" >> .env
echo "DEVELOPER_MODE_ON=${{secrets.DEVELOPER_MODE_ON}}" >> .env
- name: Set up Node.js
uses: actions/setup-node@v2
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
echo "STRAPI_TOURISM_TOKEN=${{secrets.STRAPI_TOURISM_TOKEN}}" >> .env
echo "GOOGLE_MAPS_API_KEY=${{secrets.GOOGLE_MAPS_API_KEY}}" >> .env
echo "SERVER_URL=${{secrets.SERVER_URL}}" >> .env
echo "DEVELOPER_MODE_ON=${{secrets.DEVELOPER_MODE_ON}}" >> .env
- name: Create SSH key file
run: echo -e "${{ secrets.EC2_SSH_KEY }}" > ~/ec2_key
env:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/lint_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
echo "STRAPI_TOURISM_TOKEN=${{secrets.STRAPI_TOURISM_TOKEN}}" >> .env
echo "GOOGLE_MAPS_API_KEY=${{secrets.GOOGLE_MAPS_API_KEY}}" >> .env
echo "SERVER_URL=${{secrets.SERVER_URL}}" >> .env
echo "DEVELOPER_MODE_ON=${{secrets.DEVELOPER_MODE_ON}}" >> .env
- name: Set up Node.js
uses: actions/setup-node@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
echo "STRAPI_TOURISM_TOKEN=${{secrets.STRAPI_TOURISM_TOKEN}}" >> .env
echo "GOOGLE_MAPS_API_KEY=${{secrets.GOOGLE_MAPS_API_KEY}}" >> .env
echo "SERVER_URL=${{secrets.SERVER_URL}}" >> .env
echo "DEVELOPER_MODE_ON=${{secrets.DEVELOPER_MODE_ON}}" >> .env
- name: Set up Node.js
uses: actions/setup-node@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,6 @@ dist
.yarn/install-state.gz
.pnp.*
.DS_Store


public/
30 changes: 10 additions & 20 deletions controllers/Bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ async function process_text(req, res) {

let response= {
raw: null,
formatted: null
formatted: null,
media:null
};

const EMPTY_SESSION = {
Expand Down Expand Up @@ -192,7 +193,12 @@ async function process_text(req, res) {
session.selected_route = session.routes[index];
const url = `https://www.google.com/maps/dir/${session.selected_route.source_gps.lat},${session.selected_route.source_gps.lng}/${session.selected_route.destination_gps.lat},${session.selected_route.destination_gps.lng}/`;
route_response.message = `Your route has been actived. Here is the link to navigate : ${url}. What do you want to do next?`;

const map_image_url = await mapService.get_static_image_path([session.selected_route]);
if(map_image_url){
const map_image_url_server = await actionsService.download_file(map_image_url);
logger.info(`Image url : ${map_image_url_server}`)
if(map_image_url_server) response.media=[map_image_url_server]
}
}
const formatting_response = await ai.format_response(route_response, [{ role: 'user', content: message },...session.text]);
response.formatted = formatting_response.message;
Expand Down Expand Up @@ -246,7 +252,7 @@ async function process_text(req, res) {

// Send response
if(format!='application/json'){
await actionsService.send_message(sender, response.formatted)
await actionsService.send_message(sender, response.formatted, response.media || [])
res.send("Done!")
}
else (raw_yn && response.raw) ? res.send(response.raw) : res.send(response.formatted)
Expand Down Expand Up @@ -376,23 +382,7 @@ async function process_action(action, text, session, sender=null, format='applic

return response;
}
async function downloadFile (req, res) {
try{
const url = "https://maps.googleapis.com/maps/api/staticmap?size=300x300&path=enc:yrpqF`|x_SoFxgCwfApWyeBqkCa`Cq\_pHk`@qiLji@iuUo|@qoZaHwiRdFmgS|g@_dQn^eoXzy@ynO}AicKao@swPwjCo}U{vGofLceCwsEwzAuhFmdF{tNqoAg`PoKgoVngEgzLrm@}`FppB_mJgGsqD_zAanK{hDiyDshAqaEqdAwzBrf@izHao@ksAmjEikCeQmzHh_JocFnwEefDjeGswFtuCk|Tz~AavDllBosEfiAefInk@sfOd`FqlDhv@{yGwFivKuMmwM{{A}tEE{jF|m@guNpbTqoEncKibGpyIkqCh~K}hAhiKul@buAa`Bd`BwlBl~BsLz`JiwAlpTmoBnkOcu@h}N{oBb}YsNv}x@o~A`}VecAnrArf@zyImoDfnMacCtsGoyJpw^}nEjsGcwCxpIs^dzM|u@haQi}AjcP{vA|cNuiCdz_@ahGzyMwbCpjPpHh}b@gmCh}Ocn@d_R{aDthRwnCjrHsQl}IeyAlaPo|C|a@i{B`iAouFtJgjGuz@urAfdBwnEtiG{mBxLswEic@swBcFa`BmbA}dAxiAut@trAwcA}r@alB`eAm}@`rBeuD`t@sfI|o@{K{w@_o@`OjC|aBnc@jxB_o@`rAawBfr@{bDnpHamG`dNc{E`zJihJjr@i_Dm^}qCpk@swD`bCcdExjI}fHteM}vC`jIg|D|uDusIbuLefDvsFoqDdwH_y@`mBk_EsX_jFc`GcyAfd@eu@xyCctDhiEg_FrcHseFdxC{uEdeBiiBjqC_tDts@srLroAct@b{AcThpAiiBt]sx@viAkjHznHcjEjfDgpJ|bIs_F~_C}jBl`@|qAb{Ajy@zzI{w@zl@hHxy@az@o@r\le@n_@h|AWxzAeeA~`Eg`Dji@toAv[ay@~Pl^pGmi@vn@q^tFnc@duBqvAeXcIfw@uUbb@ayA}@}hC`~Bg_CdoCk{BjuDafAxcC`~@jaDlm@`eDyNr}Cyr@j{E}_CpoAqfDdxCw`CpcFqiCfhLasE~uJaaEdaD{hBtkDjQlmDjwBdoMb@|{Hv`MlqFfwDnoEdsEh~IeJftD{fDdzEksBpmHxAx}EnVlhIgz@f`DbZfwA|p@kmAfsB_`BpbAmc@~}AzmAoUdtAtjAl[xyAbqC~gA~eAxnBsHzfBuDldBnwAlk@kOfj@v{@pqAxzBrbEzdBhxBdYhmGmhGlhDm}BzaCo_G|[krBp_DuWp~DjgFreC~yBdrAquBpqE`_CxlAlpDd{AhtE_mCpcD~YdkDh_Cbx@~cC~`C&key=AIzaSyD1nA0k1OsFbmIAqD7N1nYrAI6CqkZbHDc"
const download_file_resp = await actionsService.download_file(url,path.join(__dirname,'../public'))
return res.status(200).json({
status:true,
message:download_file_resp.message
})
}catch(error){
return res.status(400).json({
status:false,
message:'Some Error Occured'
})
}
}
export default {
process_wa_webhook,
process_text,
downloadFile
process_text
}
5 changes: 1 addition & 4 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ const __dirname = path.dirname(__filename);

const app = express()
app.use(cors())
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
app.use('/static', express.static(path.join(__dirname, 'public')));
// parse application/json
app.use('/public', express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json())

// Define endpoints here
Expand All @@ -32,7 +30,6 @@ app.post('/notify', notify)
app.post('/cancel-booking', cancelBooking)
app.post('/update-catalog', updateCatalog)
app.post('/trigger-exception', triggerExceptionOnLocation)
app.get('/download', messageController.downloadFile);

// Reset all sessions
const db = new DBService()
Expand Down
116 changes: 65 additions & 51 deletions services/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import twilio from 'twilio'
import logger from '../utils/logger.js'
import axios from 'axios'
import AI from './AI.js'
import {writeFileSync} from 'fs'
import {createWriteStream} from 'fs'
import path from 'path'
import { v4 as uuidv4 } from 'uuid'
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const accountSid = process.env.TWILIO_ACCOUNT_SID
const authToken = process.env.TWILIO_AUTH_TOKEN
const twilioNumber = process.env.TWILIO_NUMBER

const client = twilio(accountSid, authToken)
const __dirname = path.dirname(__filename);
const rootPath = path.resolve(__dirname, './');

class Actions {

Expand Down Expand Up @@ -37,7 +42,7 @@ class Actions {
if(request.data.context && request.data.context.action==='search'){
response.data.responses = response.data.responses.filter(res => res.message && res.message.catalog && res.message.catalog.providers && res.message.catalog.providers.length > 0)
if(response.data.responses.length > 0)
response.data.responses = response.data.responses.slice(0, 1);
response.data.responses = response.data.responses.slice(0, 1);
}
responseObject = {
status: true,
Expand Down Expand Up @@ -93,59 +98,68 @@ class Actions {
const format_response_response = await this.ai.format_response(
call_api_response.data,
[...context, { role: 'user', content: message }]
)
response.formatted = format_response_response.message
}
}
} catch (error) {
logger.error(`Error processing instruction: ${error.message}`)
response.formatted = `Failed to process the instruction: ${error.message}`
)
response.formatted = format_response_response.message
}
}
} catch (error) {
logger.error(`Error processing instruction: ${error.message}`)
response.formatted = `Failed to process the instruction: ${error.message}`
}

return response;
}

return response;
}

async send_message(recipient, message, media_url=null) {
try {
let body = {
body: message,
from: `whatsapp:${twilioNumber}`,
to: recipient.includes('whatsapp:') ? recipient : `whatsapp:${recipient}`,
}

if(media_url){
body.mediaUrl = [media_url];
async send_message(recipient, message, media_url=null) {
try {
let body = {
body: message,
from: `whatsapp:${twilioNumber}`,
to: recipient.includes('whatsapp:') ? recipient : `whatsapp:${recipient}`,
}

if(media_url && !process.env.DEVELOPER_MODE_ON){
body.mediaUrl = [media_url];
}
let data = await client.messages.create(body)
const status = await client.messages(data.sid).fetch()
return { deliveryStatus: status.status }
} catch (error) {
logger.error(`Error sending message: ${error.message}`)
return false;
}
let data = await client.messages.create(body)
const status = await client.messages(data.sid).fetch()
return { deliveryStatus: status.status }
} catch (error) {
logger.error(`Error sending message: ${error.message}`)
return false;
}
}

async download_file(url, destination_path) {
try {
const response = await axios.get(url, 'GET',{responseType:'arraybuffer'});

const filePath = path.join(destination_path, 'downloaded-image.png');
// const writer = createWriteStream(filePath);
console.log(Buffer.from(response.data));
writeFileSync(filePath, response.data);
// response.data.pipe(writer);
// return new Promise((resolve, reject) => {
// writer.on('finish', resolve);
// writer.on('error', reject);
// });
return {
message:'File downloaded successfully and saved at ' + filePath

async download_file(url) {
const destination_path = path.join(rootPath,'../public');
try {
const response = await axios({
method: 'GET',
url: url,
responseType: 'stream',
});

const fileName = `${uuidv4()}.png`;
const filePath = path.join(destination_path, fileName);

// Create a write stream to save the file
const writer = createWriteStream(filePath);

// Pipe the response data to the file
response.data.pipe(writer);

return new Promise((resolve, reject) => {
writer.on('finish', ()=>{
resolve(`${process.env.SERVER_URL}/public/${fileName}`)
});
writer.on('error', reject);

});
} catch (error) {
logger.error(`Error sending message: ${error.message}`)
return null;
}
} catch (error) {
logger.error(`Error sending message: ${error.message}`)
return false;
}
}
}

export default Actions

export default Actions
6 changes: 3 additions & 3 deletions tests/unit/controllers/bot.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('Test cases for Google maps', () => {
expect(source_gps).to.have.property('lng');
})

it('It should take a trip plannign input and generate static route image and directions link.', async () => {
it.only('It should take a trip plannign input and generate static route image and directions link.', async () => {
const ask = "Can you plean a trip from Denver to Yellowstone national park?";

// identify source and destination
Expand Down Expand Up @@ -90,8 +90,8 @@ describe('Test cases for Google maps', () => {
const directions = `https://www.google.com/maps/dir/${source_gps.lat},${source_gps.lng}/${destination_gps.lat},${destination_gps.lng}/`;
const route_image = `https://maps.googleapis.com/maps/api/staticmap?size=300x300&path=enc:${routes[selected_route].overview_polyline.points}&key=${process.env.GOOGLE_MAPS_API_KEY}`;


await actionsService.send_message(process.env.TEST_RECEPIENT_NUMBER, `Here are the directions: ${directions}`); // should also pass the route image, its correctly throwing an error.
const server_route_image = await actionsService.download_file(route_image);
await actionsService.send_message(process.env.TEST_RECEPIENT_NUMBER, `Here are the directions: ${directions}`, server_route_image);
logger.info(`directions: ${directions}`);
logger.info(`route_image: ${route_image}`);
expect(routes).to.be.an('array').that.is.not.empty;
Expand Down
1 change: 1 addition & 0 deletions tests/unit/services/actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as chai from 'chai'
const expect = chai.expect
import ActionService from '../../../services/Actions.js'
import { describe } from 'mocha'

const actionsService = new ActionService()

describe.skip('Test cases for process_instruction function', ()=> {
Expand Down

0 comments on commit a8dcdba

Please sign in to comment.