The requirement is to capture the keywords from the user input given in chat window and make a web api call to get a file link.
I have four different categories into which the user input query can be classified:
--Operating Group
--Technology
--Geography
--Themes
I have configured a LUIS intent and listed these four categories as entitites. However, the issue now is that the entity list cannot be predefined since there can be any number
of search keywords which can be passed to web api. I am now confused if there is any other way round for this requirement such as removing the stop words and passing the list of keywords
Web API.
Code :
[LuisIntent("Credentials")]
public async Task Credentials(IDialogContext context, LuisResult result)
{
try
{
if (result.Entities.Count() == 0)
{
if ((result.Query.ToString().ToLower() == "geo" || result.Query.ToString().ToLower() == "operating group" || result.Query.ToString().ToLower() == "technology" || result.Query.ToString().ToLower() == "Themes"))
{
}
else
{
await context.Forward(new QnABotFeedbackDialog(updateQna, result.Query, rotationTemStorage, qnaInvalidMessageCount), AfterCredentialDialog, context.Activity, CancellationToken.None);
}
}
else if (result.Entities.Count() > 0)
{
string efilterType = string.Empty;
if (result.Entities.Count() > 0)
{
foreach (var i in result.Entities)
{
if (efilterType == string.Empty)
{
efilterType = i.Entity;
}
else
{
efilterType = efilterType + "," + i.Entity;
}
}
}
await CredentialsPersonalisation(context, efilterType);
}
}
catch (Exception ex)
{
await context.PostAsync(ex.Message);
}
}
However, we do not have a fixed set of keywords which we could
pre-configure in Entity lists.
I think you misunderstood what an entity is.
Simple entities are not pre-configured lists, it learns from your utterances and for the calls after. So it's basically what you want. So you have to create your three entities as simple, then add utterances and tag the entities in those utterances. Do not use always the same value for an entity.
For example, add the following utterances:
give me the file for fs in North America region on RPA
And tag fs as OperationGroup entity, North America as Geography entity, and RPA as Technology entity
Can I have the file for PRD in Europe about LUIS?
And tag PRD as OperationGroup entity, Europe as Geography entity, and LUIS as Technology entity
Sidenote: if you have fixed lists, which is not the case here, you must create an entity of type List:
Related
Can somebody help me interpret what the heck this means from the bot framework documention:
You can also pass in LUIS entities to bind to the state. If the EntityRecommendation.Type is a path to a field in your C# class then the EntityRecommendation.Entity will be passed through the recognizer to bind to your field. Just like initial state, any step for filling in that field will be skipped.
When I call my dialog I pass in my LuisResult result Entities collection like so:
context.Call(new FormDialog<ItemSearch>( new ItemSearch(), ItemSearch.BuildForm, options: FormOptions.PromptInStart,entities:result.Entities), null);
Within those entities is at least one which maps in both name and type to a public property on my dialog however the state never gets filled. What am I missing?
TIA.
You can find an example of this in the PizzaOrderDialog. if you look at FormDialog implementation, it is using the entity.type to map the passed in entity recommendation to a step in the form. Then the detected entities will be provided as an input to that step of the form.
Here is an example of how form can skip the kind step based on the detected entities by Luis model in pizza form:
var entities = new List<EntityRecommendation>(result.Entities);
if (!entities.Any((entity) => entity.Type == "Kind"))
{
// Infer kind
foreach (var entity in result.Entities)
{
string kind = null;
switch (entity.Type)
{
case "Signature": kind = "Signature"; break;
case "GourmetDelite": kind = "Gourmet delite"; break;
case "Stuffed": kind = "stuffed"; break;
default:
if (entity.Type.StartsWith("BYO")) kind = "byo";
break;
}
if (kind != null)
{
entities.Add(new EntityRecommendation(type: "Kind") { Entity = kind });
break;
}
}
}
var pizzaForm = new FormDialog<PizzaOrder>(new PizzaOrder(), this.MakePizzaForm, FormOptions.PromptInStart, entities);
It also appears that there is an issue with passing Entities in. It seems to work if the property you are mapping to is a Enum (as per the PizzaBot sample). However if the public property is a string, it doesn't map. I'm not sure about other types.
See here https://github.com/Microsoft/BotBuilder/issues/151
I want to implement function edit and add contact programatically in windows phone 10.
Is it possible? Has any sample about it ?
Here is a code snippet for creating the contact:
public async Task AddContact(String FirstName, String LastName)
{
var contact = new Windows.ApplicationModel.Contacts.Contact();
contact.FirstName = FirstName;
contact.LastName = LastName;
//Here you can set other properties...
//Get he contact store for the app (so no lists from outlook and other stuff will be in the returned lists..)
var contactstore = await Windows.ApplicationModel.Contacts.ContactManager.RequestStoreAsync(Windows.ApplicationModel.Contacts.ContactStoreAccessType.AppContactsReadWrite);
try
{
var contactLists = await contactstore.FindContactListsAsync();
Windows.ApplicationModel.Contacts.ContactList contactList;
//if there is no contact list we create one
if (contactLists.Count == 0)
{
contactList = await contactstore.CreateContactListAsync("MyList");
}
//otherwise if there is one then we reuse it
else
{
contactList = contactLists.FirstOrDefault();
}
await contactList.SaveContactAsync(contact);
}
catch
{
//Handle it properly...
}
}
And here is a short sample for changing an existing contact:
//you can obviusly couple the changes better then this... this is just to show the basics
public async Task ChangeContact(Windows.ApplicationModel.Contacts.Contact ContactToChange, String NewFirstName, String NewLastName)
{
var contactStore = await Windows.ApplicationModel.Contacts.ContactManager.RequestStoreAsync(Windows.ApplicationModel.Contacts.ContactStoreAccessType.AppContactsReadWrite);
var contactList = await contactStore.GetContactListAsync(ContactToChange.ContactListId);
var contact = await contactList.GetContactAsync(ContactToChange.Id);
contact.FirstName = NewFirstName;
contact.LastName = NewLastName;
await contactList.SaveContactAsync(contact);
}
And very important:
In the appxmanifest you have to add the contacts capability. Right click to it in the solution explorer and "View Code" and then under Capabilities put
<uap:Capability Name="contacts" />
There is no UI for this. See this.
Both samples are meant to be for starting point... obviously it's not production ready and you have to adapt it to your scenario.
Update
Since this came up in the comments I extend my answer a little bit.
Based on this (plus my own experimentation) the ContactListId for aggregated contacts is null (which makes sense if you think about it). Here is how to get the raw contact with ContactlLstId (code is based on the comment from the link)
public async Task IterateThroughContactsForContactListId()
{
ContactStore allAccessStore = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AllContactsReadOnly);
var contacts = await allAccessStore.FindContactsAsync();
foreach (var contact in contacts)
{
//process aggregated contacts
if (contact.IsAggregate)
{
//here contact.ContactListId is "" (null....)
//in this case if you need the the ContactListId then you need to iterate through the raw contacts
var rawContacts = await allAccessStore.AggregateContactManager.FindRawContactsAsync(contact);
foreach (var rawContact in rawContacts)
{
//Here you should have ContactListId
Debug.WriteLine($"aggregated, name: {rawContact.DisplayName }, ContactListId: {rawContact.ContactListId}");
}
}
else //not aggregated contacts should work
{
Debug.WriteLine($"not aggregated, name: {contact.DisplayName }, ContactListId: {contact.ContactListId}");
}
}
}
And another important thing:
According to the documentation you won’t be able to change all the contacts which are created by other apps.
AllContactsReadWrite:
Read and write access to all app and system contacts. This value is
not available to all apps. Your developer account must be specially
provisioned by Microsoft in order to request this level of access.
In some cases, I get a System.UnauthorizedAccessException when SaveContactAsync(contact) is called. One example for this was when the contact was in the Skype Contact List.
I'm working with the OOB blog sites in SP2010. I'm using SPMetal to generate entity classes for the Posts list (among others). I've used a parameters.xml file to get the other columns that I need that aren't included by default.
One of the things that I want to do is to get the users' My Site url. I am able to do this with CAML relatively easily. However I need to do it using Linq. I can't figure out how to get the login id (i.e. domain\id) for the Author Field. I've looked through the Contact content type and it doesn't appear to have anything to help.
Has anyone run across this or gotten the login id for a user with SPMetal?
if you create Entity of Posts list using SPMetel.exe and if in Posts list having Suppose Field Type is User than automatically return two methods of like LookupId and LookupValue.
In my case : I have take promoterid As a Field name in Posts list in in my Entity having two method
private System.Nullable<int> _promoterId;
private string _promoter;
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="promoterid", Storage="_promoterId", FieldType="User", IsLookupId=true)]
public System.Nullable<int> PromoterId {
get {
return this._promoterId;
}
set {
if ((value != this._promoterId)) {
this.OnPropertyChanging("PromoterId", this._promoterId);
this._promoterId = value;
this.OnPropertyChanged("PromoterId");
}
}
}
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="promoterid", Storage="_promoter", ReadOnly=true, FieldType="User", IsLookupValue=true)]
public string Promoter {
get {
return this._promoter;
}
set {
if ((value != this._promoter)) {
this.OnPropertyChanging("Promoter", this._promoter);
this._promoter = value;
this.OnPropertyChanged("Promoter");
}
}
}
than after i can able to use using linq query
i.e
SPWeb oWebsiteRoot = SPContext.Current.Web;
EntitiesDataContext objent = new EntitiesDataContext(oWebsiteRoot.Url);
EntityList<PostsItem> evnitems = objent.GetList<PostsItem>("Posts");
var i = from item in evnitems
where item.PromoterId == SPContext.Current.Web.CurrentUser.ID
select item;
I'm trying to project parts of a Display and its list of locations from a WCF Data service into a custom type. Is this doable in WCF Data Services in a Silverlight client? There is some help here, but it doesn't show getting a list back as well as simple strings.
Currently I'm getting "NotSupportedException: Constructing or initializing instances of the type UserQuery+Info with the expression d.Base.Title is not supported.".
It would be a bonus if you could tell me how to do Expand on Locations in this syntax (I know about Displays.Expand("Locations")) or if I need it.
LINQPad snippet
var displays = from d in Displays.Where(d => d.Id == 3136)
select new Info
{
Name = d.Base.Title,
};
displays.Dump();
}
public class Info
{
private string name;
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
public IEnumerable<Location> locations;
public IEnumerable<Location> Locations
{
get{ return this.locations;}
set{ this.locations = value;}
}
The problem is that you are effectively asking your WCF server to construct some type it has no knowledge about. Since it is unable to do so, you have to it yourself on your computer:
Displays
.Where(d => d.Id == 3136)
.AsEnumerable()
.Select(d => new Info { Name = d.Base.Title })
This will run the Where() on the server, but the Select() on your computer.
As already noted by svick you can't ask the server for types it doesn't understand (at least not using OData that is). But you can still only ask for properties you want and nothing more.
Since I don't have your service available the below sample uses the demo service on odata.org:
DemoService ctx = new DemoService(new Uri("http://services.odata.org/OData/OData.svc/"));
var q =
ctx.Products
.Where(p => p.ID == 1)
.Select(p =>
new Product
{
Category = new Category
{
Name = p.Category.Name
}
});
var r =
q.AsEnumerable()
.Select(p =>
new
{
CategoryName = p.Category.Name
});
The first query "q" will run compoletely on server (except for creation of the client side objects) and it will only get the Name of the category (and metadata about all the entities in question). It will translate to URL like /Products(1)?$expand=Category&$select=Category/Name.
The second query starts with the AsEnumerable, which effectively executes the first query and then it just performs a simple transform into an anonymous type. This is done completely on the client (no server interaction).
I have a two related questions.
First:
I'm looking to do a full text search against a custom entity in Dynamics CRM 4.0. Has anyone done this before or know how to do it?
I know that I can build QueryExpressions with the web service and sdk but can I do a full text search with boolean type syntax using this method? As far as I can tell that won't do the trick.
Second:
Does anyone else feel limited with the searching abilities provided with Dynamics CRM 4.0? I know there are some 3rd pary search products out there but I haven't found one I like yet. Any suggestions would be appreciated.
Searching and filtering via the CRM SDK does take some time to get used to. In order to simulate full text search, you need to use nested FilterExpressions as your QueryExpression.Criteria. SDK page for nested filters The hardest part is figuring out how to build the parent child relationships. There's so much boolean logic going on that it's easy to get lost.
I had a requirement to build a "search engine" for one of our custom entities. Using this method for a complex search string ("one AND two OR three") with multiple searchable attributes was ugly. If you're interested though, I can dig it up. While it's not really supported, if you can access the database directly, I would suggest using SQL's full text search capabilities.
--
ok, here you go. I don't think you'll be able to copy paste this and fulfill your needs. my customer was only doing two to three key word searches and they were happy with the results from this. You can see what a pain it is to just do this in a simple search scenario. I basically puked out code until it was 'working'.
private FilterExpression BuildFilterV2(string[] words, string[] seachAttributes)
{
FilterExpression filter = new FilterExpression();
List<FilterExpression> allchildfilters = new List<FilterExpression>();
List<string> andbucket = new List<string>();
List<string> orBucket = new List<string>();
// clean up commas, quotes, etc
words = ScrubWords(words);
int index = 0;
while (index < words.Length)
{
// if current word is 'and' then add the next wrod to the ad bucket
if (words[index].ToLower() == "and")
{
andbucket.Add(words[index + 1]);
index += 2;
}
else
{
if (andbucket.Count > 0)
{
List<FilterExpression> filters = new List<FilterExpression>();
foreach (string s in andbucket)
{
filters.Add(BuildSingleWordFilter(s, seachAttributes));
}
// send existing and bucket to condition builder
FilterExpression childFilter = new FilterExpression();
childFilter.FilterOperator = LogicalOperator.And;
childFilter.Filters = filters.ToArray();
// add to child filter list
allchildfilters.Add(childFilter);
//new 'and' bucket
andbucket = new List<string>();
}
if (index + 1 < words.Length && words[index + 1].ToLower() == "and")
{
andbucket.Add(words[index]);
if (index + 2 <= words.Length)
{
andbucket.Add(words[index + 2]);
}
index += 3;
}
else
{
orBucket.Add(words[index]);
index++;
}
}
}
if (andbucket.Count > 0)
{
List<FilterExpression> filters = new List<FilterExpression>();
foreach (string s in andbucket)
{
filters.Add(BuildSingleWordFilter(s, seachAttributes));
}
// send existing and bucket to condition builder
FilterExpression childFilter = new FilterExpression();
childFilter.FilterOperator = LogicalOperator.And;
childFilter.Filters = filters.ToArray();
// add to child filter list
allchildfilters.Add(childFilter);
//new 'and' bucket
andbucket = new List<string>();
}
if (orBucket.Count > 0)
{
filter.Conditions = BuildConditions(orBucket.ToArray(), seachAttributes);
}
filter.FilterOperator = LogicalOperator.Or;
filter.Filters = allchildfilters.ToArray();
return filter;
}
private FilterExpression BuildSingleWordFilter(string word, string[] seachAttributes)
{
List<ConditionExpression> conditions = new List<ConditionExpression>();
foreach (string attr in seachAttributes)
{
ConditionExpression expr = new ConditionExpression();
expr.AttributeName = attr;
expr.Operator = ConditionOperator.Like;
expr.Values = new string[] { "%" + word + "%" };
conditions.Add(expr);
}
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.Or;
filter.Conditions = conditions.ToArray();
return filter;
}
private ConditionExpression[] BuildConditions(string[] words, string[] seachAttributes)
{
List<ConditionExpression> conditions = new List<ConditionExpression>();
foreach (string s in words)
{
foreach (string attr in seachAttributes)
{
ConditionExpression expr = new ConditionExpression();
expr.AttributeName = attr;
expr.Operator = ConditionOperator.Like;
expr.Values = new string[] { "%" + s + "%" };
conditions.Add(expr);
}
}
return conditions.ToArray();
}
Hm, that's a pretty interesting scenario...
You could certainly do a 'Like' query, and 'or' together the colums/attribute conditions you want included in the search. This seems to be how CRM does queries from the box above entity lists (and they're plenty fast). It looks like the CRM database has a full-text index, although exactly which columns are used to populate it is a bit foggy to me after a brief peek.
And remember LinqtoCRM for CRM query love (I started the project, sorry about the shameless plug).
Second - I can recommend "Global Search" by Akvelon which provides ability to search in all Custom Entities and attributes and Out of Box entities and attributes. Also they are using FTS for search in the attached documents contents. You can find more details in their official site: http://www.akvelon.com/Products/Dynamics%20CRM%20global%20Search/default.aspx
I would suggest utilizing the Dynamics CRM filtered views provided for you in the database. Then you can utilize all the power of native SQL to do any LIKE's or other logic you need. Plus, the filtered views are security trimmed, so you won't have to worry about users accessing records they do not have permission to.