Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0350dd33c8 | ||
|
|
7b956c6606 | ||
|
|
36f04f83ff |
@@ -79,8 +79,8 @@ android {
|
|||||||
applicationId "com.ariacockpit"
|
applicationId "com.ariacockpit"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 20304
|
versionCode 20305
|
||||||
versionName "0.2.3.4"
|
versionName "0.2.3.5"
|
||||||
// Fallback fuer Libraries mit Product Flavors
|
// Fallback fuer Libraries mit Product Flavors
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
missingDimensionStrategy 'react-native-camera', 'general'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aria-cockpit",
|
"name": "aria-cockpit",
|
||||||
"version": "0.2.3.4",
|
"version": "0.2.3.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
@@ -152,12 +152,12 @@ export const CONV_WINDOW_MAX_SEC = 20.0;
|
|||||||
export const CONV_WINDOW_STORAGE_KEY = 'aria_conv_window_sec';
|
export const CONV_WINDOW_STORAGE_KEY = 'aria_conv_window_sec';
|
||||||
|
|
||||||
// STT-Endpoint (ms Stille bis "fertig gesprochen"). Zu kurz = schneidet mitten
|
// STT-Endpoint (ms Stille bis "fertig gesprochen"). Zu kurz = schneidet mitten
|
||||||
// im Satz ab, besonders im Auto wo man mit Pausen spricht (Reproduktion: die
|
// im Satz ab, besonders im Auto oder wenn man zum Nachdenken pausiert. 1500 war
|
||||||
// 11.8s-Frage wurde bei "…ohne dass ein" gekappt). 1500 war zu aggressiv;
|
// zu aggressiv; 2400 default, bis 8s hoch stellbar (Denkpausen). In den Settings
|
||||||
// 2400 default, im Auto ggf. hoeher. Konfigurierbar in den Settings.
|
// unter "Stille-Toleranz" konfigurierbar.
|
||||||
export const STT_ENDPOINT_DEFAULT_MS = 2400;
|
export const STT_ENDPOINT_DEFAULT_MS = 2400;
|
||||||
export const STT_ENDPOINT_MIN_MS = 1000;
|
export const STT_ENDPOINT_MIN_MS = 1000;
|
||||||
export const STT_ENDPOINT_MAX_MS = 4000;
|
export const STT_ENDPOINT_MAX_MS = 8000; // bis 8s: genug Zeit zum Ueberlegen
|
||||||
export const STT_ENDPOINT_STORAGE_KEY = 'aria_stt_endpoint_ms';
|
export const STT_ENDPOINT_STORAGE_KEY = 'aria_stt_endpoint_ms';
|
||||||
|
|
||||||
export async function loadSttEndpointMs(): Promise<number> {
|
export async function loadSttEndpointMs(): Promise<number> {
|
||||||
|
|||||||
+12
-30
@@ -121,7 +121,9 @@ class VoxtralRunner:
|
|||||||
)
|
)
|
||||||
inputs = inputs.to(VOXTRAL_DEVICE, dtype=torch.bfloat16)
|
inputs = inputs.to(VOXTRAL_DEVICE, dtype=torch.bfloat16)
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
outputs = model.generate(**inputs, max_new_tokens=512)
|
# hoch genug fuer lange Diktate (stoppt eh am EOS); 512 hat
|
||||||
|
# mehrminutige Aufnahmen abgeschnitten.
|
||||||
|
outputs = model.generate(**inputs, max_new_tokens=4096)
|
||||||
trimmed = outputs[:, inputs.input_ids.shape[1]:]
|
trimmed = outputs[:, inputs.input_ids.shape[1]:]
|
||||||
text = proc.batch_decode(trimmed, skip_special_tokens=True)
|
text = proc.batch_decode(trimmed, skip_special_tokens=True)
|
||||||
return (text[0] if text else "").strip()
|
return (text[0] if text else "").strip()
|
||||||
@@ -284,40 +286,20 @@ class SessionManager:
|
|||||||
return
|
return
|
||||||
if self._buffer_ms(sess) < STREAM_MIN_AUDIO_MS:
|
if self._buffer_ms(sess) < STREAM_MIN_AUDIO_MS:
|
||||||
return
|
return
|
||||||
# adaptive akustische Sprach-Aktivitaet
|
# Adaptive akustische Sprach-Aktivitaet (M0.1). KEINE Live-Partials mehr:
|
||||||
|
# Voxtral-3B transkribiert den ganzen WACHSENDEN Buffer und braucht dafuer
|
||||||
|
# bei langen Aufnahmen 5-6 s — zu langsam fuer Live-Text, UND diese Latenz
|
||||||
|
# hat den semantischen Endpoint faelschlich ausgeloest (Partial-Latenz >
|
||||||
|
# Timeout → willkuerliche Abbrueche nach 20-40 s). Deshalb: Turn-Ende rein
|
||||||
|
# AKUSTISCH, transkribiert wird nur EINMAL im _finalize.
|
||||||
rms = self._tail_rms(sess)
|
rms = self._tail_rms(sess)
|
||||||
if rms >= self._voice_threshold(sess):
|
if rms >= self._voice_threshold(sess):
|
||||||
sess.last_voice_at = now
|
sess.last_voice_at = now
|
||||||
else:
|
else:
|
||||||
self._update_noise_floor(sess, rms)
|
self._update_noise_floor(sess, rms)
|
||||||
# Endpoint-Entscheidung, sobald Text erkannt wurde
|
# Endpoint: hat der User schon gesprochen UND ist es seit endpoint_ms still?
|
||||||
if sess.last_growth_at > 0.0:
|
if sess.last_voice_at > 0 and (now - sess.last_voice_at) * 1000.0 >= sess.endpoint_ms:
|
||||||
ac_sil = (now - sess.last_voice_at) * 1000.0 if sess.last_voice_at > 0 else 0.0
|
await self._finalize(sess, "endpoint")
|
||||||
se_sil = (now - sess.last_growth_at) * 1000.0
|
|
||||||
ac_done = sess.last_voice_at > 0 and ac_sil >= sess.endpoint_ms
|
|
||||||
se_done = se_sil >= sess.endpoint_ms * STREAM_SEMANTIC_BACKUP_FACTOR
|
|
||||||
if ac_done or se_done:
|
|
||||||
await self._finalize(sess, "endpoint" if ac_done else "endpoint_semantic")
|
|
||||||
return
|
|
||||||
# Partial-Transkription (throttled)
|
|
||||||
if (now - sess.last_transcribe_at) * 1000.0 < STREAM_TRANSCRIBE_INTERVAL_MS:
|
|
||||||
return
|
|
||||||
sess.last_transcribe_at = now
|
|
||||||
audio = pcm_s16le_to_float32(bytes(sess.pcm_buffer))
|
|
||||||
try:
|
|
||||||
text = (await self.runner.transcribe(audio, sess.language)).strip()
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Stream %s: Partial-Transcribe crashed", sess.request_id[:8])
|
|
||||||
return
|
|
||||||
if text and text != sess.last_partial:
|
|
||||||
sess.last_partial = text
|
|
||||||
sess.last_growth_at = now
|
|
||||||
if self._ws is not None:
|
|
||||||
await _send(self._ws, "stt_partial", {
|
|
||||||
"requestId": sess.request_id,
|
|
||||||
"audioRequestId": sess.audio_request_id,
|
|
||||||
"text": text,
|
|
||||||
})
|
|
||||||
|
|
||||||
async def _finalize(self, sess: StreamSession, reason: str) -> None:
|
async def _finalize(self, sess: StreamSession, reason: str) -> None:
|
||||||
if sess.endpoint_sent:
|
if sess.endpoint_sent:
|
||||||
|
|||||||
Reference in New Issue
Block a user