feat(caption): let live captions use their own speech model

The speech engine now keeps an auxiliary model next to the dictation model
and transcribes with whichever the request names, reloading it once if the
engine restarted. Settings > STT gains a live-caption model so captions can
run on large-v3-turbo while dictation keeps its own model. The runtime
minimum rises to 1.7.0 because older engines would silently ignore the
model choice.

Suggestion paging moves to Up/Down: the page follows the selection and the
last item waits while more candidates are being generated. The Left/Right
page shortcuts are removed; they did nothing until a page had filled and
clash with Intel's display-rotation hotkeys.
This commit is contained in:
Yun Chan 2026-09-24 21:46:54 +09:00
parent 39b8e7448e
commit 4b0f685941
29 changed files with 222 additions and 234 deletions

View file

@ -1000,6 +1000,7 @@ class SuggestionService extends EventEmitter {
if (token !== this._generationToken || this._isDuplicateCandidate(candidateText)) return false
this._candidates.push({ text: candidateText, rank: this._candidates.length })
logger.debug(`제안 후보 추가 ${this._candidates.length}/${SUGGESTION_DEFAULTS.maxCandidatesTotal}`)
this._armVisibleTtl()
this.emit('updated', this.getState())
this._record({
@ -1176,26 +1177,17 @@ class SuggestionService extends EventEmitter {
return this.getState()
}
/**
* 다음 후보로 — 페이지는 활성 후보를 따라 넘어간다.
*
* 마지막 후보에서 아직 더 만드는 중이면 그 자리에 머문다: 처음으로 돌아가 버리면
* 곧 도착할 후보를 보려던 사용자가 길을 잃는다. 다 만들었으면 처음으로 돌아간다.
*/
next(): SuggestionState {
if (this._candidates.length > 1) {
this._moveActive((this._activeIndex + 1) % this._candidates.length)
}
return this.getState()
}
/** 다음 페이지의 첫 항목으로 — 그 페이지에 후보가 없으면 그대로 둔다. */
pageNext(): SuggestionState {
const pageSize = SUGGESTION_DEFAULTS.pageSize
const totalPages = Math.ceil(this._candidates.length / pageSize)
const currentPage = Math.floor(this._activeIndex / pageSize)
if (currentPage < totalPages - 1) this._moveActive((currentPage + 1) * pageSize)
return this.getState()
}
/** 이전 페이지의 첫 항목으로 — 이미 첫 페이지면 그대로 둔다. */
pagePrev(): SuggestionState {
const currentPage = Math.floor(this._activeIndex / SUGGESTION_DEFAULTS.pageSize)
if (currentPage > 0) this._moveActive((currentPage - 1) * SUGGESTION_DEFAULTS.pageSize)
const last = this._candidates.length - 1
if (last < 1) return this.getState()
if (this._activeIndex < last) this._moveActive(this._activeIndex + 1)
else if (!this._filling) this._moveActive(0)
return this.getState()
}