Experiment to rebuild Diffuse using web applets.
0

Configure Feed

Select the types of activity you want to include in your feed.

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