Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 10db623

Browse files
authored
Support closed list as instanceOf entity in V6 schema (#708)
1 parent 53efd62 commit 10db623

File tree

4 files changed

+340
-3
lines changed

4 files changed

+340
-3
lines changed

packages/lu/src/parser/luis/luisGenBuilder.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ const buildVersion6 = function(luisApp) {
4040
let result = new LuisGen()
4141
try {
4242
result.intents = processIntents(luisApp.intents);
43-
[result.entities, result.composites] = extractEntitiesV6(luisApp.entities);
44-
result.prebuiltEntities = extractEntities(luisApp.prebuiltEntities, true);
4543
result.closedLists = extractEntities(luisApp.closedLists);
44+
[result.entities, result.composites] = extractEntitiesV6(luisApp.entities, result.closedLists);
45+
result.prebuiltEntities = extractEntities(luisApp.prebuiltEntities, true);
4646
result.regex_entities = extractEntities(luisApp.regex_entities);
4747
result.patternAnyEntities = extractEntities(luisApp.patternAnyEntities);
4848
} catch (err) {
@@ -99,13 +99,19 @@ const extractEntities = function(entities, builtIn = false) {
9999
return result;
100100
}
101101

102-
const extractEntitiesV6 = function(entities) {
102+
const extractEntitiesV6 = function(entities, closedLists) {
103103
// This method provides a simplified topological sort to
104104
// solve potential instanceOf dependecies in the v6 entities
105105

106106
const simpleEntitiesResult = [];
107107
const compositeEntitiesResult = [];
108108
const simpleEntitiesWithType = {};
109+
110+
// Add 'closedList' entities as valid types for instanceOf
111+
closedLists.forEach(listEntity => {
112+
simpleEntitiesWithType[listEntity] = 'list'
113+
});
114+
109115
const resolveEntityType = function(entityName) {
110116
const entityStack = [];
111117
let entityType = simpleEntitiesWithType[entityName];

packages/luis/test/commands/luis/generate/cs.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,15 @@ describe('luis:generate:cs', () => {
151151
.it('Generates class based on luis schema v6 correctly', async () => {
152152
await compareSourceFiles('../../../fixtures/generate/SchemaV6.cs', '../../../fixtures/generate/results/SchemaV6.cs')
153153
})
154+
155+
test
156+
.stdout()
157+
.command(['luis:generate:cs',
158+
'--in',
159+
`${path.join(__dirname, '../../../fixtures/generate/V6AnyEntityAsInstanceOf.json')}`,
160+
'--out',
161+
`${path.join(__dirname, '../../../fixtures/generate/results/V6AnyEntityAsInstanceOf.cs')}`])
162+
.it('Generates class based on V6 with entity instanceOf referencing a closedList', async () => {
163+
await compareSourceFiles('../../../fixtures/generate/V6AnyEntityAsInstanceOf.cs', '../../../fixtures/generate/results/V6AnyEntityAsInstanceOf.cs')
164+
})
154165
})
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// <auto-generated>
2+
// Code generated by luis:generate:cs
3+
// Tool github: https://github.com/microsoft/botframework-cli
4+
// Changes may cause incorrect behavior and will be lost if the code is
5+
// regenerated.
6+
// </auto-generated>
7+
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Serialization;
9+
using System;
10+
using System.Collections.Generic;
11+
using Microsoft.Bot.Builder;
12+
using Microsoft.Bot.Builder.AI.Luis;
13+
namespace Luis
14+
{
15+
public partial class MusicSkill: IRecognizerConvert
16+
{
17+
[JsonProperty("text")]
18+
public string Text;
19+
20+
[JsonProperty("alteredText")]
21+
public string AlteredText;
22+
23+
public enum Intent {
24+
PlayMusic
25+
};
26+
[JsonProperty("intents")]
27+
public Dictionary<Intent, IntentScore> Intents;
28+
29+
public class _Entities
30+
{
31+
// Lists
32+
public string[][] GenreList;
33+
34+
35+
// Composites
36+
public class _InstanceMusicParent
37+
{
38+
public InstanceData[] beforeMusic;
39+
public InstanceData[] afterMusic;
40+
public InstanceData[] music;
41+
public InstanceData[] inBetweenMusic;
42+
public InstanceData[] genre;
43+
}
44+
public class MusicParentClass
45+
{
46+
public string[] beforeMusic;
47+
public string[] afterMusic;
48+
public string[] music;
49+
public string[] inBetweenMusic;
50+
public string[][] genre;
51+
[JsonProperty("$instance")]
52+
public _InstanceMusicParent _instance;
53+
}
54+
public MusicParentClass[] MusicParent;
55+
56+
// Instance
57+
public class _Instance
58+
{
59+
public InstanceData[] GenreList;
60+
public InstanceData[] MusicParent;
61+
public InstanceData[] afterMusic;
62+
public InstanceData[] beforeMusic;
63+
public InstanceData[] genre;
64+
public InstanceData[] inBetweenMusic;
65+
public InstanceData[] music;
66+
}
67+
[JsonProperty("$instance")]
68+
public _Instance _instance;
69+
}
70+
[JsonProperty("entities")]
71+
public _Entities Entities;
72+
73+
[JsonExtensionData(ReadData = true, WriteData = true)]
74+
public IDictionary<string, object> Properties {get; set; }
75+
76+
public void Convert(dynamic result)
77+
{
78+
var app = JsonConvert.DeserializeObject<MusicSkill>(
79+
JsonConvert.SerializeObject(
80+
result,
81+
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Error = OnError }
82+
)
83+
);
84+
Text = app.Text;
85+
AlteredText = app.AlteredText;
86+
Intents = app.Intents;
87+
Entities = app.Entities;
88+
Properties = app.Properties;
89+
}
90+
91+
private static void OnError(object sender, ErrorEventArgs args)
92+
{
93+
// If needed, put your custom error logic here
94+
Console.WriteLine(args.ErrorContext.Error.Message);
95+
args.ErrorContext.Handled = true;
96+
}
97+
98+
public (Intent intent, double score) TopIntent()
99+
{
100+
Intent maxIntent = Intent.None;
101+
var max = 0.0;
102+
foreach (var entry in Intents)
103+
{
104+
if (entry.Value.Score > max)
105+
{
106+
maxIntent = entry.Key;
107+
max = entry.Value.Score.Value;
108+
}
109+
}
110+
return (maxIntent, max);
111+
}
112+
}
113+
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
{
2+
"intents": [
3+
{
4+
"name": "PlayMusic"
5+
}
6+
],
7+
"entities": [
8+
{
9+
"name": "MusicParent",
10+
"roles": [],
11+
"children": [
12+
{
13+
"name": "beforeMusic",
14+
"instanceOf": null,
15+
"children": []
16+
},
17+
{
18+
"name": "afterMusic",
19+
"instanceOf": null,
20+
"children": []
21+
},
22+
{
23+
"name": "music",
24+
"instanceOf": null,
25+
"children": []
26+
},
27+
{
28+
"name": "inBetweenMusic",
29+
"instanceOf": null,
30+
"children": []
31+
},
32+
{
33+
"name": "genre",
34+
"instanceOf": "GenreList",
35+
"children": []
36+
}
37+
]
38+
}
39+
],
40+
"composites": [],
41+
"closedLists": [
42+
{
43+
"name": "GenreList",
44+
"subLists": [
45+
{
46+
"canonicalForm": "genre_list",
47+
"list": [
48+
"schlager",
49+
"deathrash metal",
50+
"boi",
51+
"drill music"
52+
]
53+
}
54+
],
55+
"roles": []
56+
}
57+
],
58+
"regex_entities": [],
59+
"regex_features": [],
60+
"utterances": [
61+
{
62+
"text": "play adeles latest album",
63+
"intent": "PlayMusic",
64+
"entities": [
65+
{
66+
"entity": "beforeMusic",
67+
"startPos": 0,
68+
"endPos": 3
69+
},
70+
{
71+
"entity": "music",
72+
"startPos": 5,
73+
"endPos": 10
74+
},
75+
{
76+
"entity": "afterMusic",
77+
"startPos": 12,
78+
"endPos": 23
79+
},
80+
{
81+
"entity": "MusicParent",
82+
"startPos": 0,
83+
"endPos": 23
84+
}
85+
]
86+
},
87+
{
88+
"text": "play prince",
89+
"intent": "PlayMusic",
90+
"entities": [
91+
{
92+
"entity": "beforeMusic",
93+
"startPos": 0,
94+
"endPos": 3
95+
},
96+
{
97+
"entity": "music",
98+
"startPos": 5,
99+
"endPos": 10
100+
},
101+
{
102+
"entity": "MusicParent",
103+
"startPos": 0,
104+
"endPos": 10
105+
}
106+
]
107+
},
108+
{
109+
"text": "play schlager",
110+
"intent": "PlayMusic",
111+
"entities": [
112+
{
113+
"entity": "beforeMusic",
114+
"startPos": 0,
115+
"endPos": 3
116+
},
117+
{
118+
"entity": "genre",
119+
"startPos": 5,
120+
"endPos": 12
121+
},
122+
{
123+
"entity": "MusicParent",
124+
"startPos": 0,
125+
"endPos": 12
126+
}
127+
]
128+
},
129+
{
130+
"text": "can you play rihanna please?",
131+
"intent": "PlayMusic",
132+
"entities": [
133+
{
134+
"entity": "beforeMusic",
135+
"startPos": 0,
136+
"endPos": 11
137+
},
138+
{
139+
"entity": "inBetweenMusic",
140+
"startPos": 13,
141+
"endPos": 19
142+
},
143+
{
144+
"entity": "afterMusic",
145+
"startPos": 21,
146+
"endPos": 27
147+
},
148+
{
149+
"entity": "MusicParent",
150+
"startPos": 0,
151+
"endPos": 27
152+
}
153+
]
154+
},
155+
{
156+
"text": "can you play boi",
157+
"intent": "PlayMusic",
158+
"entities": [
159+
{
160+
"entity": "beforeMusic",
161+
"startPos": 0,
162+
"endPos": 11
163+
},
164+
{
165+
"entity": "genre",
166+
"startPos": 13,
167+
"endPos": 15
168+
},
169+
{
170+
"entity": "MusicParent",
171+
"startPos": 0,
172+
"endPos": 15
173+
}
174+
]
175+
},
176+
{
177+
"text": "can you play crazy beautiful",
178+
"intent": "PlayMusic",
179+
"entities": [
180+
{
181+
"entity": "beforeMusic",
182+
"startPos": 0,
183+
"endPos": 11
184+
},
185+
{
186+
"entity": "music",
187+
"startPos": 13,
188+
"endPos": 27
189+
},
190+
{
191+
"entity": "MusicParent",
192+
"startPos": 0,
193+
"endPos": 27
194+
}
195+
]
196+
}
197+
],
198+
"patterns": [],
199+
"patternAnyEntities": [],
200+
"prebuiltEntities": [],
201+
"luis_schema_version": "6.0.0",
202+
"versionId": "0.1",
203+
"name": "MusicSkill",
204+
"desc": "",
205+
"culture": "en-us",
206+
"phraselists": []
207+
}

0 commit comments

Comments
 (0)