Skip to content

Commit

Permalink
Merge pull request #74 from beckn/feat/static_map
Browse files Browse the repository at this point in the history
Added: Static Map Code
  • Loading branch information
mayurvir authored Apr 8, 2024
2 parents fb34607 + cb52caf commit 07261e4
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 41 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ dist
.yarn/install-state.gz
.pnp.*
.DS_Store

13 changes: 9 additions & 4 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,7 +382,6 @@ async function process_action(action, text, session, sender=null, format='applic

return response;
}

export default {
process_wa_webhook,
process_text
Expand Down
4 changes: 4 additions & 0 deletions public/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
10 changes: 6 additions & 4 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import {
notify,
triggerExceptionOnLocation
} from './controllers/ControlCenter.js'
import path from 'path'
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express()
app.use(cors())
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use('/public', express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json())

// Define endpoints here
Expand All @@ -28,7 +31,6 @@ app.post('/cancel-booking', cancelBooking)
app.post('/update-catalog', updateCatalog)
app.post('/trigger-exception', triggerExceptionOnLocation)


// Reset all sessions
const db = new DBService()
await db.clear_all_sessions()
Expand Down
97 changes: 67 additions & 30 deletions services/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import twilio from 'twilio'
import logger from '../utils/logger.js'
import axios from 'axios'
import AI from './AI.js'

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 @@ -36,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 @@ -92,37 +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}`,
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;
}

if(media_url){
body.mediaUrl = [media_url];
}

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;
}
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;
}
}
}

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}`);
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 07261e4

Please sign in to comment.