summaryrefslogtreecommitdiff
path: root/app/src/lib/categorization.ts
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/lib/categorization.ts')
-rw-r--r--app/src/lib/categorization.ts102
1 files changed, 102 insertions, 0 deletions
diff --git a/app/src/lib/categorization.ts b/app/src/lib/categorization.ts
new file mode 100644
index 0000000..a692240
--- /dev/null
+++ b/app/src/lib/categorization.ts
@@ -0,0 +1,102 @@
+// import { Database } from "bun:sqlite";
+// const db = new Database("data/bookmarks.db", { create: true });
+import { TwitterBookmark } from "./twitter-api";
+
+export interface CategorySuggestion {
+ categories: string[];
+ confidence: number;
+ reasoning: string;
+}
+
+export interface CategorizationRequest {
+ bookmark: TwitterBookmark;
+ userCategories: Array<{ name: string; criteria: string }>;
+}
+
+export interface CategorizationResponse {
+ suggestedCategories: CategorySuggestion[];
+ newCategories: string[];
+ summary: string;
+ keyTopics: string[];
+}
+
+export interface UserCategories {
+ categories: string[];
+}
+
+export const userCategories = [
+ { name: "AI", criteria: "AI, machine learning, LLMs, all AI related stuff" },
+ { name: "Nix", criteria: "Nix and NixOS" },
+ { name: "Urbit", criteria: "anything related to Urbit" },
+ {
+ name: "Code",
+ criteria:
+ "other stuff related to software or software development (excludes the previous)",
+ },
+ { name: "history", criteria: "posts about history or archeology" },
+ { name: "Politics", criteria: "posts about politics" },
+ {
+ name: "China",
+ criteria:
+ "posts about China or in Chinese which don't fall under any other category",
+ },
+ {
+ name: "Japan",
+ criteria:
+ "posts about Japan or in Japanese which don't fall under any other category",
+ },
+ { name: "Movies", criteria: "posts related to movies, anime or TV shows" },
+ { name: "Demographics", criteria: "posts about demographics or birth rates" },
+ { name: "Memes", criteria: "posts including memes or otherwise funny" },
+];
+
+type FileTree = Map<string, FileEntry[]>;
+type FileEntry = { file: string } | { dir: FileTree };
+// type FileTree = { dir: `${string}/`; files: string[]; dirs?: Record<string, FileTree> };
+
+class Obsidian {
+ auth = `Bearer ${Bun.env.OBSIDIAN_API_KEY!}`;
+ url = `http://127.0.0.1:27123`;
+ tree: FileTree = new Map();
+ async getFiles() {}
+ async list() {
+ this.populate(this.tree, "/");
+ }
+ async populate(parent: FileTree, dir: `${string}/`) {
+ const entries: FileEntry[] = [];
+ const res = (await this.call("/vault/" + dir)) as { files: string[] };
+ for (let entry of res.files) {
+ if (entry.endsWith(".md")) entries.push({ file: entry });
+ else if (entry.endsWith("/")) this.populate(new Map(), entry as any);
+ // entries.push({ dir: new Map() });
+ }
+ parent.set(dir, entries);
+ }
+ async call(path: string) {
+ const headers = { Authorization: this.auth };
+ const opts = { headers };
+ const res = await fetch(this.url + path, opts);
+ const j = await res.json();
+ return j;
+ }
+ async post(path: string, body: string) {
+ const headers = { Authorization: this.auth };
+ const opts = { headers, method: "POST", body };
+ const res = await fetch(this.url + path, opts);
+ return res;
+ }
+ async saveToDisk(
+ bookmark: TwitterBookmark,
+ categorization: CategorizationResponse,
+ tags: string[],
+ ) {
+ // append to file
+ const body = `\n\n`;
+ const opts = { method: "POST", headers, body };
+ const res = await this.post("/vault/", body);
+ if (!res.ok) {
+ const j = await res.json();
+ return { error: j.message };
+ } else return { ok: "" };
+ }
+}