Ship floating launcher, automatic discovery and bounded media search improvements
This commit is contained in:
1 parent
01279a6b25
commit
521966a2ac
43 files changed
+3165
-267
No files matched your search
@@ -22,6 +22,7 @@ then warms its retained CPU worker before listening on 127.0.0.1:1431.
|
||||
|
||||
```powershell
|
||||
$env:SEARCHI_FORCE_CPU = '1'
|
||||
$env:SEARCHI_EXTRACT_WORKER = (Resolve-Path target/release/searchi-extract-worker.exe).Path
|
||||
cargo run --manifest-path tools/desktop-capture/backend/Cargo.toml -- --root .searchi/readme-capture/files --db .searchi/readme-capture/index.sqlite --models .searchi/models/embeddinggemma2 --worker .searchi/runtime/cpu/Release/searchi-gemma-worker.exe --dist apps/desktop/dist --ffmpeg .searchi/media-runtime/bin/ffmpeg.exe --ffprobe .searchi/media-runtime/bin/ffprobe.exe
|
||||
```
|
||||
|
||||
@@ -46,12 +47,14 @@ loaded fonts, image pixels, and genuine worker inference counters in debug mode.
|
||||
|
||||
## Artifacts and limits
|
||||
|
||||
Outputs under docs/screenshots are search-light.png, search-dark.png,
|
||||
Outputs under docs/screenshots are launcher-empty.png, search-light.png, search-dark.png,
|
||||
media-search.png and performance-details.png, plus capture-manifest.json. The
|
||||
manifest contains actual fixture queries, counts/selection, measured response
|
||||
metrics, device/model, viewport, PNG SHA256, runner/browser versions, Git base
|
||||
commit and dirty-state flag. The base commit does not identify uncommitted
|
||||
source exactly. The ephemeral API token is never saved in the manifest.
|
||||
source exactly. It also records the actual frontend package version and built
|
||||
index SHA-256. The compact empty-bar capture has no manufactured results and
|
||||
uses the genuine ready backend. The ephemeral API token is never saved in the manifest.
|
||||
|
||||
Captures are **browser-rendered production UI with the actual CPU engine**.
|
||||
They omit native window chrome. They do not establish native WebView visual QA,
|
||||
|
||||
Generated
+16
@@ -1129,11 +1129,16 @@ name = "searchi-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"lopdf",
|
||||
"quick-xml",
|
||||
"rusqlite",
|
||||
"searchi-media",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"walkdir",
|
||||
"windows-sys",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -1192,11 +1197,22 @@ dependencies = [
|
||||
"searchi-core",
|
||||
"searchi-media",
|
||||
"searchi-semantic",
|
||||
"searchi-speech",
|
||||
"serde",
|
||||
"sha2 0.10.9",
|
||||
"usearch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "searchi-speech"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
|
||||
@@ -44,6 +44,8 @@ struct Filters {
|
||||
max_duration_ms: Option<u32>,
|
||||
modified_after_unix_ms: Option<i64>,
|
||||
modified_before_unix_ms: Option<i64>,
|
||||
media_artist: Option<String>,
|
||||
media_title: Option<String>,
|
||||
}
|
||||
impl Filters {
|
||||
fn options(self, root: &Path) -> Result<SearchOptions> {
|
||||
@@ -63,6 +65,8 @@ impl Filters {
|
||||
max_duration_ms: self.max_duration_ms,
|
||||
modified_after_unix_ms: self.modified_after_unix_ms,
|
||||
modified_before_unix_ms: self.modified_before_unix_ms,
|
||||
media_artist: self.media_artist,
|
||||
media_title: self.media_title,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -87,6 +91,10 @@ fn main() -> Result<()> {
|
||||
let mut lexical = SearchIndex::open(&args.db)?;
|
||||
validate_database(&args.db, &root)?;
|
||||
lexical.index_folder(&root)?;
|
||||
ensure!(
|
||||
lexical.extracted_source_hash(&root.join("Supplier Agreement.pdf").to_string_lossy())?.is_some(),
|
||||
"Capture PDF was not genuinely extracted; set SEARCHI_EXTRACT_WORKER to the verified document helper"
|
||||
);
|
||||
lexical.prewarm()?;
|
||||
let tools = FfmpegTools::new(args.ffmpeg, args.ffprobe)?;
|
||||
let mut hybrid = HybridSearch::open(&args.db, &args.models, &args.worker, 1)?;
|
||||
@@ -287,7 +295,7 @@ impl App {
|
||||
json!({"model":"Google EmbeddingGemma 2","ready":true,"model_directory":self.models,"worker_ready":true,"downloading":false,"embedding":false,"device_policy":"cpu","error":null,"downloaded_bytes":864676480u64,"total_bytes":864676480u64,"generation":status.generation,"chunks":status.chunks,"stale":status.stale,"pending":status.pending,"warming":false,"worker_info":self.hybrid.worker_info(),"media_tools_ready":true,"media_setup_error":null,"media_failures":status.failures}),
|
||||
)
|
||||
}
|
||||
"search_measured" | "hybrid_search_measured" => {
|
||||
"search_measured" | "hybrid_search_measured" | "semantic_search_raw" => {
|
||||
let query = args["query"].as_str().context("Query required")?;
|
||||
ensure!(query.len() <= 4096, "Query too large");
|
||||
let filters: Filters = if args["filters"].is_null() {
|
||||
@@ -297,7 +305,9 @@ impl App {
|
||||
};
|
||||
let options = filters.options(&self.root)?;
|
||||
let debug = args["debugPerformance"].as_bool().unwrap_or(false);
|
||||
if name == "search_measured" {
|
||||
if name == "semantic_search_raw" {
|
||||
Ok(serde_json::to_value(self.hybrid.search_semantic(query, 50, &options)?)?)
|
||||
} else if name == "search_measured" {
|
||||
Ok(serde_json::to_value(
|
||||
self.lexical
|
||||
.search_with_options_measured(query, 50, &options, debug)?,
|
||||
|
||||
@@ -92,6 +92,28 @@ try {
|
||||
.evaluate((image) => image.complete && image.naturalWidth > 0),
|
||||
"Brand asset failed to load",
|
||||
);
|
||||
// Capture the actual ready/empty production layout before typing. This is
|
||||
// browser-rendered UI, not native window chrome or synthesized app results.
|
||||
await page.waitForFunction(() =>
|
||||
document.documentElement.dataset.launcherLayout === "compact" &&
|
||||
document.querySelector("#query")?.value === "",
|
||||
);
|
||||
const compactPath = resolve(out, "launcher-empty.png");
|
||||
const compactBounds = await page.locator("#app").boundingBox();
|
||||
assert(compactBounds && compactBounds.width <= 720 && compactBounds.height <= 112,
|
||||
"Ready empty launcher must remain a compact bar");
|
||||
await page.locator("#app").screenshot({ path: compactPath, animations: "disabled" });
|
||||
evidence.push({
|
||||
file: "launcher-empty.png",
|
||||
sha256: createHash("sha256").update(await readFile(compactPath)).digest("hex"),
|
||||
query: "",
|
||||
mode: "empty-ready",
|
||||
result_count: 0,
|
||||
selected_filename: null,
|
||||
theme: "light",
|
||||
capture_bounds: compactBounds,
|
||||
state_assertions: { semantic_ready: true, compact_empty_layout: true, native_pixels: false },
|
||||
});
|
||||
async function query(text, debug = false) {
|
||||
const awaited = page.waitForResponse(
|
||||
(response) => {
|
||||
@@ -151,6 +173,10 @@ try {
|
||||
() => !document.querySelector("#preview")?.hidden,
|
||||
);
|
||||
if (text === "cancel the supplier partnership") {
|
||||
assert(
|
||||
!body.results.some((result) => ["Mountain Lake.jpg", "Night Pier.jpg"].includes(result.filename)),
|
||||
"Contract results must not contain the unrelated fixture photos",
|
||||
);
|
||||
assert.equal(
|
||||
latestMeasured.first_filename,
|
||||
"Supplier Agreement.pdf",
|
||||
@@ -225,9 +251,12 @@ try {
|
||||
literal_query_marks: true,
|
||||
actual_page_explanation: true,
|
||||
why_disclosure_collapsed_by_default: true,
|
||||
unrelated_photos_removed: true,
|
||||
};
|
||||
}
|
||||
if (text === "mountains reflected in calm water") {
|
||||
assert(body.results.every((result) => result.match_kind === "semantic_image"),
|
||||
"Visual search shortlist must not contain the unrelated fixture documents");
|
||||
assert.equal(
|
||||
latestMeasured.first_filename,
|
||||
"Mountain Lake.jpg",
|
||||
@@ -238,7 +267,7 @@ try {
|
||||
0,
|
||||
"Meaning-only photo result must not invent word-level alignment",
|
||||
);
|
||||
latestMeasured.ui_checks = { meaning_only_image_has_no_text_marks: true };
|
||||
latestMeasured.ui_checks = { meaning_only_image_has_no_text_marks: true, unrelated_documents_removed: true };
|
||||
}
|
||||
await page.evaluate(
|
||||
() =>
|
||||
@@ -249,8 +278,12 @@ try {
|
||||
}
|
||||
async function screenshot(name, queryText) {
|
||||
assert.deepEqual(failures, [], "Frontend page errors occurred");
|
||||
const pane = await page.locator(".results-pane").boundingBox();
|
||||
const preview = await page.locator("#preview").boundingBox();
|
||||
assert(pane && preview && preview.x >= pane.x + pane.width - 1,
|
||||
"Wide result and preview panes must remain side by side");
|
||||
const path = resolve(out, `${name}.png`);
|
||||
await page.screenshot({ path, animations: "disabled", fullPage: false });
|
||||
await page.locator("#app").screenshot({ path, animations: "disabled" });
|
||||
const selected = await page.locator("#preview-title").innerText();
|
||||
assert.equal(
|
||||
selected,
|
||||
@@ -272,7 +305,9 @@ try {
|
||||
matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light",
|
||||
),
|
||||
summary: await page.locator("#result-summary").innerText(),
|
||||
capture_bounds: await page.locator("#app").boundingBox(),
|
||||
state_assertions: {
|
||||
wide_split_preview: true,
|
||||
semantic_ready: true,
|
||||
hybrid_final: true,
|
||||
image_visible: name === "media-search",
|
||||
@@ -366,6 +401,10 @@ try {
|
||||
{
|
||||
kind: "browser-rendered-production-ui-real-cpu-engine",
|
||||
source,
|
||||
frontend_build: {
|
||||
version: JSON.parse(await readFile(resolve(repository, "apps/desktop/package.json"), "utf8")).version,
|
||||
index_sha256: createHash("sha256").update(await readFile(resolve(repository, "apps/desktop/dist/index.html"))).digest("hex"),
|
||||
},
|
||||
viewport: { width: 1440, height: 1000 },
|
||||
runner: { playwright: "1.64.0", chromium: browser.version() },
|
||||
backend: {
|
||||
|
||||
Reference in new issue
Block a user