@pellux/goodvibes-sdk 0.28.17 → 0.28.19
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/_internal/contracts/artifacts/operator-contract.json +598 -1
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.js +1 -1
- package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +598 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.js +6 -0
- package/dist/_internal/platform/knowledge/home-graph/ask.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/ask.js +24 -1
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.js +3 -0
- package/dist/_internal/platform/knowledge/home-graph/map-view.js +12 -9
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts +3 -1
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/pages.js +104 -1
- package/dist/_internal/platform/knowledge/home-graph/reindex.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/reindex.js +4 -0
- package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/service.js +2 -0
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts +25 -0
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/answer-fallback.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/answer-fallback.js +143 -1
- package/dist/_internal/platform/knowledge/semantic/answer-source-ranking.d.ts +1 -0
- package/dist/_internal/platform/knowledge/semantic/answer-source-ranking.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/answer-source-ranking.js +5 -3
- package/dist/_internal/platform/knowledge/semantic/answer.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/answer.js +227 -39
- package/dist/_internal/platform/knowledge/semantic/enrichment.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/enrichment.js +36 -1
- package/dist/_internal/platform/knowledge/semantic/fact-quality.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/fact-quality.js +24 -2
- package/dist/_internal/platform/knowledge/semantic/repair-profile.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/repair-profile.js +20 -12
- package/dist/_internal/platform/knowledge/semantic/repair-subjects.d.ts +16 -0
- package/dist/_internal/platform/knowledge/semantic/repair-subjects.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/repair-subjects.js +52 -0
- package/dist/_internal/platform/knowledge/semantic/self-improvement-promotion.js +117 -18
- package/dist/_internal/platform/knowledge/semantic/self-improvement.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/semantic/self-improvement.js +36 -10
- package/dist/_internal/platform/knowledge/semantic/service.js +4 -2
- package/dist/_internal/platform/knowledge/semantic/types.d.ts +1 -0
- package/dist/_internal/platform/knowledge/semantic/types.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/types.d.ts +4 -0
- package/dist/_internal/platform/knowledge/types.d.ts.map +1 -1
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -17,7 +17,9 @@ export function rankAnswerSources(evidence, facts) {
|
|
|
17
17
|
promotedFactCountBySource.set(sourceId, (promotedFactCountBySource.get(sourceId) ?? 0) + 1);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const sources = uniqueSources(evidence.flatMap((item) => item.source ? [item.source] : []));
|
|
21
|
+
const realSources = sources.filter((source) => source.metadata.homeGraphGeneratedPage !== true);
|
|
22
|
+
return (realSources.length > 0 ? realSources : sources)
|
|
21
23
|
.sort((left, right) => (sourceAnswerQuality(right, evidenceScoreBySource, factCountBySource, promotedFactCountBySource)
|
|
22
24
|
- sourceAnswerQuality(left, evidenceScoreBySource, factCountBySource, promotedFactCountBySource)
|
|
23
25
|
|| left.id.localeCompare(right.id)));
|
|
@@ -26,14 +28,14 @@ function sourceAnswerQuality(source, evidenceScoreBySource, factCountBySource, p
|
|
|
26
28
|
const discovery = readRecord(source.metadata.sourceDiscovery);
|
|
27
29
|
const rank = typeof discovery.sourceRank === 'number' ? Math.max(0, 12 - discovery.sourceRank) : 0;
|
|
28
30
|
return Math.round((evidenceScoreBySource.get(source.id) ?? 0) / 4)
|
|
29
|
-
+
|
|
31
|
+
+ sourceAuthorityBoostForAnswer(source)
|
|
30
32
|
+ Math.min(80, (factCountBySource.get(source.id) ?? 0) * 10)
|
|
31
33
|
+ Math.min(90, (promotedFactCountBySource.get(source.id) ?? 0) * 18)
|
|
32
34
|
+ rank * 4
|
|
33
35
|
+ (source.status === 'indexed' ? 12 : source.status === 'pending' ? 2 : 0)
|
|
34
36
|
- (source.metadata.homeGraphGeneratedPage === true ? 90 : 0);
|
|
35
37
|
}
|
|
36
|
-
function
|
|
38
|
+
export function sourceAuthorityBoostForAnswer(source) {
|
|
37
39
|
const discovery = readRecord(source.metadata.sourceDiscovery);
|
|
38
40
|
const text = `${readString(discovery.trustReason) ?? ''} ${readString(discovery.sourceDomain) ?? ''} ${source.sourceUri ?? ''} ${source.canonicalUri ?? ''}`.toLowerCase();
|
|
39
41
|
if (/\bofficial-vendor-domain\b/.test(text) || /(^|[/.])(?:lg|sony|samsung|apple)\.com\b/.test(text))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAYlD,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAE7B,oBAAoB,EAErB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAYlD,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAE7B,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAiCpB,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC5C;AAyCD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,sBAAsB,EAC/B,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,6BAA6B,CAAC,CAyGxC"}
|
|
@@ -6,7 +6,8 @@ import { concreteAnswerGapSpaceId } from './answer-space.js';
|
|
|
6
6
|
import { answerNeedsFeatureGap, cleanSynthesizedAnswer } from './answer-quality.js';
|
|
7
7
|
import { clampTimeoutMs, withTimeoutOrNull } from './timeouts.js';
|
|
8
8
|
import { renderFallbackAnswer } from './answer-fallback.js';
|
|
9
|
-
import { rankAnswerSources } from './answer-source-ranking.js';
|
|
9
|
+
import { rankAnswerSources, sourceAuthorityBoostForAnswer } from './answer-source-ranking.js';
|
|
10
|
+
import { canonicalRepairSubjectNodes } from './repair-subjects.js';
|
|
10
11
|
const GENERIC_ANSWER_INTENT_TOKENS = new Set([
|
|
11
12
|
'capabilities',
|
|
12
13
|
'capability',
|
|
@@ -38,42 +39,45 @@ export async function answerKnowledgeQuery(context, input) {
|
|
|
38
39
|
const spaceId = normalizeKnowledgeSpaceId(input.knowledgeSpaceId);
|
|
39
40
|
const mode = input.mode ?? 'standard';
|
|
40
41
|
const limit = Math.max(1, input.limit ?? 8);
|
|
41
|
-
|
|
42
|
+
let evidence = collectAnswerEvidence(context.store, input, spaceId, limit);
|
|
42
43
|
if (evidence.length === 0) {
|
|
43
|
-
const linkedObjects = input.includeLinkedObjects === false ? [] : [...input.linkedObjects ?? []];
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
const linkedObjects = input.includeLinkedObjects === false ? [] : filterAnswerLinkedObjects(spaceId, input.query, [...(input.linkedObjects ?? [])]);
|
|
45
|
+
const linkedEvidence = includeOfficialLinkedEvidence(context.store, spaceId, input.query, evidence, linkedObjects, limit);
|
|
46
|
+
if (linkedEvidence.length > 0) {
|
|
47
|
+
evidence = linkedEvidence;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const gap = shouldPersistNoMatchGap(spaceId, input.query, linkedObjects)
|
|
51
|
+
? await persistAnswerGap(context.store, concreteAnswerGapSpaceId(spaceId, [], [], linkedObjects), input.query, 'No indexed evidence matched the question.', {
|
|
52
|
+
linkedObjects,
|
|
53
|
+
})
|
|
54
|
+
: null;
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
spaceId,
|
|
58
|
+
query: input.query,
|
|
59
|
+
answer: {
|
|
60
|
+
text: input.noMatchMessage ?? `No knowledge matched "${input.query}".`,
|
|
61
|
+
mode,
|
|
62
|
+
confidence: 0,
|
|
63
|
+
sources: [],
|
|
64
|
+
linkedObjects,
|
|
65
|
+
facts: [],
|
|
66
|
+
gaps: gap ? [gap] : [],
|
|
67
|
+
synthesized: false,
|
|
68
|
+
},
|
|
69
|
+
results: [],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
64
72
|
}
|
|
65
|
-
|
|
66
|
-
const facts = filterFactsForQuery(input.query, uniqueNodes(evidence.flatMap((item) => item.facts))).slice(0, 24);
|
|
67
|
-
const sources = rankAnswerSources(evidence, facts)
|
|
68
|
-
.slice(0, limit)
|
|
69
|
-
.map(withAnswerSourceAliases);
|
|
73
|
+
let rawFacts = filterFactsForQuery(input.query, uniqueNodes(evidence.flatMap((item) => item.facts))).slice(0, 24);
|
|
70
74
|
const inferredHomeAssistantLinkedObjects = input.includeLinkedObjects === false
|
|
71
75
|
? []
|
|
72
76
|
: inferHomeAssistantLinkedObjects(context.store, spaceId, input.query);
|
|
73
77
|
const evidenceLinkedObjects = shouldUseEvidenceLinkedObjects(spaceId, input, inferredHomeAssistantLinkedObjects)
|
|
74
78
|
? evidence.flatMap((item) => item.node ? [item.node] : [])
|
|
75
79
|
: [];
|
|
76
|
-
const
|
|
80
|
+
const rawLinkedObjects = input.includeLinkedObjects === false
|
|
77
81
|
? []
|
|
78
82
|
: uniqueNodes([
|
|
79
83
|
...(input.linkedObjects ?? []),
|
|
@@ -82,6 +86,15 @@ export async function answerKnowledgeQuery(context, input) {
|
|
|
82
86
|
])
|
|
83
87
|
.filter(isSemanticAnswerLinkedObject)
|
|
84
88
|
.slice(0, 24);
|
|
89
|
+
const linkedObjects = filterAnswerLinkedObjects(spaceId, input.query, rawLinkedObjects);
|
|
90
|
+
evidence = includeOfficialLinkedEvidence(context.store, spaceId, input.query, evidence, linkedObjects, limit);
|
|
91
|
+
rawFacts = filterFactsForQuery(input.query, uniqueNodes(evidence.flatMap((item) => item.facts))).slice(0, 24);
|
|
92
|
+
const llmAnswer = await synthesizeAnswer(context.llm ?? null, input.query, mode, evidence, input.timeoutMs);
|
|
93
|
+
const rankedSources = rankAnswerSources(evidence, rawFacts);
|
|
94
|
+
const facts = withAnswerFactContract(context.store, rawFacts, linkedObjects);
|
|
95
|
+
const sources = includeOfficialLinkedSources(context.store, spaceId, rankedSources, linkedObjects)
|
|
96
|
+
.slice(0, limit)
|
|
97
|
+
.map(withAnswerSourceAliases);
|
|
85
98
|
const gapSpaceId = concreteAnswerGapSpaceId(spaceId, evidence, sources, linkedObjects);
|
|
86
99
|
const gaps = await persistAnswerGaps(context.store, gapSpaceId, input.query, llmAnswer?.gaps ?? [], {
|
|
87
100
|
sources,
|
|
@@ -103,14 +116,14 @@ export async function answerKnowledgeQuery(context, input) {
|
|
|
103
116
|
const llmText = llmAnswer?.answer?.trim();
|
|
104
117
|
const cleanedLlmText = llmText ? cleanSynthesizedAnswer(llmText, featureIntent) : undefined;
|
|
105
118
|
const dropLowValueLlmAnswer = featureIntent && Boolean(cleanedLlmText) && isLowValueFeatureOrSpecText(cleanedLlmText ?? '');
|
|
106
|
-
const fallback =
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const
|
|
119
|
+
const fallback = renderFallbackAnswer(input.query, mode, evidence, facts);
|
|
120
|
+
const preferFallback = shouldPreferFallbackAnswer(featureIntent, cleanedLlmText, fallback.text);
|
|
121
|
+
const useFallback = dropLowValueLlmAnswer || preferFallback || !cleanedLlmText;
|
|
122
|
+
const text = cleanSynthesizedAnswer((useFallback ? fallback.text : cleanedLlmText) || '', featureIntent);
|
|
123
|
+
const synthesized = useFallback ? fallback.synthesized : Boolean(cleanedLlmText);
|
|
111
124
|
const confidence = input.includeConfidence === false
|
|
112
125
|
? 0
|
|
113
|
-
: dropLowValueLlmAnswer ? 0 : answerConfidence(llmAnswer, evidence);
|
|
126
|
+
: dropLowValueLlmAnswer || (useFallback && !fallback.synthesized) ? 0 : answerConfidence(preferFallback ? null : llmAnswer, evidence);
|
|
114
127
|
return {
|
|
115
128
|
ok: true,
|
|
116
129
|
spaceId,
|
|
@@ -123,11 +136,19 @@ export async function answerKnowledgeQuery(context, input) {
|
|
|
123
136
|
linkedObjects,
|
|
124
137
|
facts,
|
|
125
138
|
gaps: evidenceGap ? uniqueNodes([...gaps, evidenceGap]) : gaps,
|
|
126
|
-
synthesized
|
|
139
|
+
synthesized,
|
|
127
140
|
},
|
|
128
141
|
results: evidence.map(toSearchResult),
|
|
129
142
|
};
|
|
130
143
|
}
|
|
144
|
+
function shouldPersistNoMatchGap(spaceId, query, linkedObjects) {
|
|
145
|
+
if (linkedObjects.length > 0)
|
|
146
|
+
return true;
|
|
147
|
+
if (normalizeKnowledgeSpaceId(spaceId) !== 'homeassistant')
|
|
148
|
+
return true;
|
|
149
|
+
const subjectTokens = tokenizeSemanticQuery(query).filter((token) => !GENERIC_ANSWER_INTENT_TOKENS.has(token));
|
|
150
|
+
return subjectTokens.length > 0;
|
|
151
|
+
}
|
|
131
152
|
function collectAnswerEvidence(store, input, spaceId, limit) {
|
|
132
153
|
const tokens = expandQueryTokens(tokenizeSemanticQuery(input.query));
|
|
133
154
|
if (tokens.length === 0)
|
|
@@ -140,13 +161,15 @@ function collectAnswerEvidence(store, input, spaceId, limit) {
|
|
|
140
161
|
const sourceFacts = buildSourceFactIndex(store, spaceId);
|
|
141
162
|
const linkedSourceIds = sourceIdsLinkedToNodes(store, new Set([...candidateNodeIds, ...linkedObjectIds]), spaceId);
|
|
142
163
|
const broadHomeAssistantAlias = normalizeKnowledgeSpaceId(spaceId) === 'homeassistant' && !strictCandidates;
|
|
164
|
+
if (broadHomeAssistantAlias && subjectTokens.length === 0 && linkedObjectIds.size === 0)
|
|
165
|
+
return [];
|
|
143
166
|
const homeAssistantScope = !strictCandidates
|
|
144
167
|
? inferHomeAssistantAnswerScope(store, spaceId, input.query, subjectTokens)
|
|
145
168
|
: null;
|
|
146
169
|
const sourceItems = store.listSources(10_000)
|
|
147
170
|
.filter((source) => belongsToAnswerSpace(source, spaceId))
|
|
148
171
|
.filter((source) => sourceInHomeAssistantAnswerScope(store, source, homeAssistantScope))
|
|
149
|
-
.filter((source) => !strictCandidates || candidateSourceIds.has(source.id) ||
|
|
172
|
+
.filter((source) => !strictCandidates || candidateSourceIds.has(source.id) || linkedSourceIds.has(source.id))
|
|
150
173
|
.map((source) => {
|
|
151
174
|
const extraction = store.getExtractionBySourceId(source.id);
|
|
152
175
|
const facts = filterFactsForQuery(input.query, sourceFacts.get(source.id) ?? []);
|
|
@@ -232,6 +255,16 @@ function inferHomeAssistantLinkedObjects(store, spaceId, query) {
|
|
|
232
255
|
.filter((node) => belongsToAnswerSpace(node, spaceId))
|
|
233
256
|
.filter(isSemanticAnswerLinkedObject);
|
|
234
257
|
}
|
|
258
|
+
function filterAnswerLinkedObjects(spaceId, query, nodes) {
|
|
259
|
+
const normalized = normalizeKnowledgeSpaceId(spaceId);
|
|
260
|
+
if (normalized !== 'homeassistant' && !isHomeAssistantKnowledgeSpace(normalized))
|
|
261
|
+
return nodes;
|
|
262
|
+
const canonical = canonicalRepairSubjectNodes({ nodes, text: query });
|
|
263
|
+
if (canonical.length > 0)
|
|
264
|
+
return canonical.slice(0, 24);
|
|
265
|
+
const integrationIntent = /\b(integration|platform|add-?on|addon|plugin|service|api|setup|configure|configuration|auth|credential|rate limit)\b/i.test(query);
|
|
266
|
+
return nodes.filter((node) => integrationIntent || node.kind !== 'ha_integration').slice(0, 24);
|
|
267
|
+
}
|
|
235
268
|
function shouldUseEvidenceLinkedObjects(spaceId, input, inferredHomeAssistantLinkedObjects) {
|
|
236
269
|
if (input.linkedObjects?.length)
|
|
237
270
|
return true;
|
|
@@ -241,6 +274,140 @@ function shouldUseEvidenceLinkedObjects(spaceId, input, inferredHomeAssistantLin
|
|
|
241
274
|
}
|
|
242
275
|
return true;
|
|
243
276
|
}
|
|
277
|
+
function withAnswerFactContract(store, facts, linkedObjects) {
|
|
278
|
+
if (facts.length === 0)
|
|
279
|
+
return [];
|
|
280
|
+
const linkedObjectIds = new Set(linkedObjects.map((node) => node.id));
|
|
281
|
+
return facts.map((fact) => {
|
|
282
|
+
const source = fact.sourceId ? store.getSource(fact.sourceId) : null;
|
|
283
|
+
const discovery = readRecord(source?.metadata.sourceDiscovery);
|
|
284
|
+
const metadataLinkedIds = uniqueStrings([
|
|
285
|
+
...readStringArray(fact.metadata.linkedObjectIds),
|
|
286
|
+
...readStringArray(fact.metadata.subjectIds),
|
|
287
|
+
...readStringArray(discovery.linkedObjectIds),
|
|
288
|
+
]);
|
|
289
|
+
const subjectIds = metadataLinkedIds.filter((id) => linkedObjectIds.has(id));
|
|
290
|
+
const fallbackSubjectIds = subjectIds.length > 0
|
|
291
|
+
? subjectIds
|
|
292
|
+
: linkedObjects.length === 1 ? [linkedObjects[0].id] : [];
|
|
293
|
+
const subjects = fallbackSubjectIds
|
|
294
|
+
.map((id) => linkedObjects.find((node) => node.id === id) ?? store.getNode(id))
|
|
295
|
+
.filter((node) => Boolean(node && node.status !== 'stale'));
|
|
296
|
+
if (subjects.length === 0)
|
|
297
|
+
return fact;
|
|
298
|
+
const targetHints = answerTargetHints(subjects);
|
|
299
|
+
const metadata = {
|
|
300
|
+
...fact.metadata,
|
|
301
|
+
subject: readString(fact.metadata.subject) ?? subjects[0]?.title,
|
|
302
|
+
subjectIds: subjects.map((node) => node.id),
|
|
303
|
+
linkedObjectIds: subjects.map((node) => node.id),
|
|
304
|
+
targetHints,
|
|
305
|
+
};
|
|
306
|
+
return {
|
|
307
|
+
...fact,
|
|
308
|
+
metadata,
|
|
309
|
+
subject: metadata.subject,
|
|
310
|
+
subjectIds: metadata.subjectIds,
|
|
311
|
+
linkedObjectIds: metadata.linkedObjectIds,
|
|
312
|
+
targetHints,
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
function answerTargetHints(nodes) {
|
|
317
|
+
return nodes.map((node) => ({
|
|
318
|
+
id: node.id,
|
|
319
|
+
kind: node.kind,
|
|
320
|
+
title: node.title,
|
|
321
|
+
...(node.summary ? { summary: node.summary } : {}),
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
function includeOfficialLinkedSources(store, spaceId, rankedSources, linkedObjects) {
|
|
325
|
+
if (linkedObjects.length === 0)
|
|
326
|
+
return rankedSources;
|
|
327
|
+
const linkedIds = new Set(linkedObjects.map((node) => node.id));
|
|
328
|
+
const linkedSourceIds = sourceIdsLinkedToNodes(store, linkedIds, spaceId);
|
|
329
|
+
const official = store.listSources(10_000)
|
|
330
|
+
.filter((source) => belongsToAnswerSpace(source, spaceId))
|
|
331
|
+
.filter((source) => sourceAuthorityBoostForAnswer(source) > 0)
|
|
332
|
+
.filter((source) => {
|
|
333
|
+
const discovery = readRecord(source.metadata.sourceDiscovery);
|
|
334
|
+
return linkedSourceIds.has(source.id)
|
|
335
|
+
|| readStringArray(discovery.linkedObjectIds).some((id) => linkedIds.has(id));
|
|
336
|
+
})
|
|
337
|
+
.sort((left, right) => sourceAuthorityBoostForAnswer(right) - sourceAuthorityBoostForAnswer(left));
|
|
338
|
+
return uniqueSources([...official, ...rankedSources]);
|
|
339
|
+
}
|
|
340
|
+
function includeOfficialLinkedEvidence(store, spaceId, query, evidence, linkedObjects, limit) {
|
|
341
|
+
if (linkedObjects.length === 0)
|
|
342
|
+
return [...evidence];
|
|
343
|
+
const linkedIds = new Set(linkedObjects.map((node) => node.id));
|
|
344
|
+
const linkedSourceIds = sourceIdsLinkedToNodes(store, linkedIds, spaceId);
|
|
345
|
+
const tokens = expandQueryTokens(tokenizeSemanticQuery(query));
|
|
346
|
+
const sourceFacts = buildSourceFactIndex(store, spaceId);
|
|
347
|
+
const officialItems = store.listSources(10_000)
|
|
348
|
+
.filter((source) => belongsToAnswerSpace(source, spaceId))
|
|
349
|
+
.filter((source) => sourceAuthorityBoostForAnswer(source) > 0)
|
|
350
|
+
.filter((source) => linkedSourceIds.has(source.id) || readStringArray(readRecord(source.metadata.sourceDiscovery).linkedObjectIds).some((id) => linkedIds.has(id)))
|
|
351
|
+
.map((source) => {
|
|
352
|
+
const extraction = store.getExtractionBySourceId(source.id);
|
|
353
|
+
const facts = filterFactsForQuery(query, sourceFacts.get(source.id) ?? []);
|
|
354
|
+
const text = sourceSemanticText(source, extraction);
|
|
355
|
+
const scoringText = [
|
|
356
|
+
source.title,
|
|
357
|
+
source.summary,
|
|
358
|
+
source.description,
|
|
359
|
+
source.tags.join(' '),
|
|
360
|
+
text,
|
|
361
|
+
facts.map(renderFactForScoring).join(' '),
|
|
362
|
+
].join('\n');
|
|
363
|
+
const semanticScore = scoreSemanticText(scoringText, tokens);
|
|
364
|
+
return {
|
|
365
|
+
kind: 'source',
|
|
366
|
+
id: source.id,
|
|
367
|
+
title: source.title ?? source.canonicalUri ?? source.sourceUri ?? source.id,
|
|
368
|
+
score: semanticScore + sourceAuthorityBoostForAnswer(source) + Math.min(80, facts.length * 10),
|
|
369
|
+
source,
|
|
370
|
+
excerpt: selectEvidenceExcerpt(query, text, facts),
|
|
371
|
+
facts,
|
|
372
|
+
};
|
|
373
|
+
})
|
|
374
|
+
.filter((item) => item.score > 0);
|
|
375
|
+
if (officialItems.length === 0)
|
|
376
|
+
return [...evidence];
|
|
377
|
+
return uniqueEvidenceItems([...officialItems, ...evidence]
|
|
378
|
+
.sort((left, right) => right.score - left.score || left.id.localeCompare(right.id)))
|
|
379
|
+
.slice(0, Math.max(limit, evidence.length, 1));
|
|
380
|
+
}
|
|
381
|
+
function shouldPreferFallbackAnswer(featureIntent, llmText, fallbackText) {
|
|
382
|
+
if (!featureIntent || !fallbackText)
|
|
383
|
+
return false;
|
|
384
|
+
if (!llmText)
|
|
385
|
+
return true;
|
|
386
|
+
const lower = llmText.toLowerCase();
|
|
387
|
+
if (isLowValueFeatureOrSpecText(llmText))
|
|
388
|
+
return true;
|
|
389
|
+
if (/\b(source-backed facts identify|available source-backed details include|matching sources exist|not enough source-backed facts|not enough concrete source-backed)\b/.test(lower)) {
|
|
390
|
+
return hasConcreteFeatureSignal(fallbackText);
|
|
391
|
+
}
|
|
392
|
+
if (/\bevidence\b/.test(lower) && featureFamilyCount(fallbackText) >= 2)
|
|
393
|
+
return true;
|
|
394
|
+
if (featureFamilyCount(llmText) < 2 && featureFamilyCount(fallbackText) >= 2)
|
|
395
|
+
return true;
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
function featureFamilyCount(text) {
|
|
399
|
+
const lower = text.toLowerCase();
|
|
400
|
+
return [
|
|
401
|
+
/\b(hdmi|earc|arc|ports?|usb|ethernet|optical|rf|antenna|rs-?232c?)\b/,
|
|
402
|
+
/\b(hdr|hdr10|dolby vision|hlg|filmmaker)\b/,
|
|
403
|
+
/\b(4k|8k|uhd|resolution|refresh|120\s*hz|100\s*hz|nanocell|display|screen)\b/,
|
|
404
|
+
/\b(webos|apps?|streaming|airplay|homekit|chromecast|smart tv|thinq)\b/,
|
|
405
|
+
/\b(wi-?fi|bluetooth|wireless lan)\b/,
|
|
406
|
+
/\b(audio|speakers?|dolby atmos|sound)\b/,
|
|
407
|
+
/\b(game|gaming|vrr|allm|freesync|g-sync)\b/,
|
|
408
|
+
/\b(tuner|atsc|qam|ntsc|broadcast)\b/,
|
|
409
|
+
].filter((pattern) => pattern.test(lower)).length;
|
|
410
|
+
}
|
|
244
411
|
async function synthesizeAnswer(llm, query, mode, evidence, requestedTimeoutMs) {
|
|
245
412
|
if (!llm)
|
|
246
413
|
return null;
|
|
@@ -534,17 +701,26 @@ function selectEvidenceExcerpt(query, text, facts) {
|
|
|
534
701
|
const tokens = expandQueryTokens(tokenizeSemanticQuery(query));
|
|
535
702
|
const intent = factIntent(tokenizeSemanticQuery(query));
|
|
536
703
|
const featureIntent = Boolean(intent && hasFeatureIntent(intent));
|
|
704
|
+
const evidenceText = stripEvidenceRoutingFragments(text);
|
|
537
705
|
const factLines = facts
|
|
538
706
|
.map(renderFactForPrompt)
|
|
539
707
|
.filter((line) => scoreSemanticText(line, tokens) > 0)
|
|
540
708
|
.filter((line) => !featureIntent || !isLowValueFeatureOrSpecText(line))
|
|
541
709
|
.slice(0, 12);
|
|
542
|
-
const windows = evidenceWindows(
|
|
710
|
+
const windows = evidenceWindows(evidenceText, tokens)
|
|
543
711
|
.filter((line) => !featureIntent || !isLowValueFeatureOrSpecText(line))
|
|
544
712
|
.slice(0, 4);
|
|
545
|
-
const fallback = featureIntent && (factLines.length > 0 || windows.length > 0) ? [] : [clampText(
|
|
713
|
+
const fallback = featureIntent && (factLines.length > 0 || windows.length > 0) ? [] : [clampText(evidenceText, 720)];
|
|
546
714
|
return uniqueStrings([...factLines, ...windows, ...fallback]).join('\n');
|
|
547
715
|
}
|
|
716
|
+
function stripEvidenceRoutingFragments(text) {
|
|
717
|
+
return normalizeWhitespace(text
|
|
718
|
+
.replace(/homegraph:\/\/\S+/gi, ' ')
|
|
719
|
+
.replace(/https?:\/\/\S+/gi, ' ')
|
|
720
|
+
.replace(/\bsemantic-gap-repair\b/gi, ' ')
|
|
721
|
+
.replace(/\bgenerated-page\b/gi, ' ')
|
|
722
|
+
.replace(/\b[a-z0-9-]+\.(?:com|net|org|io|dev|tv|ca|co\.uk)(?:\/\S*)?/gi, ' '));
|
|
723
|
+
}
|
|
548
724
|
function evidenceWindows(text, tokens) {
|
|
549
725
|
const normalized = normalizeWhitespace(text);
|
|
550
726
|
const sentences = splitSentences(normalized, 420);
|
|
@@ -694,6 +870,18 @@ function uniqueSources(sources) {
|
|
|
694
870
|
}
|
|
695
871
|
return out;
|
|
696
872
|
}
|
|
873
|
+
function uniqueEvidenceItems(items) {
|
|
874
|
+
const seen = new Set();
|
|
875
|
+
const out = [];
|
|
876
|
+
for (const item of items) {
|
|
877
|
+
const key = `${item.kind}:${item.id}`;
|
|
878
|
+
if (seen.has(key))
|
|
879
|
+
continue;
|
|
880
|
+
seen.add(key);
|
|
881
|
+
out.push(item);
|
|
882
|
+
}
|
|
883
|
+
return out;
|
|
884
|
+
}
|
|
697
885
|
function withAnswerSourceAliases(source) {
|
|
698
886
|
return {
|
|
699
887
|
...source,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrichment.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/enrichment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAEV,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAKV,oBAAoB,EAErB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"enrichment.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/enrichment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAEV,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAKV,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAmBpB,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC/C;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,kCAAkC,EAC3C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,GAAE,4BAAiC,GACzC,OAAO,CAAC,2BAA2B,CAAC,CA+BtC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MAX_SEMANTIC_SOURCE_CHARS, applySourceMetadata, clampText, normalizeWhitespace, readRecord, readString, semanticHash, semanticMetadata, semanticSlug, sourceKnowledgeSpace, sourceSemanticHash, sourceSemanticText, splitSentences, uniqueStrings, } from './utils.js';
|
|
2
|
+
import { canonicalRepairSubjectNodes } from './repair-subjects.js';
|
|
2
3
|
export async function enrichKnowledgeSource(context, source, options = {}) {
|
|
3
4
|
const extraction = context.store.getExtractionBySourceId(source.id);
|
|
4
5
|
const text = sourceSemanticText(source, extraction);
|
|
@@ -192,7 +193,11 @@ async function persistSemanticExtraction(store, source, extraction, semantic, op
|
|
|
192
193
|
entities.push(node);
|
|
193
194
|
await linkSourceToNode(store, source.id, node.id, 'mentions_entity', spaceId, semantic.extractor);
|
|
194
195
|
}
|
|
196
|
+
const sourceLinkedObjects = linkedObjectsForSource(store, source);
|
|
197
|
+
const sourceLinkedObjectIds = sourceLinkedObjects.map((node) => node.id);
|
|
198
|
+
const sourceTargetHints = sourceLinkedObjects.map((node) => ({ id: node.id, kind: node.kind, title: node.title }));
|
|
195
199
|
for (const fact of semantic.facts.slice(0, 160)) {
|
|
200
|
+
const targetHints = fact.targetHints?.length ? fact.targetHints : sourceTargetHints;
|
|
196
201
|
const node = await store.upsertNode({
|
|
197
202
|
id: `sem-fact-${semanticHash(spaceId, source.id, fact.kind, fact.title, fact.value ?? fact.summary)}`,
|
|
198
203
|
kind: 'fact',
|
|
@@ -208,7 +213,12 @@ async function persistSemanticExtraction(store, source, extraction, semantic, op
|
|
|
208
213
|
value: fact.value,
|
|
209
214
|
evidence: fact.evidence,
|
|
210
215
|
labels: fact.labels ?? [],
|
|
211
|
-
targetHints
|
|
216
|
+
targetHints,
|
|
217
|
+
...(sourceLinkedObjectIds.length > 0 ? {
|
|
218
|
+
subject: sourceLinkedObjects[0]?.title,
|
|
219
|
+
subjectIds: sourceLinkedObjectIds,
|
|
220
|
+
linkedObjectIds: sourceLinkedObjectIds,
|
|
221
|
+
} : {}),
|
|
212
222
|
sourceId: source.id,
|
|
213
223
|
extractionId: extraction?.id,
|
|
214
224
|
extractor: semantic.extractor,
|
|
@@ -480,6 +490,31 @@ function readStringArray(value) {
|
|
|
480
490
|
? uniqueStrings(value.map((entry) => typeof entry === 'string' ? entry : undefined))
|
|
481
491
|
: [];
|
|
482
492
|
}
|
|
493
|
+
function linkedObjectsForSource(store, source) {
|
|
494
|
+
const discovery = readRecord(source.metadata.sourceDiscovery);
|
|
495
|
+
const sourceSpaceId = sourceKnowledgeSpace(source);
|
|
496
|
+
const ids = uniqueStrings([
|
|
497
|
+
...readStringArray(discovery.linkedObjectIds),
|
|
498
|
+
...store.listEdges()
|
|
499
|
+
.filter((edge) => edge.fromKind === 'source' && edge.fromId === source.id)
|
|
500
|
+
.filter((edge) => edge.toKind === 'node' && edge.relation === 'source_for')
|
|
501
|
+
.filter((edge) => {
|
|
502
|
+
const edgeSpaceId = readString(edge.metadata.knowledgeSpaceId);
|
|
503
|
+
return !edgeSpaceId || edgeSpaceId === sourceSpaceId;
|
|
504
|
+
})
|
|
505
|
+
.map((edge) => edge.toId),
|
|
506
|
+
]);
|
|
507
|
+
const nodes = [];
|
|
508
|
+
for (const id of ids) {
|
|
509
|
+
const node = store.getNode(id);
|
|
510
|
+
if (node && node.status !== 'stale')
|
|
511
|
+
nodes.push(node);
|
|
512
|
+
}
|
|
513
|
+
return canonicalRepairSubjectNodes({
|
|
514
|
+
nodes,
|
|
515
|
+
text: `${source.title ?? ''} ${source.summary ?? ''} ${source.description ?? ''}`,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
483
518
|
function isFact(value) {
|
|
484
519
|
return Boolean(value);
|
|
485
520
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fact-quality.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/fact-quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAcvD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAK/E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAQlE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"fact-quality.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/fact-quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAcvD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAK/E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAQlE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAiIjE;AAsBD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAiB5E"}
|
|
@@ -29,8 +29,15 @@ export function semanticFactText(fact) {
|
|
|
29
29
|
export function isLowValueFeatureOrSpecText(text) {
|
|
30
30
|
const lower = text.toLowerCase();
|
|
31
31
|
const magicRemoteDetail = /\bmagic remote\b/.test(lower) || /\bbluetooth\b/.test(lower);
|
|
32
|
+
const nonRemoteFeatureSignal = hasNonRemoteFeatureSignal(lower);
|
|
32
33
|
if (/\?\s*$/.test(text.trim()))
|
|
33
34
|
return true;
|
|
35
|
+
if (/\bsemantic-gap-repair\b/.test(lower))
|
|
36
|
+
return true;
|
|
37
|
+
if (isUrlOrPathFragment(lower) && !hasConcreteFeatureSignal(lower))
|
|
38
|
+
return true;
|
|
39
|
+
if (isUrlOrPathFragment(lower) && /\b(source-backed facts identify|current page|database|manual\.nz|loading|semantic-gap-repair)\b/.test(lower))
|
|
40
|
+
return true;
|
|
34
41
|
if (isTruncatedManualFragment(lower))
|
|
35
42
|
return true;
|
|
36
43
|
if (/\b(items? supplied|supplied items?|included accessories|optional extras?|sold separately|separate purchase|accessories may vary|contents? of (this )?manual|may be changed|may change|subject to change|without prior notice|available menus? and options?|certified cable|unapproved items?)\b/.test(lower)) {
|
|
@@ -43,6 +50,7 @@ export function isLowValueFeatureOrSpecText(text) {
|
|
|
43
50
|
return true;
|
|
44
51
|
}
|
|
45
52
|
if (/^\s*\d+\s*(yes|no)\b/.test(lower)
|
|
53
|
+
|| /^\s*\d+\s*m\s*\(/.test(lower)
|
|
46
54
|
|| /^\s*\d+(hdmi|usb|audio|ports?|features?|smart)\b/.test(lower)
|
|
47
55
|
|| /^\s*0\s+ports\b/.test(lower)
|
|
48
56
|
|| /\b\d+\s+features such as\b/.test(lower)
|
|
@@ -50,6 +58,9 @@ export function isLowValueFeatureOrSpecText(text) {
|
|
|
50
58
|
|| /^\s*\d+\s*kg\d*/.test(lower)) {
|
|
51
59
|
return true;
|
|
52
60
|
}
|
|
61
|
+
if (/\b(series_url|exhibition display|supported audio formats|supported video formats|supported picture formats)\b/.test(lower)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
53
64
|
if (/\b(button|buttons|remote control)\b/.test(lower) && /[\u25b2\u25bc\u25c4\u25ba]|[▲▼◄►]|\\u25/.test(text)) {
|
|
54
65
|
return true;
|
|
55
66
|
}
|
|
@@ -67,7 +78,8 @@ export function isLowValueFeatureOrSpecText(text) {
|
|
|
67
78
|
return true;
|
|
68
79
|
}
|
|
69
80
|
if (/\b(magic remote|remote control)\b/.test(lower)
|
|
70
|
-
&& /\b(accessor(y|ies)|battery|batteries|button|environment|infrared|mr20ga|point|pointer|remote sensor|sap|sensor|shake|voice recognition)\b/.test(lower)
|
|
81
|
+
&& /\b(accessor(y|ies)|battery|batteries|button|environment|infrared|mr20ga|point|pointer|remote sensor|sap|sensor|shake|voice recognition)\b/.test(lower)
|
|
82
|
+
&& !nonRemoteFeatureSignal) {
|
|
71
83
|
return true;
|
|
72
84
|
}
|
|
73
85
|
if (/\b(crutchfield|speakercompare|speaker compare|equal[- ]power|equal[- ]volume|speaker shopping|speaker recommendations?)\b/.test(lower)) {
|
|
@@ -111,7 +123,8 @@ export function isLowValueFeatureOrSpecText(text) {
|
|
|
111
123
|
return true;
|
|
112
124
|
}
|
|
113
125
|
if (/\b(magic remote|remote)\b/.test(lower)
|
|
114
|
-
&& /\b(shake|pointer|cursor appears|environment|operating environment|voice recognition|recognition performance|point|sensor|press|button|sap|more actions?)\b/.test(lower)
|
|
126
|
+
&& /\b(shake|pointer|cursor appears|environment|operating environment|voice recognition|recognition performance|point|sensor|press|button|sap|more actions?)\b/.test(lower)
|
|
127
|
+
&& !nonRemoteFeatureSignal) {
|
|
115
128
|
return true;
|
|
116
129
|
}
|
|
117
130
|
if (/\b(sap|secondary audio program)\b/.test(lower) && /\b(button|press|enabled|audio)\b/.test(lower)) {
|
|
@@ -148,6 +161,15 @@ export function isLowValueFeatureOrSpecText(text) {
|
|
|
148
161
|
}
|
|
149
162
|
return false;
|
|
150
163
|
}
|
|
164
|
+
function hasNonRemoteFeatureSignal(text) {
|
|
165
|
+
return /\b(hdmi|earc|arc|hdr|hdr10|dolby vision|hlg|filmmaker|game optimizer|game mode|gaming|freesync|vrr|allm|4k|uhd|resolution|refresh|webos|airplay|homekit|wi-?fi|ethernet|usb|optical|tuner|atsc|qam|speaker|audio)\b/.test(text);
|
|
166
|
+
}
|
|
167
|
+
function isUrlOrPathFragment(value) {
|
|
168
|
+
return /https?:\/\//.test(value)
|
|
169
|
+
|| /\b[a-z0-9-]+\.(com|net|org|io|dev|tv|ca|co\.uk)\/[a-z0-9/_?=&.#-]+/.test(value)
|
|
170
|
+
|| /\b[a-z]{2}\/[a-z0-9/_-]+\/[a-z0-9._-]+/.test(value)
|
|
171
|
+
|| /\b[a-z0-9._-]+\/(specifications?|manuals?|products?|support|features?)\/[a-z0-9._-]+/.test(value);
|
|
172
|
+
}
|
|
151
173
|
function isTruncatedManualFragment(value) {
|
|
152
174
|
const trimmed = value.trim();
|
|
153
175
|
if (trimmed.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repair-profile.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/repair-profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AA0HD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GAAG,SAAS,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"repair-profile.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/repair-profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AA0HD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GAAG,SAAS,iBAAiB,EAAE,CA6B/B"}
|
|
@@ -13,7 +13,7 @@ const PROFILE_RULES = [
|
|
|
13
13
|
['4K UHD resolution', /\b4k\b|\buhd\b|\b3840\s*(?:x|×)\s*2160\b/i],
|
|
14
14
|
['NanoCell display technology', /\bnanocell\b/i],
|
|
15
15
|
['LCD/LED display', /\blcd\b|\bled\b/i],
|
|
16
|
-
['100/120 Hz refresh
|
|
16
|
+
['100/120 Hz refresh rate', /\b(?:100|120)\s*hz\b|\btrumotion\s*240\b/i],
|
|
17
17
|
['HDR10', /\bhdr10\b/i],
|
|
18
18
|
['Dolby Vision', /\bdolby vision\b/i],
|
|
19
19
|
['HLG', /\bhlg\b/i],
|
|
@@ -74,10 +74,10 @@ const PROFILE_RULES = [
|
|
|
74
74
|
intent: /\b(game|gaming|vrr|allm|freesync|g-?sync|low latency|hdmi\s*2\.1|4k\s*120)\b/,
|
|
75
75
|
minimumMatches: 1,
|
|
76
76
|
terms: [
|
|
77
|
-
['FreeSync/VRR
|
|
78
|
-
['ALLM/low
|
|
77
|
+
['FreeSync/VRR support', /\bfreesync\b|\bvrr\b/i],
|
|
78
|
+
['ALLM/low-latency support', /\ballm\b|\blow latency\b/i],
|
|
79
79
|
['Game Optimizer/game mode', /\bgame optimizer\b|\bgame mode\b|\bgaming\b/i],
|
|
80
|
-
['HDMI 2.1/high-bandwidth HDMI
|
|
80
|
+
['HDMI 2.1/high-bandwidth HDMI', /\bhdmi\s*2\.1\b|\b4k\s*(?:at|@)?\s*120\b|\b120\s*hz\b/i],
|
|
81
81
|
],
|
|
82
82
|
},
|
|
83
83
|
{
|
|
@@ -88,10 +88,10 @@ const PROFILE_RULES = [
|
|
|
88
88
|
intent: /\b(audio|speaker|sound|dolby atmos|dolby digital|earc|arc|watts?|channels?)\b/,
|
|
89
89
|
minimumMatches: 1,
|
|
90
90
|
terms: [
|
|
91
|
-
['speaker/audio output
|
|
91
|
+
['speaker/audio output', /\bspeakers?\b|\b(?:10|20|40)\s*w\b|\b2(?:\.0)?\s*ch\b/i],
|
|
92
92
|
['Dolby audio formats', /\bdolby atmos\b|\bdolby digital\b|\bdolby audio\b/i],
|
|
93
93
|
['HDMI ARC/eARC audio', /\bearc\b|\barc\b/i],
|
|
94
|
-
['
|
|
94
|
+
['audio format support', /\bsupported audio formats?\b|\bpcm\b|\btruehd\b/i],
|
|
95
95
|
],
|
|
96
96
|
},
|
|
97
97
|
{
|
|
@@ -110,14 +110,12 @@ const PROFILE_RULES = [
|
|
|
110
110
|
},
|
|
111
111
|
];
|
|
112
112
|
export function deriveRepairProfileFacts(input) {
|
|
113
|
-
const text =
|
|
113
|
+
const text = profileEvidenceText([
|
|
114
114
|
input.source.title,
|
|
115
115
|
input.source.summary,
|
|
116
116
|
input.source.description,
|
|
117
|
-
input.source.sourceUri,
|
|
118
|
-
input.source.canonicalUri,
|
|
119
117
|
input.text,
|
|
120
|
-
]
|
|
118
|
+
]);
|
|
121
119
|
if (!hasConcreteFeatureSignal(text))
|
|
122
120
|
return [];
|
|
123
121
|
const query = input.query.toLowerCase();
|
|
@@ -127,9 +125,10 @@ export function deriveRepairProfileFacts(input) {
|
|
|
127
125
|
.filter(([, pattern]) => pattern.test(text))
|
|
128
126
|
.map(([label]) => label));
|
|
129
127
|
const wanted = broadProfileIntent || rule.intent.test(query);
|
|
130
|
-
|
|
128
|
+
const minimumMatches = rule.intent.test(query) ? 1 : rule.minimumMatches;
|
|
129
|
+
if (values.length < minimumMatches || !wanted)
|
|
131
130
|
return [];
|
|
132
|
-
const summary = `${rule.title}
|
|
131
|
+
const summary = `${rule.title}: ${joinValues(values)}.`;
|
|
133
132
|
if (isLowValueFeatureOrSpecText(summary))
|
|
134
133
|
return [];
|
|
135
134
|
return [{
|
|
@@ -143,6 +142,15 @@ export function deriveRepairProfileFacts(input) {
|
|
|
143
142
|
}];
|
|
144
143
|
}).slice(0, 10);
|
|
145
144
|
}
|
|
145
|
+
function profileEvidenceText(values) {
|
|
146
|
+
return normalizeWhitespace(values
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
.join(' ')
|
|
149
|
+
.replace(/homegraph:\/\/\S+/g, ' ')
|
|
150
|
+
.replace(/https?:\/\/\S+/g, ' ')
|
|
151
|
+
.replace(/\b[a-z0-9.-]+\.(?:com|net|org|io|dev|tv|ca|co\.uk)\/[a-z0-9/_?=&.#-]+/gi, ' ')
|
|
152
|
+
.replace(/\b(?:series_url|current page|loading)\b/gi, ' '));
|
|
153
|
+
}
|
|
146
154
|
function joinValues(values) {
|
|
147
155
|
if (values.length <= 1)
|
|
148
156
|
return values[0] ?? '';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { KnowledgeNodeRecord } from '../types.js';
|
|
2
|
+
export interface RepairSubjectHint {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly kind: string;
|
|
5
|
+
readonly title: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function canonicalRepairSubjectNodes(input: {
|
|
8
|
+
readonly nodes: readonly (KnowledgeNodeRecord | undefined)[];
|
|
9
|
+
readonly text?: string;
|
|
10
|
+
}): KnowledgeNodeRecord[];
|
|
11
|
+
export declare function repairSubjectIds(input: {
|
|
12
|
+
readonly nodes: readonly (KnowledgeNodeRecord | undefined)[];
|
|
13
|
+
readonly text?: string;
|
|
14
|
+
}): string[];
|
|
15
|
+
export declare function repairSubjectHints(subjects: readonly KnowledgeNodeRecord[]): RepairSubjectHint[];
|
|
16
|
+
//# sourceMappingURL=repair-subjects.d.ts.map
|