gsd-pi 0.3.3 → 2.3.5
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/dist/loader.js +0 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme.js +949 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -0
- package/package.json +1 -1
- package/src/resources/extensions/google-search/index.ts +323 -0
- package/src/resources/extensions/google-search/package.json +9 -0
- package/src/resources/extensions/voice/index.ts +27 -9
- package/src/resources/extensions/voice/speech-recognizer.swift +83 -5
- package/src/resources/extensions/voice/speech-recognizer +0 -0
|
@@ -45,15 +45,93 @@ do {
|
|
|
45
45
|
exit(1)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
// Accumulated finalized text from previous recognition segments.
|
|
49
|
+
// On-device recognition (especially macOS/iOS 18+) can reset
|
|
50
|
+
// bestTranscription.formattedString after a pause, discarding
|
|
51
|
+
// previous text. We detect this by tracking the last known good
|
|
52
|
+
// text and noticing when the new text is shorter / doesn't start
|
|
53
|
+
// with the previous text. When that happens we treat the previous
|
|
54
|
+
// text as finalized and start accumulating the new segment on top.
|
|
55
|
+
var accumulated = ""
|
|
56
|
+
var lastPartialText = ""
|
|
57
|
+
var lastEmitted = ""
|
|
49
58
|
|
|
50
59
|
recognizer.recognitionTask(with: request) { result, error in
|
|
51
60
|
if let result = result {
|
|
52
61
|
let text = result.bestTranscription.formattedString
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
|
|
63
|
+
if result.isFinal {
|
|
64
|
+
// True final from the recognizer — commit everything
|
|
65
|
+
let full: String
|
|
66
|
+
// Check if the final text already includes accumulated content
|
|
67
|
+
// (some OS versions give cumulative finals, others reset)
|
|
68
|
+
if !accumulated.isEmpty && !text.lowercased().hasPrefix(accumulated.lowercased()) {
|
|
69
|
+
full = accumulated + " " + text
|
|
70
|
+
} else if !accumulated.isEmpty && text.count < accumulated.count {
|
|
71
|
+
// Final is shorter than what we accumulated — use accumulated + new
|
|
72
|
+
full = accumulated + " " + text
|
|
73
|
+
} else {
|
|
74
|
+
full = text
|
|
75
|
+
}
|
|
76
|
+
accumulated = ""
|
|
77
|
+
lastPartialText = ""
|
|
78
|
+
if full != lastEmitted {
|
|
79
|
+
lastEmitted = full
|
|
80
|
+
print("FINAL:\(full)")
|
|
81
|
+
}
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Detect transcription reset: if the new partial text is significantly
|
|
86
|
+
// shorter than what we had, or doesn't start with the previous text,
|
|
87
|
+
// the recognizer has reset after a pause. Finalize what we had.
|
|
88
|
+
let prevText = lastPartialText
|
|
89
|
+
if !prevText.isEmpty && !text.isEmpty {
|
|
90
|
+
let prevWords = prevText.split(separator: " ")
|
|
91
|
+
let newWords = text.split(separator: " ")
|
|
92
|
+
|
|
93
|
+
// Reset detection: new text has fewer words than previous AND
|
|
94
|
+
// the first few words don't match (i.e. it's truly new speech,
|
|
95
|
+
// not just the recognizer revising the last word)
|
|
96
|
+
let looksLikeReset: Bool
|
|
97
|
+
if newWords.count < prevWords.count / 2 {
|
|
98
|
+
// Significant drop in word count — likely a reset
|
|
99
|
+
looksLikeReset = true
|
|
100
|
+
} else if newWords.count < prevWords.count &&
|
|
101
|
+
!prevWords.isEmpty && !newWords.isEmpty &&
|
|
102
|
+
newWords[0] != prevWords[0] {
|
|
103
|
+
// Different starting word + fewer words — reset
|
|
104
|
+
looksLikeReset = true
|
|
105
|
+
} else {
|
|
106
|
+
looksLikeReset = false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if looksLikeReset {
|
|
110
|
+
// Commit the previous partial text to accumulated
|
|
111
|
+
if accumulated.isEmpty {
|
|
112
|
+
accumulated = prevText
|
|
113
|
+
} else {
|
|
114
|
+
accumulated = accumulated + " " + prevText
|
|
115
|
+
}
|
|
116
|
+
// Emit a FINAL for the committed text so the TS side updates
|
|
117
|
+
print("FINAL:\(accumulated)")
|
|
118
|
+
lastEmitted = accumulated
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
lastPartialText = text
|
|
123
|
+
|
|
124
|
+
// Build the full display text
|
|
125
|
+
let displayText: String
|
|
126
|
+
if accumulated.isEmpty {
|
|
127
|
+
displayText = text
|
|
128
|
+
} else {
|
|
129
|
+
displayText = accumulated + " " + text
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if displayText != lastEmitted {
|
|
133
|
+
lastEmitted = displayText
|
|
134
|
+
print("PARTIAL:\(displayText)")
|
|
57
135
|
}
|
|
58
136
|
}
|
|
59
137
|
if let error = error {
|
|
Binary file
|