Merge the capture and dialogue sweep (#241)
One bug with teeth. capture.windowBytes computed int64(window.Seconds()) * bytesPerSecond, truncating to whole seconds. A sub-second window came out as zero bytes, which transcribeFile reads as no window, so it hands the transcriber the entire recording in one call. Multiplied in float now. One drifted comment. Peek said expired entries below the top are left alone. The code deletes the whole stack, which is what Pop and TakeExpired both document. The corrected comment also names the ordering the silent drop depends on: TakeExpired must run before Peek on a turn, or the expiry notice is unreachable. Two default TTL literals became DefaultClarifyTTL and DefaultSessionTTL, beside the existing DefaultMaxAttempts. PendingQuestion was not gofmt clean. Push and Pop are unused outside tests and stay. Push documents itself as the widening V-561 fills in, and the stack tests cover it. Neither package holds a Russian stem pattern. The only Russian strings are two markers and two prompts, and none of them routes or becomes a fact. (V-581)
This commit is contained in:
@@ -626,6 +626,9 @@ func windowBytes(f audio.Format, window time.Duration) int64 {
|
||||
if bps <= 0 || f.SampleRate <= 0 || window <= 0 {
|
||||
return 0
|
||||
}
|
||||
per := int64(window.Seconds()) * bytesPerSecond(f)
|
||||
// Fractional seconds count. Truncating the window to whole seconds turned
|
||||
// any sub-second window into zero bytes, which the caller reads as "no
|
||||
// window" and answers by handing the transcriber the entire meeting at once.
|
||||
per := int64(window.Seconds() * float64(bytesPerSecond(f)))
|
||||
return per - per%bps
|
||||
}
|
||||
|
||||
@@ -193,9 +193,7 @@ func ChunkText(text string, maxRunes int) []string {
|
||||
// Oversized sentence: emit what is buffered, then cut this one on
|
||||
// word boundaries.
|
||||
flush()
|
||||
for _, piece := range splitWords(sr, maxRunes) {
|
||||
out = append(out, piece)
|
||||
}
|
||||
out = append(out, splitWords(sr, maxRunes)...)
|
||||
continue
|
||||
}
|
||||
if len(cur)+len(sr) > maxRunes {
|
||||
|
||||
@@ -37,8 +37,8 @@ type PendingQuestion struct {
|
||||
// request rather than alone: "завтра" names a day for an hour said earlier.
|
||||
WhenText string
|
||||
Asked time.Time
|
||||
TTL time.Duration
|
||||
Attempts int // questions already asked
|
||||
TTL time.Duration
|
||||
Attempts int // questions already asked
|
||||
// MaxAttempts caps Attempts. 0 ⇒ DefaultMaxAttempts.
|
||||
MaxAttempts int
|
||||
}
|
||||
@@ -104,11 +104,14 @@ type ClarifyStore struct {
|
||||
// reply can carry.
|
||||
const MaxStackDepth = 2
|
||||
|
||||
// DefaultClarifyTTL — how long a parked question stays his answer to give.
|
||||
// Short, like confirmTTL in voice.go: a clarifying question is a same-breath
|
||||
// gesture, and a stale one should not eat a later utterance.
|
||||
const DefaultClarifyTTL = 90 * time.Second
|
||||
|
||||
func NewClarifyStore(defaultTTL time.Duration) *ClarifyStore {
|
||||
if defaultTTL <= 0 {
|
||||
// Short, like confirmTTL in voice.go: a clarifying question is a
|
||||
// same-breath gesture, a stale one should not eat a later utterance.
|
||||
defaultTTL = 90 * time.Second
|
||||
defaultTTL = DefaultClarifyTTL
|
||||
}
|
||||
return &ClarifyStore{
|
||||
stacks: make(map[string][]*PendingQuestion),
|
||||
@@ -151,9 +154,15 @@ func (s *ClarifyStore) Push(id string, q *PendingQuestion) *PendingQuestion {
|
||||
return dropped
|
||||
}
|
||||
|
||||
// Peek returns the live question on top, or nil when there is none. Expired
|
||||
// entries below it are left alone: TakeExpired is what reports those, and
|
||||
// dropping one here would be the silent death this store is careful about.
|
||||
// Peek returns the live question on top, or nil when there is none. An expired
|
||||
// top takes the whole stack with it, exactly as Pop does: the clock that killed
|
||||
// it has been running for everything underneath too.
|
||||
//
|
||||
// That drop is silent, which is the death this store is otherwise careful
|
||||
// about, so TakeExpired has to run BEFORE Peek on a turn — it is what counts the
|
||||
// dropped questions and tells him they are gone. cmd/mavend/voice.go calls
|
||||
// clarifyExpiredNotice first for that reason, and reordering the two makes the
|
||||
// notice unreachable rather than wrong.
|
||||
func (s *ClarifyStore) Peek(id string, now time.Time) *PendingQuestion {
|
||||
s.mu.RLock()
|
||||
stack := s.stacks[id]
|
||||
|
||||
@@ -87,9 +87,14 @@ type SessionStore struct {
|
||||
persist SessionPersister // may be nil: memory only (tests, no-store paths)
|
||||
}
|
||||
|
||||
// DefaultSessionTTL — how long a turn stays available to inherit from. Longer
|
||||
// than DefaultClarifyTTL because this is not a question waiting on an answer:
|
||||
// it is the last thing said, and a follow-up may land after a real pause.
|
||||
const DefaultSessionTTL = 2 * time.Minute
|
||||
|
||||
func NewSessionStore(defaultTTL time.Duration) *SessionStore {
|
||||
if defaultTTL <= 0 {
|
||||
defaultTTL = 2 * time.Minute
|
||||
defaultTTL = DefaultSessionTTL
|
||||
}
|
||||
return &SessionStore{
|
||||
sessions: make(map[string]*Session),
|
||||
|
||||
Reference in New Issue
Block a user