@miso.ai/client-sdk-ui 1.10.3 → 1.11.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/actor/autocomplete.js +4 -1
- package/dist/cjs/actor/data.js +15 -6
- package/dist/cjs/actor/fields.js +10 -10
- package/dist/cjs/actor/filters.js +114 -0
- package/dist/cjs/actor/hub.js +2 -1
- package/dist/cjs/actor/sessions.js +3 -5
- package/dist/cjs/actor/view.js +19 -6
- package/dist/cjs/actor/views.js +32 -19
- package/dist/cjs/constants.js +9 -2
- package/dist/cjs/defaults/ask/constants.js +3 -2
- package/dist/cjs/defaults/ask/templates.js +112 -219
- package/dist/cjs/defaults/common/templates.js +234 -0
- package/dist/cjs/defaults/hybrid-search/answer-box.js +115 -0
- package/dist/cjs/defaults/hybrid-search/constants.js +8 -0
- package/dist/cjs/defaults/hybrid-search/controls.js +17 -0
- package/dist/cjs/defaults/hybrid-search/index.js +31 -0
- package/dist/cjs/defaults/hybrid-search/phrases.js +27 -0
- package/dist/cjs/defaults/hybrid-search/templates.js +127 -0
- package/dist/cjs/defaults/index.js +4 -2
- package/dist/cjs/element/container/index.js +7 -0
- package/dist/cjs/element/container/miso-hybrid-search.js +21 -0
- package/dist/cjs/element/role/index.js +21 -0
- package/dist/cjs/element/role/miso-facets.js +20 -0
- package/dist/cjs/element/role/miso-hits.js +20 -0
- package/dist/cjs/element/role/miso-keywords.js +20 -0
- package/dist/cjs/layout/index.js +7 -0
- package/dist/cjs/layout/input/facets.js +294 -0
- package/dist/cjs/layout/input/option-list.js +4 -4
- package/dist/cjs/layout/input/search-box.js +6 -8
- package/dist/cjs/layout/list/collection.js +1 -2
- package/dist/cjs/layout/radio/radio.js +1 -1
- package/dist/cjs/layout/raf.js +1 -0
- package/dist/cjs/layout/template.js +3 -1
- package/dist/cjs/layout/templates.js +15 -0
- package/dist/cjs/layout/text/text.js +38 -5
- package/dist/cjs/layout/trackable.js +2 -16
- package/dist/cjs/plugin.js +4 -1
- package/dist/cjs/{source/index.js → source.js} +7 -4
- package/dist/cjs/util/bindings.js +3 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +335 -0
- package/dist/cjs/workflow/ask.js +98 -271
- package/dist/cjs/workflow/base.js +69 -35
- package/dist/cjs/workflow/explore.js +10 -0
- package/dist/cjs/workflow/hybrid-search.js +140 -0
- package/dist/cjs/workflow/index.js +7 -0
- package/dist/cjs/workflow/processors.js +113 -0
- package/dist/cjs/workflow/recommendation.js +12 -3
- package/dist/cjs/workflow/search.js +34 -12
- package/package.json +2 -2
- package/src/actor/autocomplete.js +4 -2
- package/src/actor/data.js +8 -2
- package/src/actor/fields.js +10 -10
- package/src/actor/filters.js +103 -0
- package/src/actor/hub.js +2 -1
- package/src/actor/sessions.js +3 -4
- package/src/actor/view.js +19 -2
- package/src/actor/views.js +30 -16
- package/src/constants.js +10 -0
- package/src/defaults/ask/constants.js +1 -0
- package/src/defaults/ask/templates.js +70 -179
- package/src/defaults/common/templates.js +173 -0
- package/src/defaults/hybrid-search/answer-box.js +118 -0
- package/src/defaults/hybrid-search/constants.js +2 -0
- package/src/defaults/hybrid-search/controls.js +11 -0
- package/src/defaults/hybrid-search/index.js +9 -0
- package/src/defaults/hybrid-search/phrases.js +22 -0
- package/src/defaults/hybrid-search/templates.js +83 -0
- package/src/defaults/index.js +2 -0
- package/src/element/container/index.js +1 -0
- package/src/element/container/miso-hybrid-search.js +19 -0
- package/src/element/role/index.js +3 -0
- package/src/element/role/miso-facets.js +16 -0
- package/src/element/role/miso-hits.js +16 -0
- package/src/element/role/miso-keywords.js +16 -0
- package/src/layout/index.js +1 -0
- package/src/layout/input/facets.js +242 -0
- package/src/layout/input/option-list.js +3 -4
- package/src/layout/input/search-box.js +6 -7
- package/src/layout/list/collection.js +1 -2
- package/src/layout/radio/radio.js +1 -1
- package/src/layout/raf.js +1 -0
- package/src/layout/template.js +2 -1
- package/src/layout/templates.js +15 -0
- package/src/layout/text/text.js +28 -3
- package/src/layout/trackable.js +2 -15
- package/src/plugin.js +6 -2
- package/src/{source/index.js → source.js} +7 -4
- package/src/util/bindings.js +4 -0
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +280 -0
- package/src/workflow/ask.js +82 -204
- package/src/workflow/base.js +64 -27
- package/src/workflow/explore.js +10 -1
- package/src/workflow/hybrid-search.js +125 -0
- package/src/workflow/index.js +1 -0
- package/src/workflow/processors.js +95 -0
- package/src/workflow/recommendation.js +9 -2
- package/src/workflow/search.js +35 -7
- package/dist/cjs/source/api.js +0 -23
- package/src/source/api.js +0 -12
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { trimObj, API } from '@miso.ai/commons';
|
|
2
|
+
import AnswerBasedWorkflow from './answer-based.js';
|
|
3
|
+
import { mergeApiOptions } from './options.js';
|
|
4
|
+
import { fields } from '../actor/index.js';
|
|
5
|
+
import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
6
|
+
import { ListLayout, TextLayout, FacetsLayout } from '../layout/index.js';
|
|
7
|
+
import { writeKeywordsToData, addDataInstructions } from './processors.js';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
10
|
+
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
|
|
11
|
+
name: API.NAME.SEARCH,
|
|
12
|
+
payload: {
|
|
13
|
+
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS.payload,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const DEFAULT_LAYOUTS = Object.freeze({
|
|
18
|
+
...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
|
|
19
|
+
[ROLE.PRODUCTS]: [ListLayout.type, { itemType: 'article' }],
|
|
20
|
+
[ROLE.KEYWORDS]: [TextLayout.type, { raw: true }],
|
|
21
|
+
[ROLE.HITS]: [TextLayout.type, { raw: true, format: 'number' }],
|
|
22
|
+
[ROLE.FACETS]: [FacetsLayout.type],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const DEFAULT_TRACKERS = Object.freeze({
|
|
26
|
+
...AnswerBasedWorkflow.DEFAULT_TRACKERS,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const DEFAULT_OPTIONS = Object.freeze({
|
|
30
|
+
...AnswerBasedWorkflow.DEFAULT_OPTIONS,
|
|
31
|
+
api: DEFAULT_API_OPTIONS,
|
|
32
|
+
layouts: DEFAULT_LAYOUTS,
|
|
33
|
+
trackers: DEFAULT_TRACKERS,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const ROLES_CONFIG = Object.freeze({
|
|
37
|
+
[ROLE.QUESTION]: {
|
|
38
|
+
mapping: ROLE.KEYWORDS,
|
|
39
|
+
},
|
|
40
|
+
[ROLE.FACETS]: {
|
|
41
|
+
mapping: 'facet_counts',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export default class HybridSearch extends AnswerBasedWorkflow {
|
|
46
|
+
|
|
47
|
+
constructor(plugin, client) {
|
|
48
|
+
super({
|
|
49
|
+
name: 'hybrid-search',
|
|
50
|
+
plugin,
|
|
51
|
+
client,
|
|
52
|
+
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
53
|
+
rolesConfig: ROLES_CONFIG,
|
|
54
|
+
defaults: DEFAULT_OPTIONS,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_initSubscriptions(args) {
|
|
59
|
+
super._initSubscriptions(args);
|
|
60
|
+
this._unsubscribes = [
|
|
61
|
+
...this._unsubscribes,
|
|
62
|
+
this._hub.on(fields.filters(), filters => this._refine(filters)),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// query //
|
|
67
|
+
_buildPayload({ q, qs, filters, ...payload } = {}) {
|
|
68
|
+
const fq = this._buildFq(filters); // TODO: combine with fq in payload?
|
|
69
|
+
return trimObj({
|
|
70
|
+
...payload,
|
|
71
|
+
q, // q, not question
|
|
72
|
+
fq,
|
|
73
|
+
_meta: {
|
|
74
|
+
...payload._meta,
|
|
75
|
+
question_source: qs || ORGANIC_QUESTION_SOURCE, // might be null, not undefined
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_buildFq(filters) {
|
|
81
|
+
if (!filters) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const clauses = [];
|
|
85
|
+
const { facets } = filters;
|
|
86
|
+
for (const field in facets) {
|
|
87
|
+
const values = facets[field];
|
|
88
|
+
if (!values || !values.length) {
|
|
89
|
+
continue; // just in case
|
|
90
|
+
}
|
|
91
|
+
clauses.push(`${field}:(${values.map(v => `"${v}"`).join(' OR ')})`);
|
|
92
|
+
}
|
|
93
|
+
return clauses.map(c => `(${c})`).join(' AND ');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_refine(filters) {
|
|
97
|
+
const query = this._hub.states[fields.query()];
|
|
98
|
+
const payload = this._buildPayload({ ...query, filters, answer: false });
|
|
99
|
+
const { session } = this;
|
|
100
|
+
|
|
101
|
+
const event = mergeApiOptions(this._options.resolved.api, { payload, session, _skipLoading: true });
|
|
102
|
+
this._request(event);
|
|
103
|
+
|
|
104
|
+
// emulate loading status exclusively for products
|
|
105
|
+
// TODO
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// data //
|
|
109
|
+
_defaultProcessData(data) {
|
|
110
|
+
data = super._defaultProcessData(data);
|
|
111
|
+
data = writeKeywordsToData(data);
|
|
112
|
+
data = instructPartialUpdates(data);
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function instructPartialUpdates(data) {
|
|
119
|
+
if (!data.value) {
|
|
120
|
+
return data;
|
|
121
|
+
}
|
|
122
|
+
return addDataInstructions(data, data.value.products ?
|
|
123
|
+
{ includes: [ ROLE.PRODUCTS, ROLE.HITS, ROLE.FACETS, ROLE.KEYWORDS, ROLE.QUESTION ], merge: true } :
|
|
124
|
+
{ excludes: [ ROLE.PRODUCTS, ROLE.HITS, ROLE.FACETS ], merge: true });
|
|
125
|
+
}
|
package/src/workflow/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as Asks } from './asks.js';
|
|
2
|
+
export { default as HybridSearch } from './hybrid-search.js';
|
|
2
3
|
export { default as Explore } from './explore.js';
|
|
3
4
|
export { default as Search } from './search.js';
|
|
4
5
|
export { default as Recommendations } from './recommendations.js';
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { trimObj } from '@miso.ai/commons';
|
|
2
|
+
import { STATUS } from '../constants.js';
|
|
3
|
+
|
|
4
|
+
export function writeDataStatus(data) {
|
|
5
|
+
const status = getStatus(data);
|
|
6
|
+
const ongoing = status === STATUS.READY ? !!data.ongoing : undefined;
|
|
7
|
+
return trimObj({ ...data, status, ongoing });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getStatus(data) {
|
|
11
|
+
if (!data) {
|
|
12
|
+
return STATUS.INITIAL;
|
|
13
|
+
}
|
|
14
|
+
const { request, error, value } = data;
|
|
15
|
+
return error ? STATUS.ERRONEOUS : value ? STATUS.READY : request ? STATUS.LOADING : STATUS.INITIAL;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function writeMisoIdToMeta(data) {
|
|
19
|
+
const { value } = data;
|
|
20
|
+
if (!value) {
|
|
21
|
+
return data;
|
|
22
|
+
}
|
|
23
|
+
const { miso_id } = value;
|
|
24
|
+
if (!miso_id) {
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
...data,
|
|
29
|
+
meta: {
|
|
30
|
+
...data.meta,
|
|
31
|
+
miso_id,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function writeKeywordsToData(data) {
|
|
37
|
+
const { request, value } = data;
|
|
38
|
+
if (!request || !value) {
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
const { payload } = request || {};
|
|
42
|
+
const { q: keywords } = payload || {};
|
|
43
|
+
if (!keywords) {
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
...data,
|
|
48
|
+
value: {
|
|
49
|
+
...value,
|
|
50
|
+
keywords,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function writeAnswerStageToMeta(data) {
|
|
56
|
+
const { value } = data;
|
|
57
|
+
if (!value) {
|
|
58
|
+
return data;
|
|
59
|
+
}
|
|
60
|
+
const { answer_stage } = value;
|
|
61
|
+
if (!answer_stage) {
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
// 1. put answer_stage to meta
|
|
65
|
+
// 2. mark ongoing flag
|
|
66
|
+
return {
|
|
67
|
+
...data,
|
|
68
|
+
ongoing: !value.finished,
|
|
69
|
+
meta: {
|
|
70
|
+
...data.meta,
|
|
71
|
+
answer_stage,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function addDataInstructions(data, instructions) {
|
|
77
|
+
if (!instructions) {
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
_inst: {
|
|
82
|
+
...data._inst,
|
|
83
|
+
...instructions,
|
|
84
|
+
},
|
|
85
|
+
...data,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function removeDataInstructions(data) {
|
|
90
|
+
if (typeof data !== 'object') {
|
|
91
|
+
return data;
|
|
92
|
+
}
|
|
93
|
+
const { _inst, ...rest } = data;
|
|
94
|
+
return rest;
|
|
95
|
+
}
|
|
@@ -35,12 +35,19 @@ export default class Recommendation extends Workflow {
|
|
|
35
35
|
context,
|
|
36
36
|
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
37
37
|
defaults: DEFAULT_OPTIONS,
|
|
38
|
+
id,
|
|
38
39
|
});
|
|
40
|
+
}
|
|
39
41
|
|
|
42
|
+
_initProperties(args) {
|
|
43
|
+
super._initProperties(args);
|
|
44
|
+
const { id } = args;
|
|
40
45
|
defineValues(this, { id });
|
|
41
|
-
|
|
46
|
+
}
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
_initReset(args) {
|
|
49
|
+
this._context._members.set(args.id, this);
|
|
50
|
+
super._initReset(args);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
// lifecycle //
|
package/src/workflow/search.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { API } from '@miso.ai/commons';
|
|
2
2
|
import Workflow from './base.js';
|
|
3
3
|
import { mergeApiOptions } from './options.js';
|
|
4
|
-
import * as sources from '../source
|
|
4
|
+
import * as sources from '../source.js';
|
|
5
5
|
import { fields, AutocompleteActor } from '../actor/index.js';
|
|
6
|
-
import { ROLE } from '../constants.js';
|
|
6
|
+
import { ROLE, DATA_ASPECT } from '../constants.js';
|
|
7
7
|
import { ListLayout, SearchBoxLayout } from '../layout/index.js';
|
|
8
8
|
import { makeConfigurable } from './options.js';
|
|
9
9
|
|
|
@@ -54,13 +54,22 @@ export default class Search extends Workflow {
|
|
|
54
54
|
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
55
55
|
defaults: DEFAULT_OPTIONS,
|
|
56
56
|
});
|
|
57
|
+
}
|
|
57
58
|
|
|
59
|
+
_initActors(args) {
|
|
60
|
+
super._initActors(args);
|
|
58
61
|
this._autocomplete = new AutocompleteActor(this._hub, {
|
|
59
62
|
source: sources.api(this._client),
|
|
60
63
|
options: this._options,
|
|
61
64
|
});
|
|
65
|
+
}
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
_initSubscriptions(args) {
|
|
68
|
+
super._initSubscriptions(args);
|
|
69
|
+
this._unsubscribes = [
|
|
70
|
+
...this._unsubscribes,
|
|
71
|
+
this._hub.on(fields.query(), args => this._query(args)),
|
|
72
|
+
];
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
// lifecycle //
|
|
@@ -80,16 +89,35 @@ export default class Search extends Workflow {
|
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
|
|
83
|
-
query(
|
|
92
|
+
query(args) {
|
|
93
|
+
if (!args.q) {
|
|
94
|
+
throw new Error(`q is required in query() call`);
|
|
95
|
+
}
|
|
96
|
+
this._hub.update(fields.query(), args);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_query(args) {
|
|
100
|
+
// start a new session
|
|
84
101
|
this.restart();
|
|
85
102
|
const { session } = this;
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
|
|
104
|
+
// build payload and trigger request
|
|
105
|
+
const payload = this._buildPayload(args);
|
|
106
|
+
const event = mergeApiOptions(this._options.resolved.api, { payload, session });
|
|
107
|
+
this._request(event);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_buildPayload(args) {
|
|
111
|
+
return args;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_request(event) {
|
|
115
|
+
this._hub.update(fields.request(), event);
|
|
88
116
|
}
|
|
89
117
|
|
|
90
118
|
updateCompletions(event) {
|
|
91
119
|
// TODO: verify
|
|
92
|
-
this._hub.update(fields.
|
|
120
|
+
this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
|
|
93
121
|
...event,
|
|
94
122
|
source: 'manual',
|
|
95
123
|
});
|
package/dist/cjs/source/api.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = _default;
|
|
7
|
-
var _commons = require("@miso.ai/commons");
|
|
8
|
-
function _default(client) {
|
|
9
|
-
// TODO: send uuid & unit id
|
|
10
|
-
return async _ref => {
|
|
11
|
-
let {
|
|
12
|
-
group,
|
|
13
|
-
name,
|
|
14
|
-
payload,
|
|
15
|
-
options
|
|
16
|
-
} = _ref;
|
|
17
|
-
if (group === _commons.API.GROUP.ASK && name === _commons.API.NAME.QUESTIONS) {
|
|
18
|
-
return client.api.ask.questions(payload, options);
|
|
19
|
-
}
|
|
20
|
-
// because name is in snake case
|
|
21
|
-
return client.api[group]._run(name, payload, options);
|
|
22
|
-
};
|
|
23
|
-
}
|
package/src/source/api.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { API } from '@miso.ai/commons';
|
|
2
|
-
|
|
3
|
-
export default function(client) {
|
|
4
|
-
// TODO: send uuid & unit id
|
|
5
|
-
return async ({ group, name, payload, options }) => {
|
|
6
|
-
if (group === API.GROUP.ASK && name === API.NAME.QUESTIONS) {
|
|
7
|
-
return client.api.ask.questions(payload, options);
|
|
8
|
-
}
|
|
9
|
-
// because name is in snake case
|
|
10
|
-
return client.api[group]._run(name, payload, options);
|
|
11
|
-
};
|
|
12
|
-
}
|