Add site definition worker inference
This commit is contained in:
parent
134157bc71
commit
3ccdaaf953
17 changed files with 250 additions and 50 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { DefinitionEngine, matchesUrlPattern, selectDefinition } from "../src/content/definition-engine";
|
||||
import { DefinitionEngine, hasPotentialDefinitionForUrl, matchesUrlPattern, selectDefinition, selectDefinitionForUrl } from "../src/content/definition-engine";
|
||||
import { BUILTIN_DEFINITIONS } from "../src/content/definitions";
|
||||
import type { SiteDefinition } from "../src/shared/types";
|
||||
|
||||
|
|
@ -84,6 +84,17 @@ describe("DefinitionEngine", () => {
|
|||
expect(posts.map((post) => post.text)).toEqual(["first threads post with visible text", "a reply in the conversation"]);
|
||||
});
|
||||
|
||||
it("discovers Threads detail-page posts from pagelet containers", () => {
|
||||
document.body.innerHTML = readFileSync("tests/fixtures/threads-post-page.html", "utf8");
|
||||
const threads = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "threads")!;
|
||||
const posts = new DefinitionEngine(threads).discover(document);
|
||||
expect(posts.map((post) => post.id)).toEqual([
|
||||
"threads:http://localhost:3000/@alice/post/ABC123",
|
||||
"threads:http://localhost:3000/@bob/post/DEF456"
|
||||
]);
|
||||
expect(posts.map((post) => post.text)).toEqual(["the main post on the threads detail page", "a reply on the threads detail page"]);
|
||||
});
|
||||
|
||||
it("selects Threads on current and legacy domains", () => {
|
||||
const threads = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "threads")!;
|
||||
document.body.innerHTML = '<div role="article" data-pressable-container="true"></div>';
|
||||
|
|
@ -92,4 +103,23 @@ describe("DefinitionEngine", () => {
|
|||
}
|
||||
expect(selectDefinition([threads], "https://example.com/home")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("can identify a specific site while its SPA markers are still loading", () => {
|
||||
const threads = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "threads")!;
|
||||
document.body.innerHTML = "";
|
||||
expect(selectDefinition([threads], "https://www.threads.com/")).toBeUndefined();
|
||||
expect(selectDefinitionForUrl([BUILTIN_DEFINITIONS[0]!, threads], "https://www.threads.com/")).toBe(threads);
|
||||
});
|
||||
|
||||
it("keeps broad definitions pending until their hydration markers appear", () => {
|
||||
const mastodon = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "mastodon")!;
|
||||
const threads = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "threads")!;
|
||||
document.body.innerHTML = "";
|
||||
expect(selectDefinition([mastodon], "https://mastodon.example/@user")).toBeUndefined();
|
||||
expect(selectDefinitionForUrl([mastodon], "https://mastodon.example/@user")).toBeUndefined();
|
||||
expect(hasPotentialDefinitionForUrl([mastodon], "https://mastodon.example/@user")).toBe(true);
|
||||
expect(hasPotentialDefinitionForUrl([threads], "https://example.com/")).toBe(false);
|
||||
document.body.innerHTML = '<div class="status"><div class="status__content">Ready</div></div>';
|
||||
expect(selectDefinition([mastodon], "https://mastodon.example/@user")).toBe(mastodon);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
10
tests/fixtures/threads-post-page.html
vendored
Normal file
10
tests/fixtures/threads-post-page.html
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<main>
|
||||
<div data-pagelet="threads_post_page_0">
|
||||
<a href="/@alice/post/ABC123"><span dir="auto">12h</span></a>
|
||||
<span dir="auto">The main post on the Threads detail page</span>
|
||||
</div>
|
||||
<div data-pagelet="threads_post_page_1">
|
||||
<a href="/@bob/post/DEF456"><span dir="auto">1h</span></a>
|
||||
<span dir="auto">A reply on the Threads detail page</span>
|
||||
</div>
|
||||
</main>
|
||||
50
tests/inference-worker.test.ts
Normal file
50
tests/inference-worker.test.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { InferenceWorkerHost, type InferenceWorker } from "../src/background/inference-worker";
|
||||
import type { InferenceRequest } from "../src/shared/types";
|
||||
|
||||
const request: InferenceRequest = { id: "post", text: "text", site: "threads", navigationId: "nav", priority: 0, requestId: "request" };
|
||||
class FakeWorker implements InferenceWorker {
|
||||
readonly listeners = new Map<string, EventListener[]>();
|
||||
readonly requests: Array<{ requests: InferenceRequest[]; modelBaseUrl: string }> = [];
|
||||
terminated = false;
|
||||
|
||||
addEventListener(type: "message" | "error", listener: EventListener): void {
|
||||
this.listeners.set(type, [...(this.listeners.get(type) ?? []), listener]);
|
||||
}
|
||||
|
||||
removeEventListener(type: "message" | "error", listener: EventListener): void {
|
||||
this.listeners.set(type, (this.listeners.get(type) ?? []).filter((candidate) => candidate !== listener));
|
||||
}
|
||||
|
||||
postMessage(message: { requests: InferenceRequest[]; modelBaseUrl: string }): void {
|
||||
this.requests.push(message);
|
||||
}
|
||||
|
||||
terminate(): void { this.terminated = true; }
|
||||
|
||||
reply(): void {
|
||||
const event = new MessageEvent("message", { data: { results: [{ requestId: request.requestId, id: request.id, textHash: "hash", label: "not_toxic", probability: .1, navigationId: request.navigationId }] } });
|
||||
this.listeners.get("message")?.forEach((listener) => listener(event));
|
||||
}
|
||||
}
|
||||
|
||||
describe("InferenceWorkerHost", () => {
|
||||
it("reuses its worker", async () => {
|
||||
const workers: FakeWorker[] = [];
|
||||
const host = new InferenceWorkerHost(() => {
|
||||
const worker = new FakeWorker();
|
||||
workers.push(worker);
|
||||
return worker;
|
||||
}, "chrome-extension://id/models/toxicity/");
|
||||
|
||||
const first = host.run([request]);
|
||||
workers[0]!.reply();
|
||||
await first;
|
||||
const second = host.run([request]);
|
||||
workers[0]!.reply();
|
||||
await second;
|
||||
expect(workers).toHaveLength(1);
|
||||
|
||||
expect(workers[0]!.requests).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { setDefinitionPaused } from "../src/shared/settings";
|
||||
import { mergeSettings, setDefinitionPaused } from "../src/shared/settings";
|
||||
import { DEFAULT_SETTINGS } from "../src/shared/types";
|
||||
|
||||
describe("definition pause settings", () => {
|
||||
|
|
@ -18,3 +18,10 @@ describe("definition pause settings", () => {
|
|||
expect(settings.disabledDefinitionIds).toEqual(["mastodon"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("legacy settings", () => {
|
||||
it("removes legacy inference settings", () => {
|
||||
expect(mergeSettings({ cpuThreads: 99 })).not.toHaveProperty("cpuThreads");
|
||||
expect(mergeSettings({ inferenceDevice: "webgpu" } as never)).not.toHaveProperty("inferenceDevice");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue