I am trying to develop an API to upload the intent to Dialogflow V2. I have tried below snippet, which it is not working however if trying to communicate with Dialogflow it does work (detect intent)and does get a reply from the Dialogflow for queries.
PERMISSION
I AM & ADMIN > SERVICE ACCOUNTS > DIALOGFLOW ADMIN
ERROR
Error: 7 PERMISSION_DENIED: IAM permission 'dialogflow.entityTypes.create' on 'projects/dexter-47332/agent' denied.
BLOGS/ REFERENCES
Dialogflow easy way for authorization
https://github.com/dialogflow/dialogflow-nodejs-client-v2/blob/master/samples/resource.js#L26
https://www.npmjs.com/package/dialogflow
https://developers.google.com/apis-explorer/
https://cloud.google.com/docs/authentication/production
//------- keys.json (test 1)
{
"type": "service_account",
"project_id": "mybot",
"private_key_id": "123456asd",
"private_key": "YOURKEY",
"client_email": "yourID#mybot.iam.gserviceaccount.com",
"client_id": "098091234",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/yourID%40mybot.iam.gserviceaccount.com"
}
//--------------------- ** (test 2) ** ---------
let privateKey = 'key';
let clientEmail = "email";
let config = {
credentials: {
private_key: privateKey,
client_email: clientEmail
}
}
function createEntityTypes(projectId) {
// [START dialogflow_create_entity]
// Imports the Dialogflow library
const dialogflow = require('dialogflow');
// ******** Instantiates clients (Test 1)********
const entityTypesClient = new dialogflow.EntityTypesClient({
'keyFilename': './keys.json'
});
const intentsClient = new dialogflow.IntentsClient({
'keyFilename': './keys.json'
});
// ******** Instantiates clients (Test 2)********
const entityTypesClient = new dialogflow.EntityTypesClient(config);
const intentsClient = new dialogflow.IntentsClient(config);
// The path to the agent the created entity type belongs to.
const agentPath = intentsClient.projectAgentPath(projectId);
const promises = [];
// Create an entity type named "size", with possible values of small, medium
// and large and some synonyms.
const sizeRequest = {
parent: agentPath,
entityType: {
displayName: 'test',
kind: 'KIND_MAP',
autoExpansionMode: 'AUTO_EXPANSION_MODE_UNSPECIFIED',
entities: [{
value: 'small',
synonyms: ['small', 'petit']
},
{
value: 'medium',
synonyms: ['medium']
},
{
value: 'large',
synonyms: ['large', 'big']
},
],
},
};
promises.push(
entityTypesClient
.createEntityType(sizeRequest)
.then(responses => {
console.log('Created size entity type:');
logEntityType(responses[0]);
})
.catch(err => {
console.error('Failed to create size entity type ----->:', err);
})
);
}
createEntityTypes(projectId);
You can use JWT(JSON Web Tokens) for authenticating with service accounts like in this example
const serviceAccount = { }; // JSON key contents {"type": "service_account",...
const serviceAccountAuth = new google.auth.JWT({
email: serviceAccount.client_email,
key: serviceAccount.private_key,
scopes: 'https://www.googleapis.com/auth/calendar'
});
For more OAuth2.0 scopes for Google APIs you can see the full list here.
I encountered the same error. I corrected it by deleting the current service account and creating a new one and selected the "owner" option for the role.
The associated service-account has to have the role "Dialogflow API Admin" to be able to create intents and entities.
I think you must provide a name parameter there in the sizeRequest and make it equal to an empty string.
Take a look at the code snippet.
let request = {
parent: `projects/${PROJECID}/agent`,
entityType: {
name: '',
autoExpansionMode: 'AUTO_EXPANSION_MODE_DEFAULT',
displayName: 'size_type',
enableFuzzyExtraction: false,
entities: [
{
value: 'Big',
synonyms: ['big', 'large', 'huge']
},
{
value: 'Medium',
synonyms: ['medium', 'not big']
}
],
kind: 'KIND_MAP'
},
languageCode: 'en'
};
Please let me know if this helps.
Related
I'm building a marketplace (you can imagine it like an Ebay where there are buyer and seller). And i want to get an items that bought customer (and vice versa with seller).
Here is my checkout session service:
async charge(userId: number, dto: CreateChargeDto) {
//Get an item by id
const item = await this.prisma.item.findUnique({
where: {
id: dto.itemId,
},
});
if (!item) {
throw new BadRequestException('There is no item with this id');
}
// Search for user
const user = await this.prisma.user.findUnique({
where: {
id: userId,
},
});
//update customer
await this.updateCustomer(user.stripeCustomerId, dto);
const session = await this.stripe.checkout.sessions.create({
success_url: 'http://localhost:3000/success?message=Succesful+payment',
cancel_url: 'http://localhost:3000/404?message=Payment+canceled',
mode: 'payment',
currency: 'pln',
customer: user.stripeCustomerId,
customer_update: {
address: 'auto',
},
metadata: {
seller_id: item.userId, // here is where i save seller id
},
line_items: [
{
quantity: 1,
price_data: {
currency: 'pln',
unit_amount: item.price * 100,
product_data: {
name: item.name,
images: item.images,
metadata: {
id: item.id,
},
},
},
},
],
});
return session.id;
}
async getCheckoutList(userId: number) {
const user = await this.prisma.user.findUnique({
where: {
id: userId,
},
});
const checkouts = await this.stripe.
return checkouts.data;
}
And now i wanna filter this session checkouts so i can display them in buyer (or seller) personal page.
const checkouts = await this.stripe.checkout.sessions.list({
where: {
metadata: {
seller_id: // seller id
}
}
How can i do it?
There's currently no way to filter for Checkout Sessions by metadata.
Some other options are :
Listen for the checkout.session.completed webhook event, save the data to your DB and then perform your own filtering. See https://stripe.com/docs/webhooks for more information on handling webhooks.
Add the metadata to the PaymentIntent also using the following parameter : https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-payment_intent_data-metadata. You can then use the Search API to filter for the
corresponding PaymentIntent with https://stripe.com/docs/search. Once
you have the PaymentIntent, retrieve the corresponding
Checkout Session with
https://stripe.com/docs/api/checkout/sessions/list#list_checkout_sessions-payment_intent
To filter for Checkout Sessions by Customer, you can use https://stripe.com/docs/api/checkout/sessions/list#list_checkout_sessions-customer
So the best in my opinion in this situation is to use a webhook.
The perfect example in Nestjs you can read here: https://wanago.io/2021/07/05/api-nestjs-stripe-events-webhooks/
I am working with the Geolocation API on my discord.js bot. I have the api working properly and i receive the info i wanted into the console log but i have been unable to integrate the data i receive from the console to the actual bot embed. Any help is appreciated
var IPGeolocationAPI = require('ip-geolocation-api-javascript-sdk');
var ipgeolocationApi = new IPGeolocationAPI("8c402b955bfb4b82a7353abc99c9dca9", false);
const Discord = require('discord.js');
module.exports = {
name: 'ip',
execute(message, args) {
var inp = args[0]
// Function to handle response from IP Geolocation API
function handleResponse(json) {
console.log(json);
message.author.send(json);
/*
//create embed
const embed = new Discord.MessageEmbed()
.setTitle(`**${inp}**`)
json.forEach((data, value) => {
embed.addField(data, value)
}) //end for each
message.author.send({
embed
});
*/
} //end handle
var GeolocationParams = require('ip-geolocation-api-javascript-sdk/GeolocationParams.js');
// Get complete geolocation in English for IP address input by argument
var geolocationParams = new GeolocationParams();
geolocationParams.setIPAddress(inp);
geolocationParams.setLang('en');
ipgeolocationApi.getGeolocation(handleResponse, geolocationParams);
}
}
Errors:
for normal send: DiscordAPIError: Cannot send an empty message
for embed: json.forEach is not a function
console output:
{
ip: '123.456.789(ip removed)',
continent_code: 'NA',
continent_name: 'North America',
country_code2: 'US',
country_code3: 'USA',
country_name: 'United States',
country_capital: 'Washington',
state_prov: 'Georgia',
district: '',
city: 'Marietta',
zipcode: '30060',
latitude: '33.92530',
longitude: '-84.48170',
is_eu: false,
calling_code: '+1',
country_tld: '.us',
languages: 'en-US,es-US,haw,fr',
country_flag: 'https://ipgeolocation.io/static/flags/us_64.png',
geoname_id: '4207783',
isp: 'Total Server Solutions L.L.C.',
connection_type: '',
organization: 'Total Server Solutions L.L.C.',
currency: { code: 'USD', name: 'US Dollar', symbol: '$' },
time_zone: {
name: 'America/New_York',
offset: -5,
current_time: '2020-05-07 12:21:15.314-0400',
current_time_unix: 1588868475.314,
is_dst: true,
dst_savings: 1
}
}
the json variable in your code is an object. Rather than forEach (which is meant for arrays) try
for (var key in json){
//loop through all , pick what you want
}
I'm building a content middleware which gather contents from our external publishers. The publishers will share their contents either in rss or json and the key/value field would be different from each other. To make thing easier, I created a config file where I can pre-defined the key/value and the feed type. The problem is, how can I dynamically return this config value based on publishers name.
Example: To get Publisher #1 feed type, I just can use config.articles.rojak_daily.url_feed
my config file /config/index.js
module.exports = {
batch:100,
mysql: {
database: process.env.database,
host: process.env.host,
username: process.env.username,
password: process.env.password
},
articles:{
rojak_daily:{ // Publisher 1
url: 'xxx',
url_feed: 'rss',
id: null,
Name: 'title',
Description: 'description',
Link: 'link',
DatePublishFrom: 'pubDate',
LandscapeImage: 's3image',
SiteName: 'Rojak Daily',
SiteLogo: null
},
rojak_weekly:{ // publisher 2
url: 'xxx',
url_feed: 'json',
id: null,
Name: 'Name',
Description: 'Desc',
Link: 'link',
DatePublishFrom: 'pubDate',
LandscapeImage: 's3image',
SiteName: 'Rojak Weekly',
SiteLogo: null
}
}
}
my main application script
const config = require('#config'); // export from config file
class Main {
constructor(){
this.publishers = ['rojak_daily','rojak_weekly'];
}
// Main process
async startExport(){
try{
for(let publisher of this.publishers){
const feedType = await this.getFeedType(publisher)
const result = (feedType == 'rss')? await this.rss.start(publisher): await this.json.start(publisher)
return result
}
}catch(err){
console.log("Error occured: ", err)
}
}
// Get feed type from config
async getFeedType(publisher){
return await config.articles.rojak_daily.url_feed;
// this only return publisher 1 url feed.
// my concern is to dynamically passing variable
// into this config file (example: config.articles.<publisher>.url_feed)
}
}
module.exports = Main
async getFeedType(publisher){
return await config.articles[publisher].url_feed;
}
You can access properties of objects by variable
You could either loop over the articles by using Object.entries(articles) or Object.values(articles) in conjunction with Array.prototype.forEach(), or since you already have the name of the publisher you could access that entry with config.articles[publisher].url_feed, like so:
const config = {
articles: {
rojak_daily: { // Publisher 1
url: 'xxx',
url_feed: 'rss',
id: null,
Name: 'title',
Description: 'description',
Link: 'link',
DatePublishFrom: 'pubDate',
LandscapeImage: 's3image',
SiteName: 'Rojak Daily',
SiteLogo: null
},
rojak_weekly: { // publisher 2
url: 'xxx',
url_feed: 'json',
id: null,
Name: 'Name',
Description: 'Desc',
Link: 'link',
DatePublishFrom: 'pubDate',
LandscapeImage: 's3image',
SiteName: 'Rojak Weekly',
SiteLogo: null
}
}
}
const publishers = ['rojak_daily', 'rojak_weekly']
function getFeedType(publisher) {
return config.articles[publisher].url_feed;
}
publishers.forEach(publisher => console.log(getFeedType(publisher)));
I have a working serverless application deployed on Lambda (nodejs6.10) and can create and read users from my DynamoDB, however, I have been having problems trying to perform an update on a specific attribute.
Basically, my table has a key of userId and two attributes called email and score.
The application detects if a referral code (userId) was supplied and if so it should increment their score by 1. Below are the params that I am passing to the dynamoDb.update function.
if (refcode) {
console.log("A referral code: " + refcode + " was detected");
const params = {
TableName: USERS_TABLE,
Key: {
userId: refcode
},
UpdateExpression: "set score = score + :val",
ExpressionAttributeValues: {
":val": 1
},
ReturnValues: "UPDATED_NEW"
};
console.log(params);
dynamoDb.update(params, (error, result) => {
console.log("Checking for error...");
if (error) {
console.log(error);
res.status(400), json({ error: "Could not GET user" });
}
console.log("Checking for result...");
if (result.Item) {
console.log("Item updated");
const { userId, email, score } = result.Item;
} else {
res.status(404).json({ error: "Invalid referral code" });
console.log("Invalid ref code");
}
});
}
In Cloudwatch I can see that my function has entered this part of the logic successfully, however, it looks like it never runs the dynamoDb.update part. Here are the cloudwatch logs:
START RequestId: 7d92d4da-a710-11e8-abdd-039e23e278bd Version: $LATEST
2018-08-23T20:09:52.392Z 7d92d4da-a710-11e8-abdd-039e23e278bd A referral code: cEBeGM1sk was detected
2018-08-23T20:09:52.393Z 7d92d4da-a710-11e8-abdd-039e23e278bd { TableName: '**<redacted>**',
Key: { userId: 'cEBeGM1sk' },
UpdateExpression: 'set score = score + :val',
ExpressionAttributeValues: { ':val': 1 },
ReturnValues: 'UPDATED_NEW' }
2018-08-23T20:09:52.550Z 7d92d4da-a710-11e8-abdd-039e23e278bd Reached the end - taking user to thank you page
END RequestId: 7d92d4da-a710-11e8-abdd-039e23e278bd
REPORT RequestId: 7d92d4da-a710-11e8-abdd-039e23e278bd Duration: 1530.76 ms Billed Duration: 1600 ms Memory Size: 128 MB Max Memory Used: 45 MB
Any help much appreciated! It should work according to the atomic update example given on the AWS documentation: AWS Documentation
Use add not set. If initial value is undefined, 0 will be used.
This code does what is expected to be done:
const AWS = require('aws-sdk');
const getEnv = require('../../../helpers/environment/get');
AWS.config.update({
accessKeyId: getEnv('AWS_ACCESS_KEY'),
secretAccessKey: getEnv('AWS_ACCESS_KEY_SECRET'),
region: getEnv('AWS_REGION'),
});
const client = new AWS.DynamoDB.DocumentClient();
const queryResult = await dynamo.update({
TableName: getEnv('AWS_DYNAMO_TABLE_LOG'),
Key: {
pk: 'a',
t: 1,
},
UpdateExpression: 'add #test :value',
ExpressionAttributeNames: {
'#test': 'test_incr',
},
ExpressionAttributeValues: {
':value': 2,
},
ReturnConsumedCapacity: 'TOTAL',
ReturnValues: 'ALL_NEW',
}, (error, data) => {console.log({error, data})});
Consider using a newer version of NodeJS with your lambda ;) any was supported recent LTS is often best choice https://github.com/nodejs/Release#release-schedule
Also for DynamoDB nodejs client i personaly find this doc most usefull: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html
P.s. about lambda version, at the moment supported versions are node 14 and 12 without additional config. Yet some of aws services when integrating requires older version, aka 12
Thanks, Lukas!
The documentation was very confusing for a new developer - your answer has explained and fixed my problem, and shown how to use the ExpressionAttributeNames correctly, Thank you!
const params = {
TableName: USERS_TABLE,
Key: {
userId: refcode
},
UpdateExpression: "add #test :value",
ExpressionAttributeNames: {
"#test": "score"
},
ExpressionAttributeValues: {
":value": 2
},
ReturnConsumedCapacity: "TOTAL",
ReturnValues: "ALL_NEW"
};
So without the merge function below, this code sends an email on save, but I cannot for the life of me get email merge to work in Netsuite 2.0, so how do I merge an advanced pdf template with an item fulfillment and email it?
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*/
define(['N/email','N/render', 'N/record', 'N/file'],
function(email, record, file,render) {
function afterSubmit(context) {
function templatemerge() {
var myMergeResult = render.mergeEmail({
templateId: 121,
entity: {
type: 'employee',
id: 18040
},
recipient: {
type: 'employee',
id: 18040
},
supportCaseId: 'NULL',
transactionId: 1176527,
customRecord: 'NULL'
});
}
templatemerge();
function sendEmailWithAttachement() {
var newId = context.newRecord;
var emailbody = 'attachment';
var senderId = 18040;
var recipientEmail = 'email#email.com';
email.send({
author: senderId,
recipients: recipientEmail,
subject: 'Item Fulfillments',
body: emailbody
});
}
sendEmailWithAttachement();
}
return {
afterSubmit: afterSubmit
};
});
Try rearranging the first function signature to function(email, render, record, file)
They are probably in the wrong order.