@pellux/goodvibes-sdk 0.27.2 → 0.27.3
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 +134 -4
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
- package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
- package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +134 -4
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.js +1 -0
- package/dist/_internal/platform/control-plane/method-catalog-homegraph.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/method-catalog-homegraph.js +10 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts +1 -0
- 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 +7 -0
- package/dist/_internal/platform/daemon/http/home-graph-routes.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/home-graph-routes.js +7 -0
- package/dist/_internal/platform/knowledge/extractors.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/extractors.js +1 -116
- package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts +27 -0
- package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/home-graph/auto-link.js +236 -0
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts +1 -0
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.js +14 -8
- package/dist/_internal/platform/knowledge/home-graph/index.d.ts +1 -1
- package/dist/_internal/platform/knowledge/home-graph/index.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts +11 -0
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/home-graph/pages.js +44 -0
- package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts +3 -1
- package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/rendering.js +161 -4
- package/dist/_internal/platform/knowledge/home-graph/service.d.ts +6 -1
- package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/service.js +56 -3
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts +17 -0
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/index.d.ts +1 -1
- package/dist/_internal/platform/knowledge/index.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/pdf-extractor.d.ts +3 -0
- package/dist/_internal/platform/knowledge/pdf-extractor.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/pdf-extractor.js +346 -0
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import JSZip from 'jszip';
|
|
|
2
2
|
import { extname } from 'node:path';
|
|
3
3
|
import { guessMimeType } from '../artifacts/types.js';
|
|
4
4
|
import { extractReadableHtml } from './html-readability.js';
|
|
5
|
+
import { extractPdf } from './pdf-extractor.js';
|
|
5
6
|
const MAX_STRUCTURE_SEARCH_TEXT_CHARS = 128 * 1024;
|
|
6
7
|
function decodeHtmlEntities(value) {
|
|
7
8
|
return value
|
|
@@ -306,122 +307,6 @@ function extractYaml(buffer) {
|
|
|
306
307
|
metadata: {},
|
|
307
308
|
};
|
|
308
309
|
}
|
|
309
|
-
async function extractPdf(buffer) {
|
|
310
|
-
const parsed = await extractPdfWithPdfJs(buffer);
|
|
311
|
-
if (parsed)
|
|
312
|
-
return parsed;
|
|
313
|
-
return extractPdfRawStreams(buffer);
|
|
314
|
-
}
|
|
315
|
-
async function extractPdfWithPdfJs(buffer) {
|
|
316
|
-
try {
|
|
317
|
-
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
318
|
-
const loadingTask = pdfjs.getDocument({
|
|
319
|
-
data: new Uint8Array(buffer),
|
|
320
|
-
useSystemFonts: true,
|
|
321
|
-
});
|
|
322
|
-
const document = await loadingTask.promise;
|
|
323
|
-
const pageCount = document.numPages;
|
|
324
|
-
const pageTexts = [];
|
|
325
|
-
for (let pageNumber = 1; pageNumber <= pageCount; pageNumber += 1) {
|
|
326
|
-
const page = await document.getPage(pageNumber);
|
|
327
|
-
const content = await page.getTextContent();
|
|
328
|
-
const lines = textContentItemsToLines(content.items);
|
|
329
|
-
if (lines.length > 0)
|
|
330
|
-
pageTexts.push(lines.join('\n'));
|
|
331
|
-
page.cleanup();
|
|
332
|
-
}
|
|
333
|
-
await document.destroy();
|
|
334
|
-
const text = cleanText(pageTexts.join('\n\n'));
|
|
335
|
-
if (!text)
|
|
336
|
-
return undefined;
|
|
337
|
-
const searchText = searchTextPayload(text);
|
|
338
|
-
return {
|
|
339
|
-
extractorId: 'pdfjs',
|
|
340
|
-
format: 'pdf',
|
|
341
|
-
title: firstNonEmptyLine(text) ?? 'PDF document',
|
|
342
|
-
summary: summarizeText(text) ?? 'PDF document.',
|
|
343
|
-
excerpt: excerptText(text),
|
|
344
|
-
sections: uniqueStrings(text.split(/\n+/), 24),
|
|
345
|
-
links: uniqueStrings(Array.from(text.matchAll(/\bhttps?:\/\/[^\s)]+/g), (match) => match[0]), 50),
|
|
346
|
-
estimatedTokens: estimateTokens(text),
|
|
347
|
-
structure: {
|
|
348
|
-
pageCount,
|
|
349
|
-
extractedTextChars: text.length,
|
|
350
|
-
...(searchText ? { searchText } : {}),
|
|
351
|
-
},
|
|
352
|
-
metadata: {
|
|
353
|
-
limitations: ['PDF text extraction does not perform OCR for scanned images.'],
|
|
354
|
-
},
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
catch {
|
|
358
|
-
return undefined;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
function textContentItemsToLines(items) {
|
|
362
|
-
const lines = [];
|
|
363
|
-
let current = '';
|
|
364
|
-
for (const item of items) {
|
|
365
|
-
const record = unknownRecord(item);
|
|
366
|
-
const text = typeof record.str === 'string' ? cleanText(record.str) : '';
|
|
367
|
-
if (text)
|
|
368
|
-
current = current ? `${current} ${text}` : text;
|
|
369
|
-
if (record.hasEOL === true && current) {
|
|
370
|
-
lines.push(current);
|
|
371
|
-
current = '';
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (current)
|
|
375
|
-
lines.push(current);
|
|
376
|
-
return lines;
|
|
377
|
-
}
|
|
378
|
-
function unknownRecord(value) {
|
|
379
|
-
return value && typeof value === 'object' ? value : {};
|
|
380
|
-
}
|
|
381
|
-
function extractPdfRawStreams(buffer) {
|
|
382
|
-
const body = buffer.toString('latin1');
|
|
383
|
-
const texts = [];
|
|
384
|
-
const streamRe = /stream\r?\n([\s\S]*?)\r?\nendstream/g;
|
|
385
|
-
let match;
|
|
386
|
-
while ((match = streamRe.exec(body)) !== null) {
|
|
387
|
-
const chunk = match[1];
|
|
388
|
-
const parenRe = /\(([^)\\]*(?:\\.[^)\\]*)*)\)/g;
|
|
389
|
-
let textMatch;
|
|
390
|
-
while ((textMatch = parenRe.exec(chunk)) !== null) {
|
|
391
|
-
const text = cleanText(textMatch[1]
|
|
392
|
-
.replace(/\\n/g, '\n')
|
|
393
|
-
.replace(/\\r/g, '\r')
|
|
394
|
-
.replace(/\\t/g, '\t')
|
|
395
|
-
.replace(/\\\\/g, '\\')
|
|
396
|
-
.replace(/\\\(/g, '(')
|
|
397
|
-
.replace(/\\\)/g, ')'));
|
|
398
|
-
if (text.length > 1)
|
|
399
|
-
texts.push(text);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
const combined = uniqueStrings(texts, 64).join('\n');
|
|
403
|
-
const searchable = uniqueStrings(texts, 512).join('\n');
|
|
404
|
-
const searchText = searchTextPayload(searchable);
|
|
405
|
-
return {
|
|
406
|
-
extractorId: 'pdf',
|
|
407
|
-
format: 'pdf',
|
|
408
|
-
title: firstNonEmptyLine(combined) ?? 'PDF document',
|
|
409
|
-
summary: summarizeText(combined) ?? 'PDF extraction produced limited text; OCR is not used in-core.',
|
|
410
|
-
excerpt: excerptText(combined),
|
|
411
|
-
sections: uniqueStrings(combined.split(/\n+/), 8),
|
|
412
|
-
links: uniqueStrings(Array.from(combined.matchAll(/\bhttps?:\/\/[^\s)]+/g), (match) => match[0]), 50),
|
|
413
|
-
estimatedTokens: estimateTokens(combined),
|
|
414
|
-
structure: {
|
|
415
|
-
extractedStringCount: texts.length,
|
|
416
|
-
...(searchText ? { searchText } : {}),
|
|
417
|
-
},
|
|
418
|
-
metadata: {
|
|
419
|
-
limitations: texts.length === 0
|
|
420
|
-
? ['No readable text streams were found. Complex PDFs need OCR or a dedicated provider.']
|
|
421
|
-
: ['PDF extraction is best-effort and does not use OCR.'],
|
|
422
|
-
},
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
310
|
async function extractDocx(buffer) {
|
|
426
311
|
const zip = await JSZip.loadAsync(buffer);
|
|
427
312
|
const file = zip.file('word/document.xml');
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { KnowledgeStore } from '../store.js';
|
|
2
|
+
import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
3
|
+
import type { HomeGraphState } from './state.js';
|
|
4
|
+
export interface HomeGraphAutoLinkResult {
|
|
5
|
+
readonly edge: KnowledgeEdgeRecord;
|
|
6
|
+
readonly node: KnowledgeNodeRecord;
|
|
7
|
+
readonly relation: string;
|
|
8
|
+
readonly score: number;
|
|
9
|
+
readonly reasons: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function autoLinkHomeGraphSource(input: {
|
|
12
|
+
readonly store: KnowledgeStore;
|
|
13
|
+
readonly spaceId: string;
|
|
14
|
+
readonly installationId: string;
|
|
15
|
+
readonly source: KnowledgeSourceRecord;
|
|
16
|
+
readonly extraction?: KnowledgeExtractionRecord;
|
|
17
|
+
readonly state: HomeGraphState;
|
|
18
|
+
}): Promise<HomeGraphAutoLinkResult | undefined>;
|
|
19
|
+
export declare function autoLinkHomeGraphSources(input: {
|
|
20
|
+
readonly store: KnowledgeStore;
|
|
21
|
+
readonly spaceId: string;
|
|
22
|
+
readonly installationId: string;
|
|
23
|
+
readonly sources: readonly KnowledgeSourceRecord[];
|
|
24
|
+
readonly extractionBySourceId: ReadonlyMap<string, KnowledgeExtractionRecord>;
|
|
25
|
+
readonly state: HomeGraphState;
|
|
26
|
+
}): Promise<readonly HomeGraphAutoLinkResult[]>;
|
|
27
|
+
//# sourceMappingURL=auto-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-link.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/auto-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAQrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOjD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC,GAAG,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,CA2B/C;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;IAC9E,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC,GAAG,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CAiB9C"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { buildHomeGraphMetadata, edgeIsActive, isGeneratedPageSource, readRecord, uniqueStrings, } from './helpers.js';
|
|
2
|
+
const MIN_AUTO_LINK_SCORE = 90;
|
|
3
|
+
const MIN_SOURCE_TEXT_CHARS = 16;
|
|
4
|
+
const MAX_TEXT_FIELD_CHARS = 32_768;
|
|
5
|
+
const GENERIC_TOKENS = new Set(['device', 'home', 'assistant', 'smart', 'manual', 'owner', 'guide', 'user', 'the']);
|
|
6
|
+
export async function autoLinkHomeGraphSource(input) {
|
|
7
|
+
if (isGeneratedPageSource(input.source) || shouldSkipAutoLink(input.source))
|
|
8
|
+
return undefined;
|
|
9
|
+
if (hasActiveSourceLink(input.source.id, input.state.edges))
|
|
10
|
+
return undefined;
|
|
11
|
+
const candidates = scoreCandidates(input.source, input.extraction, input.state);
|
|
12
|
+
const best = candidates[0];
|
|
13
|
+
if (!best || best.score < MIN_AUTO_LINK_SCORE)
|
|
14
|
+
return undefined;
|
|
15
|
+
const next = candidates[1];
|
|
16
|
+
if (next && best.score - next.score < 20 && !best.reasons.some((reason) => reason.startsWith('exact-model:'))) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const relation = inferRelation(input.source);
|
|
20
|
+
const edge = await input.store.upsertEdge({
|
|
21
|
+
fromKind: 'source',
|
|
22
|
+
fromId: input.source.id,
|
|
23
|
+
toKind: 'node',
|
|
24
|
+
toId: best.node.id,
|
|
25
|
+
relation,
|
|
26
|
+
weight: Math.min(5, Math.max(1, Math.round(best.score / 60))),
|
|
27
|
+
metadata: buildHomeGraphMetadata(input.spaceId, input.installationId, {
|
|
28
|
+
linkStatus: 'active',
|
|
29
|
+
linkMethod: 'homegraph-auto-link',
|
|
30
|
+
autoLinkedAt: Date.now(),
|
|
31
|
+
autoLinkScore: best.score,
|
|
32
|
+
autoLinkReasons: best.reasons,
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
return { edge, node: best.node, relation, score: best.score, reasons: best.reasons };
|
|
36
|
+
}
|
|
37
|
+
export async function autoLinkHomeGraphSources(input) {
|
|
38
|
+
const linked = [];
|
|
39
|
+
for (const source of input.sources) {
|
|
40
|
+
const result = await autoLinkHomeGraphSource({
|
|
41
|
+
store: input.store,
|
|
42
|
+
spaceId: input.spaceId,
|
|
43
|
+
installationId: input.installationId,
|
|
44
|
+
source,
|
|
45
|
+
extraction: input.extractionBySourceId.get(source.id),
|
|
46
|
+
state: {
|
|
47
|
+
...input.state,
|
|
48
|
+
edges: [...input.state.edges, ...linked.map((entry) => entry.edge)],
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (result)
|
|
52
|
+
linked.push(result);
|
|
53
|
+
}
|
|
54
|
+
return linked;
|
|
55
|
+
}
|
|
56
|
+
function scoreCandidates(source, extraction, state) {
|
|
57
|
+
const sourceText = sourceEvidenceText(source, extraction);
|
|
58
|
+
if (sourceText.length < MIN_SOURCE_TEXT_CHARS)
|
|
59
|
+
return [];
|
|
60
|
+
const lower = sourceText.toLowerCase();
|
|
61
|
+
const sourceTokens = new Set(tokenize(sourceText));
|
|
62
|
+
return state.nodes
|
|
63
|
+
.filter((node) => isAutoLinkCandidateNode(node))
|
|
64
|
+
.map((node) => {
|
|
65
|
+
const reasons = [];
|
|
66
|
+
let score = 0;
|
|
67
|
+
const identity = nodeIdentity(node, state);
|
|
68
|
+
for (const model of identity.models) {
|
|
69
|
+
if (model.length >= 4 && includesIdentity(lower, model)) {
|
|
70
|
+
score += model.length >= 8 ? 180 : 120;
|
|
71
|
+
reasons.push(`exact-model:${model}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const entityId of identity.entityIds) {
|
|
75
|
+
if (includesIdentity(lower, entityId)) {
|
|
76
|
+
score += 140;
|
|
77
|
+
reasons.push(`entity-id:${entityId}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const deviceId of identity.deviceIds) {
|
|
81
|
+
if (includesIdentity(lower, deviceId)) {
|
|
82
|
+
score += 120;
|
|
83
|
+
reasons.push(`device-id:${deviceId}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const titleTokens = tokenize(node.title).filter((token) => !isGenericToken(token));
|
|
87
|
+
const overlap = titleTokens.filter((token) => sourceTokens.has(token));
|
|
88
|
+
if (overlap.length > 0) {
|
|
89
|
+
score += overlap.reduce((sum, token) => sum + (token.length <= 3 ? 12 : 18), 0);
|
|
90
|
+
reasons.push(`title:${overlap.slice(0, 5).join(',')}`);
|
|
91
|
+
}
|
|
92
|
+
const manufacturerMatches = identity.manufacturers.filter((manufacturer) => includesIdentity(lower, manufacturer));
|
|
93
|
+
if (manufacturerMatches.length > 0) {
|
|
94
|
+
score += 28;
|
|
95
|
+
reasons.push(`manufacturer:${manufacturerMatches[0]}`);
|
|
96
|
+
}
|
|
97
|
+
const relatedEntityMatches = identity.relatedEntityTokens.filter((token) => sourceTokens.has(token));
|
|
98
|
+
if (relatedEntityMatches.length > 0) {
|
|
99
|
+
score += Math.min(50, relatedEntityMatches.length * 10);
|
|
100
|
+
reasons.push(`related-entity:${relatedEntityMatches.slice(0, 5).join(',')}`);
|
|
101
|
+
}
|
|
102
|
+
if (node.kind === 'ha_device' && isManualLikeSource(source))
|
|
103
|
+
score += 16;
|
|
104
|
+
if (node.kind === 'ha_integration' && isIntegrationDocumentationSource(source))
|
|
105
|
+
score += 40;
|
|
106
|
+
if (node.kind === 'ha_integration' && isManualLikeSource(source))
|
|
107
|
+
score -= 45;
|
|
108
|
+
return { node, score, reasons };
|
|
109
|
+
})
|
|
110
|
+
.filter((entry) => entry.score > 0)
|
|
111
|
+
.sort((left, right) => right.score - left.score || left.node.id.localeCompare(right.node.id));
|
|
112
|
+
}
|
|
113
|
+
function shouldSkipAutoLink(source) {
|
|
114
|
+
const kind = typeof source.metadata.homeGraphSourceKind === 'string' ? source.metadata.homeGraphSourceKind : '';
|
|
115
|
+
return kind === 'snapshot' || kind === 'generated-page';
|
|
116
|
+
}
|
|
117
|
+
function hasActiveSourceLink(sourceId, edges) {
|
|
118
|
+
return edges.some((edge) => edgeIsActive(edge) && ((edge.fromKind === 'source' && edge.fromId === sourceId && edge.toKind === 'node')
|
|
119
|
+
|| (edge.fromKind === 'node' && edge.toKind === 'source' && edge.toId === sourceId)));
|
|
120
|
+
}
|
|
121
|
+
function isAutoLinkCandidateNode(node) {
|
|
122
|
+
return node.kind === 'ha_device'
|
|
123
|
+
|| node.kind === 'ha_entity'
|
|
124
|
+
|| node.kind === 'ha_integration'
|
|
125
|
+
|| node.kind === 'ha_area'
|
|
126
|
+
|| node.kind === 'ha_room';
|
|
127
|
+
}
|
|
128
|
+
function sourceEvidenceText(source, extraction) {
|
|
129
|
+
const structure = readRecord(extraction?.structure);
|
|
130
|
+
return uniqueStrings([
|
|
131
|
+
source.title,
|
|
132
|
+
source.summary,
|
|
133
|
+
source.description,
|
|
134
|
+
source.sourceUri,
|
|
135
|
+
source.canonicalUri,
|
|
136
|
+
source.tags.join(' '),
|
|
137
|
+
extraction?.title,
|
|
138
|
+
extraction?.summary,
|
|
139
|
+
extraction?.excerpt,
|
|
140
|
+
...(extraction?.sections ?? []),
|
|
141
|
+
readString(structure.searchText),
|
|
142
|
+
]).join('\n').slice(0, MAX_TEXT_FIELD_CHARS);
|
|
143
|
+
}
|
|
144
|
+
function nodeIdentity(node, state) {
|
|
145
|
+
const homeAssistant = readRecord(node.metadata.homeAssistant);
|
|
146
|
+
const relatedEntities = node.kind === 'ha_device'
|
|
147
|
+
? relatedEntityNodes(node.id, state)
|
|
148
|
+
: [];
|
|
149
|
+
return {
|
|
150
|
+
models: uniqueStrings([
|
|
151
|
+
readString(node.metadata.model),
|
|
152
|
+
readString(node.metadata.modelId),
|
|
153
|
+
readString(node.metadata.model_id),
|
|
154
|
+
]),
|
|
155
|
+
manufacturers: uniqueStrings([
|
|
156
|
+
readString(node.metadata.manufacturer),
|
|
157
|
+
readString(node.metadata.vendor),
|
|
158
|
+
]),
|
|
159
|
+
entityIds: uniqueStrings([
|
|
160
|
+
readString(homeAssistant.entityId),
|
|
161
|
+
...relatedEntities.map((entity) => readString(readRecord(entity.metadata.homeAssistant).entityId)),
|
|
162
|
+
]),
|
|
163
|
+
deviceIds: uniqueStrings([
|
|
164
|
+
readString(homeAssistant.deviceId),
|
|
165
|
+
node.kind === 'ha_device' ? readString(homeAssistant.objectId) : undefined,
|
|
166
|
+
]),
|
|
167
|
+
relatedEntityTokens: uniqueStrings(relatedEntities.flatMap((entity) => [
|
|
168
|
+
...tokenize(entity.title),
|
|
169
|
+
...tokenize(readString(readRecord(entity.metadata.homeAssistant).entityId) ?? ''),
|
|
170
|
+
readString(entity.metadata.domain),
|
|
171
|
+
readString(entity.metadata.platform),
|
|
172
|
+
])),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function relatedEntityNodes(deviceNodeId, state) {
|
|
176
|
+
const entityIds = new Set(state.edges.filter((edge) => (edgeIsActive(edge)
|
|
177
|
+
&& edge.fromKind === 'node'
|
|
178
|
+
&& edge.toKind === 'node'
|
|
179
|
+
&& edge.toId === deviceNodeId
|
|
180
|
+
&& edge.relation === 'belongs_to_device')).map((edge) => edge.fromId));
|
|
181
|
+
return state.nodes.filter((node) => entityIds.has(node.id) && node.kind === 'ha_entity');
|
|
182
|
+
}
|
|
183
|
+
function inferRelation(source) {
|
|
184
|
+
const tags = source.tags.map((tag) => tag.toLowerCase());
|
|
185
|
+
const text = [source.sourceType, source.title, source.sourceUri, ...tags].join(' ').toLowerCase();
|
|
186
|
+
if (text.includes('receipt'))
|
|
187
|
+
return 'has_receipt';
|
|
188
|
+
if (text.includes('warranty'))
|
|
189
|
+
return 'has_warranty';
|
|
190
|
+
if (isManualLikeSource(source))
|
|
191
|
+
return 'has_manual';
|
|
192
|
+
return 'source_for';
|
|
193
|
+
}
|
|
194
|
+
function isManualLikeSource(source) {
|
|
195
|
+
const tags = source.tags.map((tag) => tag.toLowerCase());
|
|
196
|
+
const text = [source.sourceType, source.title, source.sourceUri, ...tags].join(' ').toLowerCase();
|
|
197
|
+
return source.sourceType === 'manual'
|
|
198
|
+
|| tags.includes('manual')
|
|
199
|
+
|| tags.includes('artifact')
|
|
200
|
+
|| tags.includes('document')
|
|
201
|
+
|| /\bmanual\b|\.pdf\b|owner.?s guide|user guide/.test(text);
|
|
202
|
+
}
|
|
203
|
+
function isIntegrationDocumentationSource(source) {
|
|
204
|
+
const tags = source.tags.map((tag) => tag.toLowerCase());
|
|
205
|
+
const kind = typeof source.metadata.homeGraphSourceKind === 'string'
|
|
206
|
+
? source.metadata.homeGraphSourceKind.toLowerCase()
|
|
207
|
+
: '';
|
|
208
|
+
return tags.includes('integration') || tags.includes('documentation') || kind === 'documentation-candidate';
|
|
209
|
+
}
|
|
210
|
+
function tokenize(value) {
|
|
211
|
+
return uniqueStrings(value.toLowerCase().split(/[^a-z0-9_.:-]+/).filter((token) => token.length >= 2));
|
|
212
|
+
}
|
|
213
|
+
function isGenericToken(value) {
|
|
214
|
+
return GENERIC_TOKENS.has(value);
|
|
215
|
+
}
|
|
216
|
+
function includesIdentity(haystack, identity) {
|
|
217
|
+
const normalized = identity.trim().toLowerCase();
|
|
218
|
+
if (!normalized)
|
|
219
|
+
return false;
|
|
220
|
+
if (/^[a-z0-9_.:-]+$/.test(normalized)) {
|
|
221
|
+
return new RegExp(`(?:^|[^a-z0-9])${escapeRegExp(normalized)}(?:$|[^a-z0-9])`).test(haystack);
|
|
222
|
+
}
|
|
223
|
+
return haystack.includes(normalized);
|
|
224
|
+
}
|
|
225
|
+
function readString(value) {
|
|
226
|
+
if (typeof value === 'string') {
|
|
227
|
+
const trimmed = value.trim();
|
|
228
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
229
|
+
}
|
|
230
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
231
|
+
return String(value);
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
function escapeRegExp(value) {
|
|
235
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
236
|
+
}
|
|
@@ -10,6 +10,7 @@ interface HomeGraphPageContext {
|
|
|
10
10
|
export declare function generateAutomaticHomeGraphPages(context: HomeGraphPageContext & {
|
|
11
11
|
readonly input: HomeGraphSnapshotInput;
|
|
12
12
|
}): Promise<HomeGraphGeneratedPagesSummary>;
|
|
13
|
+
export declare function refreshAutomaticHomeGraphPages(context: HomeGraphPageContext): Promise<HomeGraphGeneratedPagesSummary>;
|
|
13
14
|
export declare function refreshHomeGraphDevicePassport(context: HomeGraphPageContext & {
|
|
14
15
|
readonly input: HomeGraphProjectionInput;
|
|
15
16
|
}): Promise<HomeGraphDevicePassportResult & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/generated-pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8BlD,OAAO,KAAK,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;CAAE,GACzE,OAAO,CAAC,8BAA8B,CAAC,
|
|
1
|
+
{"version":3,"file":"generated-pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/generated-pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8BlD,OAAO,KAAK,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;CAAE,GACzE,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AAED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AA2ED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,6BAA6B,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CA0EhF;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAsC5E;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAyB5E"}
|
|
@@ -3,13 +3,19 @@ import { HOME_GRAPH_CONNECTOR_ID, buildHomeGraphMetadata, edgeIsActive, homeGrap
|
|
|
3
3
|
import { findHomeAssistantNode, missingDevicePassportFields, readHomeGraphState, renderHomeGraphState, safeHomeGraphFilename, sourcesLinkedToNode, } from './state.js';
|
|
4
4
|
import { renderDevicePassportPage, renderPacketPage, renderRoomPage, } from './rendering.js';
|
|
5
5
|
export async function generateAutomaticHomeGraphPages(context) {
|
|
6
|
-
|
|
6
|
+
return generateHomeGraphPagesForCurrentState(context, context.input.pageAutomation ?? {});
|
|
7
|
+
}
|
|
8
|
+
export async function refreshAutomaticHomeGraphPages(context) {
|
|
9
|
+
return generateHomeGraphPagesForCurrentState(context, {});
|
|
10
|
+
}
|
|
11
|
+
async function generateHomeGraphPagesForCurrentState(context, options) {
|
|
12
|
+
const effectiveOptions = options ?? {};
|
|
7
13
|
const summary = createGeneratedPagesSummary();
|
|
8
|
-
if (
|
|
14
|
+
if (effectiveOptions.enabled === false)
|
|
9
15
|
return summary;
|
|
10
16
|
const state = readHomeGraphState(context.store, context.spaceId);
|
|
11
|
-
if (
|
|
12
|
-
const devices = limitRecords(state.nodes.filter((node) => node.kind === 'ha_device' && node.status !== 'stale').sort(compareByTitle),
|
|
17
|
+
if (effectiveOptions.devicePassports !== false) {
|
|
18
|
+
const devices = limitRecords(state.nodes.filter((node) => node.kind === 'ha_device' && node.status !== 'stale').sort(compareByTitle), effectiveOptions.maxDevicePassports);
|
|
13
19
|
for (const device of devices) {
|
|
14
20
|
const deviceId = readHomeAssistantObjectId(device, 'objectId', 'deviceId') ?? device.id;
|
|
15
21
|
try {
|
|
@@ -36,10 +42,10 @@ export async function generateAutomaticHomeGraphPages(context) {
|
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
|
-
if (
|
|
45
|
+
if (effectiveOptions.roomPages !== false) {
|
|
40
46
|
const rooms = limitRecords(state.nodes
|
|
41
47
|
.filter((node) => (node.kind === 'ha_area' || node.kind === 'ha_room') && node.status !== 'stale')
|
|
42
|
-
.sort(compareByTitle),
|
|
48
|
+
.sort(compareByTitle), effectiveOptions.maxRoomPages);
|
|
43
49
|
for (const room of rooms) {
|
|
44
50
|
const areaId = readHomeAssistantObjectId(room, 'objectId', 'areaId') ?? room.id;
|
|
45
51
|
try {
|
|
@@ -109,7 +115,7 @@ export async function refreshHomeGraphDevicePassport(context) {
|
|
|
109
115
|
relation: 'source_for',
|
|
110
116
|
metadata: buildHomeGraphMetadata(spaceId, installationId),
|
|
111
117
|
});
|
|
112
|
-
const markdown = renderDevicePassportPage({ spaceId, device, entities, sources, issues, missingFields });
|
|
118
|
+
const markdown = renderDevicePassportPage({ spaceId, device, entities, sources, extractions: state.extractions, issues, missingFields });
|
|
113
119
|
const generated = await materializeGeneratedMarkdown({
|
|
114
120
|
store,
|
|
115
121
|
artifactStore,
|
|
@@ -147,7 +153,7 @@ export async function generateHomeGraphRoomPage(context) {
|
|
|
147
153
|
const state = readHomeGraphState(store, spaceId);
|
|
148
154
|
const areaId = input.areaId ?? input.roomId;
|
|
149
155
|
const title = input.title ?? resolveRoomTitle(state.nodes, areaId) ?? 'Home Graph Room';
|
|
150
|
-
const markdown = renderRoomPage({ ...state, title }, areaId);
|
|
156
|
+
const markdown = renderRoomPage({ ...state, title, extractions: state.extractions }, areaId);
|
|
151
157
|
const filename = `${safeHomeGraphFilename(title)}.md`;
|
|
152
158
|
const targetNode = areaId
|
|
153
159
|
? findHomeAssistantNode(state.nodes, 'ha_area', areaId) ?? findHomeAssistantNode(state.nodes, 'ha_room', areaId)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { HomeGraphService } from './service.js';
|
|
2
2
|
export { HOME_GRAPH_NODE_KINDS, HOME_GRAPH_RELATIONS, } from './types.js';
|
|
3
|
-
export type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphGeneratedPagesSummary, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphKnowledgeTarget, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapEdge, HomeGraphMapHaFilterInput, HomeGraphMapInput, HomeGraphMapNode, HomeGraphMapResult, HomeGraphNodeKind, HomeGraphObjectInput, HomeGraphObjectKind, HomeGraphPageAutomationOptions, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReindexResult, HomeGraphRelation, HomeGraphReviewInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult, } from './types.js';
|
|
3
|
+
export type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphGeneratedPagesSummary, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphKnowledgeTarget, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapEdge, HomeGraphMapHaFilterInput, HomeGraphMapInput, HomeGraphMapNode, HomeGraphMapResult, HomeGraphNodeKind, HomeGraphObjectInput, HomeGraphObjectKind, HomeGraphPageAutomationOptions, HomeGraphPageListResult, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReindexResult, HomeGraphRelation, HomeGraphReviewInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult, } from './types.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,6BAA6B,EAC7B,eAAe,EACf,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,6BAA6B,EAC7B,eAAe,EACf,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ArtifactStore } from '../../artifacts/index.js';
|
|
2
|
+
import type { KnowledgeSourceRecord } from '../types.js';
|
|
3
|
+
import type { HomeGraphPageListResult } from './types.js';
|
|
4
|
+
export declare function listHomeGraphPages(input: {
|
|
5
|
+
readonly artifactStore: ArtifactStore;
|
|
6
|
+
readonly spaceId: string;
|
|
7
|
+
readonly sources: readonly KnowledgeSourceRecord[];
|
|
8
|
+
readonly limit: number;
|
|
9
|
+
readonly includeMarkdown: boolean;
|
|
10
|
+
}): Promise<HomeGraphPageListResult>;
|
|
11
|
+
//# sourceMappingURL=pages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA0BnC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isGeneratedPageSource } from './helpers.js';
|
|
2
|
+
export async function listHomeGraphPages(input) {
|
|
3
|
+
const pages = [];
|
|
4
|
+
const sources = input.sources
|
|
5
|
+
.filter(isGeneratedPageSource)
|
|
6
|
+
.sort(compareGeneratedPages)
|
|
7
|
+
.slice(0, input.limit);
|
|
8
|
+
for (const source of sources) {
|
|
9
|
+
const artifact = typeof source.artifactId === 'string' ? input.artifactStore.get(source.artifactId) : undefined;
|
|
10
|
+
const markdown = input.includeMarkdown && artifact
|
|
11
|
+
? await readMarkdown(input.artifactStore, artifact.id)
|
|
12
|
+
: undefined;
|
|
13
|
+
pages.push({
|
|
14
|
+
source,
|
|
15
|
+
...(artifact ? {
|
|
16
|
+
artifact: {
|
|
17
|
+
id: artifact.id,
|
|
18
|
+
mimeType: artifact.mimeType,
|
|
19
|
+
filename: artifact.filename,
|
|
20
|
+
createdAt: artifact.createdAt,
|
|
21
|
+
metadata: artifact.metadata,
|
|
22
|
+
},
|
|
23
|
+
} : {}),
|
|
24
|
+
...(markdown ? { markdown } : {}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return { ok: true, spaceId: input.spaceId, pages };
|
|
28
|
+
}
|
|
29
|
+
function compareGeneratedPages(left, right) {
|
|
30
|
+
const leftKind = typeof left.metadata.projectionKind === 'string' ? left.metadata.projectionKind : '';
|
|
31
|
+
const rightKind = typeof right.metadata.projectionKind === 'string' ? right.metadata.projectionKind : '';
|
|
32
|
+
return leftKind.localeCompare(rightKind)
|
|
33
|
+
|| (left.title ?? left.id).localeCompare(right.title ?? right.id)
|
|
34
|
+
|| left.id.localeCompare(right.id);
|
|
35
|
+
}
|
|
36
|
+
async function readMarkdown(artifactStore, artifactId) {
|
|
37
|
+
try {
|
|
38
|
+
const { buffer } = await artifactStore.readContent(artifactId);
|
|
39
|
+
return buffer.toString('utf-8');
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { KnowledgeEdgeRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
1
|
+
import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
2
2
|
import type { HomeGraphMapInput, HomeGraphMapResult } from './types.js';
|
|
3
3
|
export interface HomeGraphRenderState {
|
|
4
4
|
readonly spaceId: string;
|
|
@@ -7,6 +7,7 @@ export interface HomeGraphRenderState {
|
|
|
7
7
|
readonly nodes: readonly KnowledgeNodeRecord[];
|
|
8
8
|
readonly edges: readonly KnowledgeEdgeRecord[];
|
|
9
9
|
readonly issues: readonly KnowledgeIssueRecord[];
|
|
10
|
+
readonly extractions?: readonly KnowledgeExtractionRecord[];
|
|
10
11
|
}
|
|
11
12
|
export declare function renderRoomPage(state: HomeGraphRenderState, areaId?: string): string;
|
|
12
13
|
export declare function renderDevicePassportPage(input: {
|
|
@@ -14,6 +15,7 @@ export declare function renderDevicePassportPage(input: {
|
|
|
14
15
|
readonly device: KnowledgeNodeRecord;
|
|
15
16
|
readonly entities: readonly KnowledgeNodeRecord[];
|
|
16
17
|
readonly sources: readonly KnowledgeSourceRecord[];
|
|
18
|
+
readonly extractions?: readonly KnowledgeExtractionRecord[];
|
|
17
19
|
readonly issues: readonly KnowledgeIssueRecord[];
|
|
18
20
|
readonly missingFields: readonly string[];
|
|
19
21
|
}): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAEpB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EAEpB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAA6B,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnG,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAiDnF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,MAAM,CA8BT;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,GAAG,MAAM,CAkBd;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE,iBAAsB,GAAG,kBAAkB,CAcnH"}
|