Skip to content

Commit 40d929d

Browse files
authored
ENG-800 handle update embeddings button (#510)
* handle update embeddings button * 1. Fix query to get imported nodes edit data 2. remove isabled arg 3. Fix getAllDiscourseNodesSince to get nodes per node type, use map to store and get non duplicate data 4. getNodesByType * remove success banner for suggestive mode, send error email on fail, fix on load check if we need to initialize by default (#527) * remove success banner for suggestive mode, send error email on fail, fix on load check if we need to initialize by default * address coderabbit review * address review * address review * remove console log * use logged in client * remove supabase based guarding * remove unused
1 parent 6721a47 commit 40d929d

File tree

8 files changed

+177
-123
lines changed

8 files changed

+177
-123
lines changed

apps/roam/src/components/settings/DiscourseNodeSuggestiveRules.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import TextPanel from "roamjs-components/components/ConfigPanels/TextPanel";
1212
import getSubTree from "roamjs-components/util/getSubTree";
1313
import { DiscourseNode } from "~/utils/getDiscourseNodes";
1414
import extractRef from "roamjs-components/util/extractRef";
15+
import { getAllDiscourseNodesSince } from "~/utils/getAllDiscourseNodesSince";
16+
import { upsertNodesToSupabaseAsContentWithEmbeddings } from "~/utils/syncDgNodesToSupabase";
17+
import { discourseNodeBlockToLocalConcept } from "~/utils/conceptConversion";
18+
import { getLoggedInClient, getSupabaseContext } from "~/utils/supabaseContext";
1519

1620
const BlockRenderer = ({ uid }: { uid: string }) => {
1721
const containerRef = useRef<HTMLDivElement>(null);
@@ -64,10 +68,34 @@ const DiscourseNodeSuggestiveRules = ({
6468
(e: React.ChangeEvent<HTMLInputElement>) => {
6569
const newValue = e.target.value;
6670
setEmbeddingRef(newValue);
71+
node.embeddingRef = newValue;
6772
},
68-
[],
73+
[node],
6974
);
70-
75+
const [isUpdating, setIsUpdating] = useState(false);
76+
77+
const handleUpdateEmbeddings = async (): Promise<void> => {
78+
setIsUpdating(true);
79+
try {
80+
const blockNodesSince = await getAllDiscourseNodesSince(
81+
new Date(0).toISOString(),
82+
[node],
83+
);
84+
const supabaseClient = await getLoggedInClient();
85+
if (!supabaseClient) return;
86+
87+
const context = await getSupabaseContext();
88+
if (context && blockNodesSince) {
89+
await upsertNodesToSupabaseAsContentWithEmbeddings(
90+
blockNodesSince,
91+
supabaseClient,
92+
context,
93+
);
94+
}
95+
} finally {
96+
setIsUpdating(false);
97+
}
98+
};
7199
return (
72100
<div className="flex flex-col gap-4 p-4">
73101
<BlocksPanel
@@ -82,11 +110,10 @@ const DiscourseNodeSuggestiveRules = ({
82110
<TextPanel
83111
title="Embedding Block Ref"
84112
description="Copy block ref from template which you want to be embedded and ranked."
85-
order={0}
113+
order={1}
86114
uid={node.embeddingRefUid || ""}
87115
parentUid={parentUid}
88-
value={node.embeddingRef || ""}
89-
defaultValue={node.embeddingRef || ""}
116+
defaultValue={embeddingRef || ""}
90117
options={{
91118
placeholder: "((block-uid))",
92119
onChange: handleEmbeddingRefChange,
@@ -103,19 +130,18 @@ const DiscourseNodeSuggestiveRules = ({
103130
<FlagPanel
104131
title="First Child"
105132
description="If the block is the first child of the embedding block ref, it will be embedded and ranked."
106-
order={1}
133+
order={2}
107134
uid={node.isFirstChild?.uid || ""}
108135
parentUid={parentUid}
109136
value={node.isFirstChild?.value || false}
110137
/>
111138

112-
{/* TODO: Add a button to update embeddings in seperate PR */}
113139
<Button
114140
text="Update Embeddings"
115141
intent={Intent.NONE}
116-
onClick={() => console.log("Not implemented")}
142+
onClick={() => void handleUpdateEmbeddings()}
143+
loading={isUpdating}
117144
className="w-52"
118-
disabled
119145
/>
120146
</div>
121147
);

apps/roam/src/components/settings/SuggestiveModeSettings.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ const SuggestiveModeSettings = () => {
111111
});
112112
try {
113113
await createOrUpdateDiscourseEmbedding();
114+
await createBlock({
115+
parentUid: settings.settingsUid,
116+
node: { text: "(BETA) Suggestive Mode Enabled" },
117+
});
114118
} catch (e) {
115119
console.error("Failed to generate embeddings", e);
116120
renderToast({

apps/roam/src/index.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ import {
3232
setSyncActivity,
3333
} from "./utils/syncDgNodesToSupabase";
3434
import { initPluginTimer } from "./utils/pluginTimer";
35+
import { getUidAndBooleanSetting } from "./utils/getExportSettings";
36+
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
37+
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
38+
import { DISCOURSE_CONFIG_PAGE_TITLE } from "./utils/renderNodeConfigPage";
3539

3640
const initPostHog = () => {
3741
posthog.init("phc_SNMmBqwNfcEpNduQ41dBUjtGNEUEKAy6jTn63Fzsrax", {
@@ -126,7 +130,16 @@ export default runExtension(async (onloadArgs) => {
126130
document.addEventListener("input", discourseNodeSearchTriggerListener);
127131
document.addEventListener("selectionchange", nodeCreationPopoverListener);
128132

129-
await initializeSupabaseSync();
133+
const isSuggestiveModeEnabled = getUidAndBooleanSetting({
134+
tree: getBasicTreeByParentUid(
135+
getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE),
136+
),
137+
text: "(BETA) Suggestive Mode Enabled",
138+
}).value;
139+
140+
if (isSuggestiveModeEnabled) {
141+
initializeSupabaseSync();
142+
}
130143

131144
const { extensionAPI } = onloadArgs;
132145
window.roamjs.extension.queryBuilder = {

apps/roam/src/utils/conceptConversion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const getNodeExtraData = (
2626
[?block :create/user ?author_id]
2727
[?author_id :user/uid ?author_uid]
2828
[?block :create/time ?created]
29-
[?block :edit/time ?last_modified]
29+
[(get-else $ ?block :edit/time ?created) ?last_modified]
3030
[(get-else $ ?block :block/page ?block) ?page_id]
3131
[?page_id :block/uid ?page_uid]
3232
]`,

apps/roam/src/utils/discourseConfigRef.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type FormattedConfigTree = {
4545
suggestiveMode: SuggestiveModeConfigWithUids;
4646
leftSidebar: LeftSidebarConfig;
4747
leftSidebarEnabled: BooleanSetting;
48+
suggestiveModeEnabled: BooleanSetting;
4849
};
4950

5051
export const getFormattedConfigTree = (): FormattedConfigTree => {
@@ -77,6 +78,10 @@ export const getFormattedConfigTree = (): FormattedConfigTree => {
7778
tree: configTreeRef.tree,
7879
text: "(BETA) Left Sidebar",
7980
}),
81+
suggestiveModeEnabled: getUidAndBooleanSetting({
82+
tree: configTreeRef.tree,
83+
text: "(BETA) Suggestive Mode",
84+
}),
8085
};
8186
};
8287
export default configTreeRef;

apps/roam/src/utils/getAllDiscourseNodesSince.ts

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import getDiscourseNodes, { type DiscourseNode } from "./getDiscourseNodes";
2-
import findDiscourseNode from "./findDiscourseNode";
1+
import { type DiscourseNode } from "./getDiscourseNodes";
32
import getDiscourseNodeFormatExpression from "./getDiscourseNodeFormatExpression";
43
import { extractRef } from "roamjs-components/util";
54

@@ -23,10 +22,10 @@ export type DiscourseNodesSinceResult = {
2322
blockNodes: RoamDiscourseNodeData[];
2423
};
2524

26-
export const getDiscourseNodeTypeWithSettingsBlockNodes = (
25+
export const getDiscourseNodeTypeWithSettingsBlockNodes = async (
2726
node: DiscourseNode,
2827
sinceMs: number,
29-
): RoamDiscourseNodeData[] => {
28+
): Promise<RoamDiscourseNodeData[]> => {
3029
const regex = getDiscourseNodeFormatExpression(node.format);
3130
const regexPattern = regex.source.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3231
const firstChildUid = extractRef(node.embeddingRef);
@@ -40,30 +39,32 @@ export const getDiscourseNodeTypeWithSettingsBlockNodes = (
4039
[(re-find ?title-regex ?node-title)]
4140
[?node :block/uid ?nodeUid]
4241
[?node :create/time ?nodeCreateTime]
43-
[?node :edit/time ?nodeEditTime]
42+
[(get-else $ ?node :edit/time ?nodeCreateTime) ?nodeEditTime]
4443
[?s :block/uid ?firstChildUid]
4544
[?s :block/string ?firstChildString]
4645
[?bg :block/page ?node]
4746
[?bg :block/string ?firstChildString]
4847
[?bg :block/children ?child]
4948
[?child :block/order 0]
5049
[?child :block/string ?childString]
51-
[?child :edit/time ?childEditTime]
50+
[(get-else $ ?child :edit/time ?nodeCreateTime) ?childEditTime]
5251
[?child :create/user ?user-eid]
5352
[?user-eid :user/uid ?author_local_id]
54-
[?child :edit/user ?eu]
55-
[?eu :user/display-name ?author_name]
53+
[(get-else $ ?child :edit/user ?user-eid) ?eu]
54+
[(get-else $ ?eu :user/display-name "Anonymous User") ?author_name]
5655
[or
5756
[(> ?childEditTime ?since)]
5857
[(> ?nodeEditTime ?since)]]
5958
]`;
6059

61-
const blockNode = window.roamAlphaAPI.data.q(
62-
queryBlock,
63-
String(firstChildUid),
64-
String(node.type),
65-
sinceMs,
66-
) as unknown as RoamDiscourseNodeData[];
60+
const blockNode = (await Promise.resolve(
61+
window.roamAlphaAPI.data.backend.q(
62+
queryBlock,
63+
String(firstChildUid),
64+
String(node.type),
65+
sinceMs,
66+
),
67+
)) as unknown as RoamDiscourseNodeData[];
6768
return blockNode;
6869
};
6970

@@ -72,65 +73,60 @@ export const getAllDiscourseNodesSince = async (
7273
nodeTypes: DiscourseNode[],
7374
): Promise<RoamDiscourseNodeData[]> => {
7475
const sinceMs = new Date(since).getTime();
75-
const result: RoamDiscourseNodeData[] = [];
76+
const resultMap = new Map<string, RoamDiscourseNodeData>();
7677

77-
const query = `[
78+
await Promise.all(
79+
nodeTypes.map(async (node) => {
80+
const regex = getDiscourseNodeFormatExpression(node.format);
81+
const regexPattern = regex.source
82+
.replace(/\\/g, "\\\\")
83+
.replace(/"/g, '\\"');
7884

79-
:find ?node-title ?uid ?nodeCreateTime ?nodeEditTime ?author_local_id ?author_name
80-
:keys text source_local_id created last_modified author_local_id author_name
81-
:in $ ?since
82-
:where
83-
[?node :node/title ?node-title]
84-
[?node :block/uid ?uid]
85-
[?node :create/time ?nodeCreateTime]
86-
[?node :create/user ?user-eid]
87-
[?user-eid :user/uid ?author_local_id]
88-
[(get-else $ ?user-eid :user/display-name "Unknown-Creator") ?author_name]
89-
[(get-else $ ?node :edit/time 0) ?nodeEditTime]
90-
[(get-else $ ?node :edit/time ?nodeCreateTime) ?filterTime]
91-
[(> ?filterTime ?since)]
92-
]`;
93-
const allNodes = (await Promise.resolve(
94-
window.roamAlphaAPI.data.backend.q(query, sinceMs),
95-
)) as unknown as RoamDiscourseNodeData[];
85+
const query = `[
86+
:find ?node-title ?uid ?nodeCreateTime ?nodeEditTime ?author_local_id ?author_name ?type
87+
:keys text source_local_id created last_modified author_local_id author_name type
88+
:in $ ?since ?type
89+
:where
90+
[(re-pattern "${regexPattern}") ?title-regex]
91+
[?node :node/title ?node-title]
92+
[(re-find ?title-regex ?node-title)]
93+
[?node :block/uid ?uid]
94+
[?node :create/time ?nodeCreateTime]
95+
[?node :create/user ?user-eid]
96+
[?user-eid :user/uid ?author_local_id]
97+
[(get-else $ ?user-eid :user/display-name "Anonymous User") ?author_name]
98+
[(get-else $ ?node :edit/time ?nodeCreateTime) ?nodeEditTime]
99+
[(> ?nodeEditTime ?since)]
100+
]`;
96101

97-
const discourseNodes = getDiscourseNodes();
102+
const nodesOfType = (await Promise.resolve(
103+
window.roamAlphaAPI.data.backend.q(query, sinceMs, String(node.type)),
104+
)) as unknown as RoamDiscourseNodeData[];
98105

99-
result.push(
100-
...allNodes.flatMap((entity) => {
101-
if (!entity.source_local_id) {
102-
return [];
103-
}
104-
const node = findDiscourseNode(entity.source_local_id, discourseNodes);
105-
if (
106-
!node ||
107-
node.backedBy === "default" ||
108-
!entity.text ||
109-
entity.text.trim() === ""
110-
) {
111-
return [];
106+
nodesOfType.forEach((n) => {
107+
if (n.source_local_id) {
108+
resultMap.set(n.source_local_id, n);
109+
}
110+
});
111+
112+
const hasBlockSettings =
113+
node.embeddingRef && extractRef(node.embeddingRef);
114+
if (hasBlockSettings) {
115+
const blockNodes = await getDiscourseNodeTypeWithSettingsBlockNodes(
116+
node,
117+
sinceMs,
118+
);
119+
if (blockNodes) {
120+
blockNodes.forEach((blockNode) => {
121+
if (blockNode.source_local_id) {
122+
resultMap.set(blockNode.source_local_id, blockNode);
123+
}
124+
});
125+
}
112126
}
113-
return [
114-
{
115-
...entity,
116-
type: node.type,
117-
},
118-
];
119127
}),
120128
);
121-
122-
if (nodeTypes.length > 0) {
123-
for (const node of nodeTypes) {
124-
const blockNode = getDiscourseNodeTypeWithSettingsBlockNodes(
125-
node,
126-
sinceMs,
127-
);
128-
if (blockNode) {
129-
result.push(...blockNode);
130-
}
131-
}
132-
}
133-
return result;
129+
return Array.from(resultMap.values());
134130
};
135131

136132
export const nodeTypeSince = async (

apps/roam/src/utils/getDiscourseNodes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const getDiscourseNodes = (relations = getDiscourseRelations()) => {
112112
const embeddingBlockRef = getSubTree({
113113
tree: suggestiveRules.children,
114114
key: "Embedding Block Ref",
115-
}).children?.[0];
115+
});
116116

117117
return {
118118
format: getSettingValueFromTree({ tree: children, key: "format" }),
@@ -134,7 +134,7 @@ const getDiscourseNodes = (relations = getDiscourseRelations()) => {
134134
key: "description",
135135
}),
136136
template: getSubTree({ tree: children, key: "template" }).children,
137-
embeddingRef: embeddingBlockRef?.text,
137+
embeddingRef: embeddingBlockRef?.children?.[0]?.text,
138138
embeddingRefUid: embeddingBlockRef?.uid,
139139
isFirstChild: getUidAndBooleanSetting({
140140
tree: suggestiveRules.children,

0 commit comments

Comments
 (0)