Skip to content

Commit

Permalink
- Added multiple domains as part of a registry config that can be lat…
Browse files Browse the repository at this point in the history
…er used to lookup from actual registry

- Added seperate github workflows for different test case
- Fixed issues with config resolution
- Added test cases for workflow
  • Loading branch information
mayurvir committed Mar 29, 2024
1 parent d211b55 commit 9b1708c
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 34 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/api_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Run api tests

on:
push:
branches-ignore:
- main
jobs:
test-lint:
name: Test
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up environment variables
run: |
echo "OPENAI_AI_KEY=${{secrets.OPENAI_AI_KEY}}" >> .env
echo "OPENAI_MODEL_ID=${{secrets.OPENAI_MODEL_ID}}" >> .env
echo "OPEN_AI_EMBEDDINGS_MODEL=${{secrets.OPEN_AI_EMBEDDINGS_MODEL}}" >> .env
echo "PORT=${{secrets.PORT}}" >> .env
echo "SERVER_PORT=${{secrets.SERVER_PORT}}" >> .env
echo "TWILIO_ACCOUNT_SID=${{secrets.TWILIO_ACCOUNT_SID}}" >> .env
echo "TWILIO_AUTH_TOKEN=${{secrets.TWILIO_AUTH_TOKEN}}" >> .env
echo "TWILIO_NUMBER=${{secrets.TWILIO_NUMBER}}" >> .env
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Run api tests
run: npm run docker:test:apis
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Run linting and tests
name: Run linting tests

on:
push:
Expand Down Expand Up @@ -34,6 +34,3 @@ jobs:

- name: Run linting
run: npm run docker:lint

- name: Run tests
run: npm run docker:test
36 changes: 36 additions & 0 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Run unit tests

on:
push:
branches-ignore:
- main
jobs:
test-lint:
name: Test
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up environment variables
run: |
echo "OPENAI_AI_KEY=${{secrets.OPENAI_AI_KEY}}" >> .env
echo "OPENAI_MODEL_ID=${{secrets.OPENAI_MODEL_ID}}" >> .env
echo "OPEN_AI_EMBEDDINGS_MODEL=${{secrets.OPEN_AI_EMBEDDINGS_MODEL}}" >> .env
echo "PORT=${{secrets.PORT}}" >> .env
echo "SERVER_PORT=${{secrets.SERVER_PORT}}" >> .env
echo "TWILIO_ACCOUNT_SID=${{secrets.TWILIO_ACCOUNT_SID}}" >> .env
echo "TWILIO_AUTH_TOKEN=${{secrets.TWILIO_AUTH_TOKEN}}" >> .env
echo "TWILIO_NUMBER=${{secrets.TWILIO_NUMBER}}" >> .env
echo "TEST_RECEPIENT_NUMBER=${{secrets.TEST_RECEPIENT_NUMBER}}" >> .env
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Run unit tests
run: npm run docker:test:unit
11 changes: 1 addition & 10 deletions config/openai.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
{ "key": "rating", "description": "Provide a rating" },
{ "key": "support", "description": "Get support" }
],
"SUPPORTED_DOMAINS": [
{"key": "uei:charging", "description": "Used for energy transactions"}
],
"SCHEMA_TRANSLATION_CONTEXT": [
{ "role": "system", "content": "Your job is to identify the endpoint, method and request body from the given schema, based on the last user input and return the extracted details in the following JSON structure : \n\n {'url':'', 'method':'', 'body':''}'"},
{ "role": "system", "content": "A typical order flow should be search > select > init > confirm."},
Expand All @@ -22,11 +19,5 @@
{ "role": "system", "content": "Use the response of search request from assistant for filling transaction_id, bpp_id, bpp_uri in the context of all calls except `search`."},
{ "role": "system", "content": "Use the response from assistant to select items from the list of items provided by the assistant."}

],
"PRESETS" : {
"bap_id": "mit-ps-bap.becknprotocol.io",
"bap_uri": "https://mit-ps-bap.becknprotocol.io",
"version": "1.1.0",
"base_url": "https://mit-ps-bap-client.becknprotocol.io"
}
]
}
14 changes: 14 additions & 0 deletions config/registry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"url": "https://mit-ps-bap-client.becknprotocol.io",
"domains": [
"uei:charging",
"retail:1.1.0",
"hospitality"
],
"description": "This network supports multiple domains e.g. uei:charging for ev chargers, retail:1.1.0 for retail stores including grocceries and pet supplies, hospitality for hotels",
"bap_subscriber_id": "mit-ps-bap.becknprotocol.io",
"bap_subscriber_url": "https://mit-ps-bap.becknprotocol.io",
"version": "1.1.0"
}
]
64 changes: 46 additions & 18 deletions services/AI.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { v4 as uuidv4 } from 'uuid'
const openai = new OpenAI({
apiKey: process.env.OPENAI_AI_KEY,
})
const config = JSON.parse(readFileSync('./config/openai.json'))
const openai_config = JSON.parse(readFileSync('./config/openai.json'))
const registry_config = JSON.parse(readFileSync('./config/registry.json'))

class AI {

Expand All @@ -23,7 +24,7 @@ class AI {
*/
async get_beckn_action_from_text(text){
const openai_messages = [
{ role: 'system', content: `Your job is to analyse the text input given by user and identify if that is an action based on given set of actions. The supported actions with their descriptions are : ${JSON.stringify(config.SUPPORTED_ACTIONS)}.` },
{ role: 'system', content: `Your job is to analyse the text input given by user and identify if that is an action based on given set of actions. The supported actions with their descriptions are : ${JSON.stringify(openai_config.SUPPORTED_ACTIONS)}.` },
{ role: 'system', content: `You must return a json in the following format {'action':'SOME_ACTION_OR_NULL', 'response': 'Should be reponse based on the query.'}` },
{ role: 'system', content: `If the instruction is an action, the action key should be set under 'action' otehrwise action should be null and response should contain completion for the given text.` },
{ role: 'system', content: `A typical order flow should be search > select > init > confirm.`},
Expand Down Expand Up @@ -57,16 +58,6 @@ class AI {
message: null
}


// Preparse presets
let presets = {
...config.PRESETS,
domain : "Any of these : uei:charging",
message_id : uuidv4(),
transaction_id: uuidv4(),
action :`Any of these : ${JSON.stringify(config.SUPPORTED_DOMAINS.map(item => item.key))}`
}

// get the right/compressed schema
const schema_response = await this._get_schema_by_instruction(instruction)
const schema = schema_response.data;
Expand All @@ -75,8 +66,8 @@ class AI {
if(schema_response.status){
let openai_messages = [
{ "role": "system", "content": `Schema definition: ${JSON.stringify(schema)}` },
...config.SCHEMA_TRANSLATION_CONTEXT,
{"role": "system", "content": `Use the following presets to fill the context : ${JSON.stringify(presets)}`},
...openai_config.SCHEMA_TRANSLATION_CONTEXT,
{"role": "system", "content": `Prepare 'context' from this : ${JSON.stringify(schema_response.data.config)}`},
...context,
{ "role": "user", "content": instruction }
]
Expand All @@ -93,7 +84,7 @@ class AI {
logger.info(`\u001b[1;34m ${JSON.stringify(completion.usage)}\u001b[0m`)

const response = JSON.parse(jsonString)
response.url = `${config.PRESETS.base_url}/${response.body.context.action}`
response.url = `${schema_response.data.config.base_url}/${response.body.context.action}`
action_response = {...action_response, status: true, data: response}
}
catch(e){
Expand Down Expand Up @@ -149,15 +140,29 @@ class AI {
async _get_schema_by_instruction(instruction) {
let response = {
status: false,
data: null,
data: {
schema:null,
config: null,
action: null
},
message : null
}

const action = await this.get_beckn_action_from_text(instruction);
if(action?.action){
response.data.config = await this._get_config_by_action(action.action);
try {
const filePath = `./schemas/core_1.1.0/${action?.action}.yml`;
const schema = yaml.load(readFileSync(filePath, 'utf8'));
response = {...response, status: true, data: schema};
response = {
...response,
status: true,
data: {
...response.data,
schema: schema,
action: action.action
}
}; // update schema and action
} catch (error) {
const defaultFilePath = './schemas/core_1.1.0.yml';
const defaultSchema = yaml.load(readFileSync(defaultFilePath, 'utf8'));
Expand All @@ -170,7 +175,15 @@ class AI {
}
}

response = {...response, status: true, data: defaultSchema};
response = {
...response,
status: true,
data: {
...response.data,
schema: defaultSchema,
action: action.action
}
};
}
}
else{
Expand Down Expand Up @@ -208,6 +221,21 @@ class AI {
}

}

async _get_config_by_action(action){

// TODO: update this fucntion to lookup the root registry and use AI to find the best registry for this, get rid of registry_oconfig.
return {
action: action,
version: registry_config[0].version,
domain:`Any one of ${JSON.stringify(registry_config[0].domains)} based on this description: ${registry_config[0].description}`,
message_id : uuidv4(),
transaction_id: uuidv4(),
base_url: registry_config[0].url,
bap_id: registry_config[0].bap_subscriber_id,
bap_uri: registry_config[0].bap_subscriber_url,
}
}
}

export default AI;
4 changes: 2 additions & 2 deletions tests/unit/controllers/bot.test.js → tests/apis/bot.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, it } from 'mocha'
import app from '../../../server.js'
import app from '../../server.js'
import request from 'supertest'
import * as chai from 'chai'
const expect = chai.expect


describe.skip('API tests for /webhook endpoint for an end to end search > select > init > confirm use case', () => {
describe('API tests for /webhook endpoint for an end to end search > select > init > confirm use case', () => {
it('Should test succesful search response using /webhook endpoint', async () => {
const response = await request(app).post('/webhook').send({
From: process.env.TEST_RECEPIENT_NUMBER,
Expand Down

0 comments on commit 9b1708c

Please sign in to comment.