Experiment to rebuild Diffuse using web applets.
1import * as Orama from "@orama/orama";
2// import { pluginQPS } from "@orama/plugin-qps";
3
4import type { Track } from "@applets/core/types";
5import { expose, provide, transfer } from "@scripts/common";
6import { SCHEMA } from "./constants";
7import type { State } from "./types";
8
9////////////////////////////////////////////
10// SETUP
11////////////////////////////////////////////
12
13let state: State = {
14 inserted: new Set<string>(),
15};
16
17// TODO: Generate embeddings plugin
18//
19// I tried this and getting some bundler/vite errors about a default import.
20//
21// const plugin = await pluginEmbeddings({
22// embeddings: {
23// defaultProperty: "embeddings",
24// onInsert: {
25// generate: true,
26// // Properties to use for generating embeddings at insert time.
27// // These properties will be concatenated and used to generate embeddings.
28// properties: ["album", "artist", "title", "year", "kind", "genre"],
29// // verbose: true,
30// },
31// },
32// });
33//
34// TODO:
35//
36// Does not work either.
37// `TypeError: a is undefined`
38//
39// pluginQPS()
40
41const PLUGINS: Orama.OramaPlugin[] = [];
42
43// Search through tracks
44const db = Orama.create({
45 schema: SCHEMA,
46 plugins: PLUGINS,
47
48 // components: {
49 // TODO:
50 // https://docs.orama.com/open-source/usage/insert#remote-document-storing
51 // documentStore: { ... }
52 // },
53});
54
55// 🚀
56
57const actions = {
58 search,
59 supply,
60};
61
62const { tasks } = provide({
63 actions,
64 tasks: actions,
65});
66
67export type Actions = typeof actions;
68export type Tasks = typeof tasks;
69
70////////////////////////////////////////////
71// ACTIONS
72////////////////////////////////////////////
73
74async function search(term: string): Promise<Track[]> {
75 const results = await Orama.search(db, {
76 // mode: "hybrid",
77 term,
78 });
79
80 const tracks = results.hits.map((hit) => hit.document as unknown as Track);
81 return transfer(tracks);
82}
83
84async function supply(tracks: Track[]) {
85 // TODO: Generate a hash based on the track itself,
86 // so we can detect changes to tags or other data.
87
88 const ids = [];
89 const tracksMap: Record<string, Track> = {};
90
91 tracks.forEach((track) => {
92 ids.push(track.id);
93 tracksMap[track.id] = track;
94 });
95
96 const currentSet = state.inserted;
97 const newSet = new Set(tracks.map((t) => t.id));
98
99 const removedIds = currentSet.difference(newSet);
100 const newIds = newSet.difference(currentSet);
101 const newTracks = Array.from(newIds).map((id) => tracksMap[id]);
102
103 await Orama.removeMultiple(db, Array.from(removedIds));
104 await Orama.insertMultiple(db, newTracks);
105
106 state.inserted = newSet;
107}