@tychenjiajun/pi-voice 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/package.json +1 -1
- package/src/model-picker.ts +17 -8
- package/src/settings-menu.ts +9 -2
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ After ASR produces a transcript, Pi Voice can refine it with the same model (and
|
|
|
64
64
|
Set it up in `/voice-settings` → **Post-processing** → **On**. You then choose the model:
|
|
65
65
|
|
|
66
66
|
- **Pi's current model** (default) — whichever model the agent is using, exactly like compaction;
|
|
67
|
-
- **a different model** — any model from Pi's registry, using that provider's configured authentication.
|
|
67
|
+
- **a different model** — any model from Pi's registry, using that provider's configured authentication. The picker is searchable: type a keyword (a model name or part of `provider/id`) to filter the list, `Enter` selects the highlighted match, and `Esc` clears the search.
|
|
68
68
|
|
|
69
69
|
Pi Voice makes a small nested request through Pi's model registry, so it automatically reuses Pi's model definitions and API keys (or OAuth). No base URL, key, or timeout is stored in Pi Voice settings.
|
|
70
70
|
|
|
@@ -116,6 +116,21 @@ When FFmpeg is unavailable, `transcribe_file` reports platform-specific guidance
|
|
|
116
116
|
|
|
117
117
|
## Changelog
|
|
118
118
|
|
|
119
|
+
### 0.7.0
|
|
120
|
+
|
|
121
|
+
**Added — Searchable post-processing model picker**
|
|
122
|
+
|
|
123
|
+
- `/voice-settings` → **Post-processing** → model now has a search box, so a registry with a thousand-plus models can be narrowed by typing instead of arrowing through the whole list.
|
|
124
|
+
- The search uses the same fuzzy matcher as the transcription model picker (`fuzzyFilter` from `@earendil-works/pi-tui`) and matches the model name as well as `provider/id`, so `wspr` finds `openai/whisper-1` and `claude` finds `anthropic/claude-opus-4-5`.
|
|
125
|
+
- Results are sorted by match quality with the cursor on the best match (Enter picks it), `Esc` clears the search and restores the full list, and the subtitle reminds you that typing filters the models.
|
|
126
|
+
|
|
127
|
+
### 0.6.0
|
|
128
|
+
|
|
129
|
+
**Changed — Fuzzy model search**
|
|
130
|
+
|
|
131
|
+
- The model picker now uses the same fuzzy filter Pi's own model selector uses (`fuzzyFilter` from `@earendil-works/pi-tui`), so typing partial or abbreviated names finds matches that exact substring search could not — e.g. `wspr` matches `whisper-medium`, and `pkrt` matches `parakeet`. Results within each section are also sorted by match quality, putting the best-scoring model at the top.
|
|
132
|
+
- While a search query is active the cursor stays on the best match instead of following a model that may have moved or dropped out of the results, matching Pi's model selector interaction.
|
|
133
|
+
|
|
119
134
|
### 0.5.0
|
|
120
135
|
|
|
121
136
|
**Changed — Exclusive local / remote modes (no fallback)**
|
package/package.json
CHANGED
package/src/model-picker.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "@earendil-works/pi-tui";
|
|
15
15
|
import {
|
|
16
16
|
CATALOG_MODELS,
|
|
17
|
+
catalogModelSearchText,
|
|
17
18
|
canonicalLanguage,
|
|
18
19
|
languageIdentity,
|
|
19
20
|
displayLanguage,
|
|
@@ -32,7 +33,6 @@ import {
|
|
|
32
33
|
import {
|
|
33
34
|
MANUAL_LANGUAGE_TAG,
|
|
34
35
|
ON_DISK_LABEL,
|
|
35
|
-
matchesCatalogSearch,
|
|
36
36
|
modelDetailText,
|
|
37
37
|
modelTableLayout,
|
|
38
38
|
modelTableRow,
|
|
@@ -576,14 +576,19 @@ export class CatalogModelPicker extends Container implements Focusable {
|
|
|
576
576
|
|
|
577
577
|
// The sectioned list: models on disk first, then the ranked catalog with
|
|
578
578
|
// each of them left out, so a model is listed once. A search filters each
|
|
579
|
-
// section in place
|
|
580
|
-
// while a query is on they are a section of their
|
|
581
|
-
// says why it was folded.
|
|
579
|
+
// section in place by fuzzy match quality (best matches first) and reaches
|
|
580
|
+
// the folded models too: while a query is on they are a section of their
|
|
581
|
+
// own, so a match there says why it was folded.
|
|
582
582
|
private buildRows(query: string): ListRow[] {
|
|
583
583
|
const downloaded = this.downloadedModels();
|
|
584
584
|
const onDisk = new Set(downloaded.map((model) => model.id));
|
|
585
|
+
// fuzzyFilter is the same matcher Pi's own model selector uses: each
|
|
586
|
+
// token's characters must appear in order but not consecutively, so typing
|
|
587
|
+
// "wspr" finds "whisper". It also re-sorts each section by match quality so
|
|
588
|
+
// the best-scoring match is at the top, which makes a 1000+ model catalog
|
|
589
|
+
// navigable by typing rather than scrolling.
|
|
585
590
|
const matching = (models: readonly CatalogModel[]) =>
|
|
586
|
-
query ? models
|
|
591
|
+
query ? fuzzyFilter([...models], query, catalogModelSearchText) : models;
|
|
587
592
|
const keep = (models: readonly CatalogModel[]) =>
|
|
588
593
|
matching(models).filter((model) => !onDisk.has(model.id));
|
|
589
594
|
const rows: ListRow[] = [];
|
|
@@ -688,9 +693,13 @@ export class CatalogModelPicker extends Container implements Focusable {
|
|
|
688
693
|
this.body.addChild(this.footer);
|
|
689
694
|
|
|
690
695
|
const query = this.search.getValue().trim();
|
|
691
|
-
// Selecting a model reorders the Downloaded section, so the cursor
|
|
692
|
-
//
|
|
693
|
-
|
|
696
|
+
// Selecting a model reorders the Downloaded section, so the cursor follows
|
|
697
|
+
// the highlighted model rather than its old row number — but only when not
|
|
698
|
+
// searching. While a query is on, handleInput resets selectedIndex to 0
|
|
699
|
+
// on each keystroke, and fuzzyFilter re-sorts every section by match
|
|
700
|
+
// quality, so the best match should stay at the top rather than chasing a
|
|
701
|
+
// model that may have moved or dropped out of the results.
|
|
702
|
+
const highlightedId = query ? undefined : this.highlightedModel()?.id;
|
|
694
703
|
this.rows = this.buildRows(query);
|
|
695
704
|
this.filtered = this.rows.flatMap((row) => (row.type === "model" ? [row.model] : []));
|
|
696
705
|
const followed = highlightedId === undefined
|
package/src/settings-menu.ts
CHANGED
|
@@ -389,7 +389,7 @@ function samePolishModel(
|
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
/** Pick Pi's current model (default) or any model with configured auth. */
|
|
392
|
-
async function choosePolishModel(
|
|
392
|
+
export async function choosePolishModel(
|
|
393
393
|
ctx: ExtensionContext,
|
|
394
394
|
current: PolishModelRef | undefined,
|
|
395
395
|
): Promise<"current" | PolishModelRef | undefined> {
|
|
@@ -423,7 +423,14 @@ async function choosePolishModel(
|
|
|
423
423
|
keybindings,
|
|
424
424
|
choices,
|
|
425
425
|
current ? polishModelKey(current) : "current",
|
|
426
|
-
{
|
|
426
|
+
{
|
|
427
|
+
title: "Post-processing model",
|
|
428
|
+
subtitle: "Type to filter models",
|
|
429
|
+
// The registry can hold a thousand-plus models; arrowing through them
|
|
430
|
+
// is unusable, so the list is fuzzy-searchable like every model picker.
|
|
431
|
+
searchable: true,
|
|
432
|
+
cancelLabel: "back",
|
|
433
|
+
},
|
|
427
434
|
done,
|
|
428
435
|
),
|
|
429
436
|
);
|