Skip to content

Commit

Permalink
- Updated search schema to include fulfilment and tags
Browse files Browse the repository at this point in the history
- Updated prompt to cleanup empty fields
  • Loading branch information
mayurvir committed Apr 5, 2024
1 parent 37069eb commit 80a534b
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 23 deletions.
4 changes: 3 additions & 1 deletion config/openai.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
{ "role": "system", "content": "A typical order flow should be search > select > init > confirm."},
{ "role": "system", "content": "Use the response of search from assistant to select items from the list of items provided by the assistant."},
{ "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": "For `select`, `init`, `confirm`, you must use the item `id` as part of the payload for selected item instead of name or any other key."}
{ "role": "system", "content": "For `select`, `init`, `confirm`, you must use the item `id` as part of the payload for selected item instead of name or any other key."},
{ "role": "system", "content": "For hotel booking, there should be two fulfilment stoprs, one for check-in and one for check-out."},
{ "role": "system", "content": "For search actions, you should check the network policy for supported tags and use them based on user preferences to prepare the search payload."}
]
}
11 changes: 10 additions & 1 deletion config/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
"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, dhp:consultation:0.1.0 for doctors or healthcare, tourism for tickets and tours",
"bap_subscriber_id": "mit-ps-bap.becknprotocol.io",
"bap_subscriber_url": "https://mit-ps-bap.becknprotocol.io",
"version": "1.1.0"
"version": "1.1.0",
"policies": {
"tags": [
{ "pet-friendly": { "enum": ["yes", "no"]}},
{ "ev-charging": { "enum": ["yes", "no"]}},
{ "accomodation-type“": { "enum": ["campsite", "hotel", "independent-house"]}},
{ "vehicle-type": { "enum": ["2-wheeler", "4-wheeler"]}},
{ "connector-type": { "enum": ["CCS", "CHAdeMo"]}}
]
}
}
]
8 changes: 5 additions & 3 deletions controllers/Bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ async function process_text(req, res) {
};
}

logger.info(`\u001b[1;34m Profile: ${JSON.stringify(session.profile)}\u001b[0m`);

// get action
ai.action = await ai.get_beckn_action_from_text(message, session.actions.formatted);

Expand Down Expand Up @@ -91,7 +93,7 @@ async function process_text(req, res) {
session.text.push({ role: 'assistant', content: response.formatted });
}
else{
response = await process_action(ai.action, message, session, sender);
response = await process_action(ai.action, message, session, sender, format);

// update actions
if(response.formatted && response.raw){
Expand Down Expand Up @@ -129,7 +131,7 @@ async function process_text(req, res) {
* @param {*} session
* @returns
*/
async function process_action(action, text, session, sender=null){
async function process_action(action, text, session, sender=null, format='application/json'){
let ai = new AI();
let response = {
raw: null,
Expand All @@ -149,7 +151,7 @@ async function process_action(action, text, session, sender=null){

// Prepare request
if(schema && beckn_context){
const request = await ai.get_beckn_request_from_text(text, session.actions.raw, beckn_context, schema);
const request = await ai.get_beckn_request_from_text(text, [...session.text, ...session.actions.raw], beckn_context, schema, session.profile);

if(request.status){
// call api
Expand Down
99 changes: 83 additions & 16 deletions schemas/core_1.1.0/search.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,14 @@ components:
description: 'The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing <ul><li>What they want (A product, service, offer)</li><li>Who they want (A seller, service provider, agent etc)</li><li>Where they want it and where they want it from</li><li>When they want it (start and end time of fulfillment</li><li>How they want to pay for it</li></ul><br>This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags<br>This is typically used by the BAP to send the purpose of the user''s search to the BPP. This will be used by the BPP to find products or services it offers that may match the user''s intent.<br>For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,<ul><li>Where would they like to begin their journey (intent.fulfillment.start.location)</li><li>Where would they like to end their journey (intent.fulfillment.end.location)</li><li>When would they like to begin their journey (intent.fulfillment.start.time)</li><li>When would they like to end their journey (intent.fulfillment.end.time)</li><li>Who is the transport service provider they would like to avail services from (intent.provider)</li><li>Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)</li><li>What kind of fare product would they like to purchase (intent.item)</li><li>What add-on services would they like to avail</li><li>What offers would they like to apply on their booking (intent.offer)</li><li>What category of services would they like to avail (intent.category)</li><li>What additional luggage are they carrying</li><li>How would they like to pay for their journey (intent.payment)</li></ul><br>For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,<ul><li>Where would they like to get their scan/test done (intent.fulfillment.start.location)</li><li>When would they like to get their scan/test done (intent.fulfillment.start.time)</li><li>When would they like to get the results of their test/scan (intent.fulfillment.end.time)</li><li>Who is the service provider they would like to avail services from (intent.provider)</li><li>Who is getting the test/scan (intent.fulfillment.customer)</li><li>What kind of test/scan would they like to purchase (intent.item)</li><li>What category of services would they like to avail (intent.category)</li><li>How would they like to pay for their journey (intent.payment)</li></ul>'
type: object
properties:
descriptor:
description: 'A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object.'
item:
description: Details of the item that the consumer wants to search
allOf:
- $ref: '#/components/schemas/Descriptor'
- $ref: '#/components/schemas/Item'
fulfillment:
description: Details on how the customer wants their order fulfilled
allOf:
- $ref: '#/components/schemas/Fulfillment'
Descriptor:
description: Physical description of something.
type: object
Expand All @@ -103,20 +107,83 @@ components:
type: string
description: It should contain the search query string such as product or service name.
code:
type: string
Item:
description: 'Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item.'
type: object
properties:
descriptor:
description: Physical description of the item
allOf:
- $ref: '#/components/schemas/Descriptor'
tags:
type: array
items:
$ref: '#/components/schemas/TagGroup'
Tag:
description: 'Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service.'
type: object
properties:
descriptor:
description: 'Description of the Tag, can be used to store detailed information.'
allOf:
- $ref: '#/components/schemas/Descriptor'
value:
description: The value of the tag. This set by the BPP and rendered as-is by the BAP.
type: string
short_desc:
display:
description: 'This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value.'
type: boolean
TagGroup:
description: 'A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316'
type: object
properties:
list:
description: 'An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema.'
type: array
items:
$ref: '#/components/schemas/Tag'
Fulfillment:
description: Describes how a an order will be rendered/fulfilled to the end-customer
type: object
properties:
stops:
description: The list of logical stops encountered during the fulfillment of an order.
type: array
items:
$ref: '#/components/schemas/Stop'
Stop:
description: A logical point in space and time during the fulfillment of an order.
type: object
properties:
location:
description: Location of the stop. It should only be used if a valid gps location is avaiable in the context.
allOf:
- $ref: '#/components/schemas/Location'
type:
description: The type of stop. Allowed values of this property can be defined by the network policy.
type: string
long_desc:
time:
description: Timings applicable at the stop.
allOf:
- $ref: '#/components/schemas/Time'
Location:
description: The physical location of something
type: object
properties:
gps:
description: The GPS co-ordinates of this location.
allOf:
- $ref: '#/components/schemas/Gps'
Gps:
description: Describes a GPS coordinate. This should only be used if a valid gps location is available.
type: string
pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$'
Time:
description: 'Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations<br>This has properties like label, time stamp,duration,range, days, schedule'
type: object
properties:
timestamp:
type: string
additional_desc:
type: object
properties:
url:
type: string
content_type:
type: string
enum:
- text/plain
- text/html
- application/json
format: date-time

34 changes: 32 additions & 2 deletions services/AI.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class AI {
try{
const completion = await openai.chat.completions.create({
messages: openai_messages,
model: process.env.OPENAI_MODEL_ID
model: process.env.OPENAI_MODEL_ID,
max_tokens: 300
})
response = completion.choices[0].message.content;
}
Expand Down Expand Up @@ -174,6 +175,7 @@ class AI {
{ "role": "system", "content": `Schema definition: ${JSON.stringify(schema)}` },
...openai_config.SCHEMA_TRANSLATION_CONTEXT,
{"role": "system", "content": `This is the user profile that you can use for transactions : ${JSON.stringify(profile)}`},
{"role": "system", "content": `Network policy: ${JSON.stringify(registry_config[0].policies)}`},
{"role": "system", "content": `Following is the conversation history`},
...context,
{ "role": "user", "content": instruction }
Expand All @@ -188,7 +190,6 @@ class AI {
})
const jsonString = completion.choices[0].message.content.trim()
logger.info(`Got beckn payload`)
logger.info(jsonString)
logger.info(`\u001b[1;34m ${JSON.stringify(completion.usage)}\u001b[0m`)

let response = JSON.parse(jsonString)
Expand All @@ -200,6 +201,11 @@ class AI {
};
response.url = `${beckn_context.base_url}/${beckn_context.action}`

// Post-processing
response.body.message = await this.cleanup_payload(response.body.message);

logger.info(JSON.stringify(response));

action_response = {...action_response, status: true, data: response}
}
catch(e){
Expand All @@ -211,6 +217,30 @@ class AI {
return action_response;
}

async cleanup_payload(payload){
let response = {};
const openai_messages = [
{ role: 'system', content: 'You are required to take the given json payload and remove any empty fields from it and return the resulting json object.'},
{ role: 'system', content: `Input payload: ${JSON.stringify(payload)}`}
]

try{
const completion = await openai.chat.completions.create({
messages: openai_messages,
model: process.env.OPENAI_MODEL_ID,
response_format: { type: 'json_object' },
temperature: 0,
})
const jsonString = completion.choices[0].message.content.trim()
response = JSON.parse(jsonString)
}
catch(e){
logger.error(e);
}

return response;
}

async compress_search_results(search_res){

const desired_output = {
Expand Down
Loading

0 comments on commit 80a534b

Please sign in to comment.