Making DialogFlow v2 DetectIntent Calls w/ C# (including input context) - c#

So I finally figured out a way to successfully make detect intent calls and provide an input context. My question is whether or not this is the CORRECT (or best) way to do it:
(And yes, I know you can just call DetectIntent(agent, session, query) but I have to provide a input context(s) depending on the request)
var query = new QueryInput
{
Text = new TextInput
{
Text = model.Content,
LanguageCode = string.IsNullOrEmpty(model.Language) ? "en-us" : model.Language,
}
};
var commonContext = new global::Google.Cloud.Dialogflow.V2.Context
{
ContextName = new ContextName(agent, model.sessionId, "my-input-context-data"),
LifespanCount = 3,
Parameters = new Struct
{
Fields = {
{ "Source", Value.ForString(model.Source) },
{ "UserId" , Value.ForString(model.UserId.ToString())},
{ "Name" , Value.ForString(model.FirstName)}
}
}
};
var request = new DetectIntentRequest
{
SessionAsSessionName = new SessionName(agent, model.sessionId),
QueryParams = new QueryParameters
{
GeoLocation = new LatLng {Latitude = model.Latitude, Longitude = model.Longitude},
TimeZone = model.TimeZone ?? "MST"
},
QueryInput = query
};
request.QueryParams.Contexts.Add(commonContext);
// ------------
var creds = GetGoogleCredentials("myCredentials.json");
var channel = new Grpc.Core.Channel(SessionsClient.DefaultEndpoint.Host, creds.ToChannelCredentials());
var client = SessionsClient.Create(channel);
var response = client.DetectIntent(request);
channel.ShutdownAsync();
return response;
Note: I included the explicit ShutDownAsync (it's not in an async call) because I was getting some file locking issues when attempting to re-deploy the WebAPI project (and only after having executed this code).
Thanks
Chris
Updated 4/25: The most basic way I use this is to integrate the user's name into intent responses:
It can also be read from within the webhook/inline fulfillment index.js:
const name = request.body.queryResult && request.body.queryResult.outputContexts && request.body.queryResult.outputContexts[0].parameters.Name

Related

Fetching secretvalue from CDK not working

I have stored an api key to invoke APigateway in secret manager. And I am trying to fetch that secret from cdk and attach to the rule's header parameter as given below
var secret = Amazon.CDK.AWS.SecretsManager.Secret.FromSecretAttributes(this, "SCMId", new Amazon.CDK.AWS.SecretsManager.SecretAttributes
{
SecretCompleteArn = apikeyArn
});
var apikey = secret.SecretValueFromJson("ApiKey").Resolve;
var httpParameters = new Amazon.CDK.AWS.Events.CfnRule.HttpParametersProperty { HeaderParameters = new Dictionary<string, string> { { "x-api-key", apikey.ToString() } } };
Then the event target with above http parameter
var eventRule = new Amazon.CDK.AWS.Events.CfnRule(this, ruleId, new Amazon.CDK.AWS.Events.CfnRuleProps
{
EventBusName = busName,
Name = ruleName,
Description = description,
EventPattern = eventPattern,
Targets = new[]
{
new Amazon.CDK.AWS.Events.CfnRule.TargetProperty
{
Id = id,
Arn = apiArn,
HttpParameters = httpParameters,
RoleArn = roleArn,
}
}
});
Still the api key is not working and I am getting 403 error when that particular event trying to invoke api.

Microsoft Teams bot - link unfurling auth flow

Can't find good example of auth flow for link unfurling. I managed to run oauth flow using this example. But after user provided login and password and bot hits OnTeamsAppBasedLinkQueryAsync second time GetUserTokenAsync still returns null. So I don't follow where should I get then token from when auth flow is finished. Should I persist it somehow? Will Teams send me the token on every request or how it should work?
So in my case following code always returns null:
var tokenResponse = await (turnContext.Adapter as IUserTokenProvider)
.GetUserTokenAsync(turnContext, _connectionName, default(string),
cancellationToken: cancellationToken);
It seems the 'state' field is not present on AppBasedLinkQuery. When the auth flow completes, OnTeamsAppBasedLinkQueryAsync will be called again and the turnContext.Activity.Value will contain the url and the 'state' (or magic code). We will get this field added to AppBasedLinkQuery (created an issue here: microsoft/botbuilder-dotnet#3429 ).
A workaround is to retrieve the state/magiccode directly from the Activity.Value Something like:
protected async override Task<MessagingExtensionResponse> OnTeamsAppBasedLinkQueryAsync(ITurnContext<IInvokeActivity> turnContext, AppBasedLinkQuery query, CancellationToken cancellationToken)
{
var magicCode = string.Empty;
var state = (turnContext.Activity.Value as Newtonsoft.Json.Linq.JObject).Value<string>("state");
if (!string.IsNullOrEmpty(state))
{
int parsed = 0;
if (int.TryParse(state, out parsed))
{
magicCode = parsed.ToString();
}
}
var tokenResponse = await(turnContext.Adapter as IUserTokenProvider).GetUserTokenAsync(turnContext, _connectionName, magicCode, cancellationToken: cancellationToken);
if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.Token))
{
// There is no token, so the user has not signed in yet.
// Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions
var signInLink = await(turnContext.Adapter as IUserTokenProvider).GetOauthSignInLinkAsync(turnContext, _connectionName, cancellationToken);
return new MessagingExtensionResponse
{
ComposeExtension = new MessagingExtensionResult
{
Type = "auth",
SuggestedActions = new MessagingExtensionSuggestedAction
{
Actions = new List<CardAction>
{
new CardAction
{
Type = ActionTypes.OpenUrl,
Value = signInLink,
Title = "Bot Service OAuth",
},
},
},
},
};
}
var heroCard = new ThumbnailCard
{
Title = "Thumbnail Card",
Text = query.Url,
Images = new List<CardImage> { new CardImage("https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png") },
};
var attachments = new MessagingExtensionAttachment(HeroCard.ContentType, null, heroCard);
var result = new MessagingExtensionResult("list", "result", new[] { attachments });
return new MessagingExtensionResponse(result);
}

Consume and Configure Graphql request from .Net C# console application client

I'm trying to consume a Graphql Api from a C# client. For that I'm using the GraphQl.Net Nuget package. The problem is that, I have no idea how to set the Api Url as I don't have HttpRequest object and this results also with additional problems that I can't set the authentcation header and send the token with the request. My code looks like:
public void Post(TestGraphQl.GraphQLQuery query)
{
var inputs = query.Variables.ToInputs();
var queryToExecute = query.Query;
var result = _executer.ExecuteAsync(_ =>
{
_.Schema = _schema;
_.Query = queryToExecute;
_.OperationName = query.OperationName;
_.Inputs = inputs;
//_.ComplexityConfiguration = new ComplexityConfiguration { MaxDepth = 15 };
_.FieldMiddleware.Use<InstrumentFieldsMiddleware>();
}).Result;
var httpResult = result.Errors?.Count > 0
? HttpStatusCode.BadRequest
: HttpStatusCode.OK;
var json = _writer.Write(result);
}
And the caller looks like this:
var jObject = new Newtonsoft.Json.Linq.JObject();
jObject.Add("id", deviceId);
client.Post(new GraphQLQuery { Query = "query($id: String) { device (id: $id) { displayName, id } }", Variables = jObject });
I'm totally new to this topic and appreciate any help. Many thanks!!
This worked out for me. You will need the GraphQL.Client Package. My_class is the class for the deserialization.
var client = new GraphQLHttpClient(Api_Url, new NewtonsoftJsonSerializer());
var request = new GraphQLRequest
{
Query = {query}
};
var response = await client.SendQueryAsync<my_class>(request);
Not sure if you are still looking for it. One can always use GraphQl.Client nuget to achieve this. Sample code to consume is
var query = #"query($id: String) { device (id: $id) { displayName, id } }";
var request = new GraphQLRequest(){
Query = query,
Variables = new {id =123}
};
var graphQLClient = new GraphQLClient("http://localhost:8080/api/GraphQL");
graphQLClient.DefaultRequestHeaders.Add("Authorization", "yourtoken");
var graphQLResponse = await graphQLClient.PostAsync(request);
Console.WriteLine(graphQLResponse.Data);

Smart Encapsulation from similar objects

I have a few Soap-requests that all start the same:
First request:
var client = new Conn.Team.z_proj_team_spQueryPortClient();
client.Endpoint.Address = EndPoint;
var query = new Conn.Team.z_proj_team_spQuery
{
Filter = new Conn.Team.z_proj_team_spFilter
{
param_code = projectCode
}
};
var auth = new Conn.Team.Auth { Username = _username, Password = _password };
var records = client.Query(auth, query).Records;
second request:
var client = new Conn.Task.z_proj_Task_spQueryPortClient();
client.Endpoint.Address = EndPoint;
var query = new Conn.Task.z_proj_Task_spQuery
{
Filter = new Conn.Task.z_proj_Task_spFilter
{
param_code = projectCode
}
};
var auth = new Conn.Task.Auth { Username = _username, Password = _password };
var records = client.Query(auth, query).Records;
As you can see, the code looks nearly the same, but these are completely different objects (that do not share a base class) but who use the same property-names.
Because I have about 10 of these calls, is there a good way to wrap these functions? Would you even advice to do so or would Reflection simple makes it "more evil"?
(BTW:) I am unsure what a good tag would be for my problem. Feel free to change them to better ones
Solved this the following "reflection/dynamic" way. Feel free to post a better solution if you have one.
private object Connect(Type clientType, Type queryType, Type filterType, Type authType, string code)
{
dynamic client = Activator.CreateInstance(clientType);
client.Endpoint.Address = EndPoint;
dynamic query = Activator.CreateInstance(queryType);
dynamic filter = Activator.CreateInstance(filterType);
filter.param_code = code;
query.Filter = filter;
dynamic auth = Activator.CreateInstance(authType);
auth.Username = _username;
auth.Password = _password;
return client.Query(auth, query).Records;
}

Xamarin: Using HttpClient POST in combination with a dynamic Class

I have some services that require rather complex objects. Every service uses almost the same base object but it needs to be extended for each service.
A simple example:
The Standard Object would be something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
}
}
}
and for my service I need to add some properties under params,
something like:
ContextObject {
params {
Device {
Name: "MyMobileDevice",
ID: 123455691919238
},
requested_employee_id: 112929
}
}
I tried to get this by using JObject and got it working so far but now I cant find a proper example on how to send this object to my server using HttpClient.
Edit:
Here is my full JObject which all Requests need:
public static JObject DefaultContext (string ServiceMethod) {
var Context = new JObject();
Context["version"] = "1.1";
Context["method"] = ServiceMethod;
Context["params"] = JObject.FromObject( new {
Context = JObject.FromObject( new {
User = App.UserSettings.USERNAME,
Password = App.UserSettings.PASSWORD,
SerialNumber = "1234567890", // TODO: use generated id
Locale = "de-DE",
Timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffzzz"),
Device = JObject.FromObject( new {
DeviceType = "phone",
ProductType = "D6603", // TODO: Get from Device-Info
screen = JObject.FromObject( new {
Density = "xxhdpi", // TODO: Get from Device-Info
resolution = JObject.FromObject( new {
Height = "1920", // TODO: Get from Device-Info
Width = "1080" // TODO: Get from Device-Info
})
}),
version = JObject.FromObject( new {
AppVersion = "myAppVersion", // TODO: Get App-Information LayoutVersion = "1.0"
} )
})
})
});
return mobileContext;
}
For my Requests I need to add parameters under the "params"-Node. Which works with:
mobileContext["params"]["mynewparameter"] = "FOO";
Now I wanted to send this JObject via System.Net.Http-Client to my server with something like this:
var client = new HttpClient ();
client.BaseAddress = new Uri (App.UserSettings.HOST + ":" + App.UserSettings.PORT + App.UserSettings.TYPE);
client.Timeout = 3000;
var context = MyContext.DefaultContext (ServiceMethods.CUSTOMER_LIST_METHOD);
context ["params"] ["myrequestparam"] = "FOO";
var jsonString = JsonConvert.SerializeObject (context);
var responseData = await client.Get???????
Is my general approach correct? How would you do it? Is there a sample on how to handle such dynamic stuff?
I couldn't find a example on how to use httpclient correctly with the Newtonsoft.JSON-Library how far am I from actually working code?

Categories