Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c224562423 | |||
| 5c07aef526 | |||
| d54d37061f |
@@ -79,8 +79,8 @@ android {
|
||||
applicationId "com.ariacockpit"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 10403
|
||||
versionName "0.1.4.3"
|
||||
versionCode 10405
|
||||
versionName "0.1.4.5"
|
||||
// Fallback fuer Libraries mit Product Flavors
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "aria-cockpit",
|
||||
"version": "0.1.4.3",
|
||||
"version": "0.1.4.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android": "react-native run-android",
|
||||
|
||||
@@ -615,6 +615,10 @@ const ChatScreen: React.FC = () => {
|
||||
mimeType: f.mimeType || '',
|
||||
serverPath: f.serverPath || '',
|
||||
})) as Attachment[];
|
||||
// clientMsgId weiterreichen — Bridge spiegelt sie im chat_backup,
|
||||
// damit wir lokale Bubbles per ID dedupen koennen statt nur per
|
||||
// Text/Timestamp-Heuristik.
|
||||
const cmid = typeof m.clientMsgId === 'string' ? m.clientMsgId : undefined;
|
||||
return {
|
||||
id: nextId(),
|
||||
sender: role as 'user' | 'aria',
|
||||
@@ -622,19 +626,32 @@ const ChatScreen: React.FC = () => {
|
||||
timestamp: m.ts || Date.now(),
|
||||
attachments: attachments.length ? attachments : undefined,
|
||||
backupTs: typeof m.ts === 'number' ? m.ts : undefined,
|
||||
...(cmid && { clientMsgId: cmid }),
|
||||
// Server-Bubble = vom Brain verarbeitet → 'delivered' (✓✓)
|
||||
...(role === 'user' && cmid && { deliveryStatus: 'delivered' as const }),
|
||||
};
|
||||
});
|
||||
const maxTs = incoming.reduce((mx: number, m: any) => Math.max(mx, m.ts || 0), 0);
|
||||
setMessages(prev => {
|
||||
// ClientMsgIds die der Server kennt — lokale Bubbles mit der
|
||||
// gleichen ID werden durch die Server-Version ersetzt.
|
||||
const serverCmids = new Set(
|
||||
fromServer.map(s => s.clientMsgId).filter((x): x is string => !!x)
|
||||
);
|
||||
// Lokal-only Bubbles erkennen + behalten:
|
||||
// - Skill-Created-Notifications (skillCreated gesetzt)
|
||||
// - Laufende Sprachnachrichten ohne STT-Result (audioRequestId
|
||||
// gesetzt UND text leer/Placeholder)
|
||||
// - User-Bubbles deren clientMsgId der Server noch nicht kennt:
|
||||
// z.B. waehrend Reconnect-Race oder solange flushQueuedMessages
|
||||
// noch laeuft. Ohne diesen Schutz haette der history_response
|
||||
// die gerade reaktivierten Offline-Nachrichten geloescht.
|
||||
const localOnly = prev.filter(m =>
|
||||
m.skillCreated ||
|
||||
m.triggerCreated ||
|
||||
m.memorySaved ||
|
||||
(m.audioRequestId && (!m.text || m.text === '🎙 Aufnahme...' || m.text === 'Aufnahme...'))
|
||||
(m.audioRequestId && (!m.text || m.text === '🎙 Aufnahme...' || m.text === 'Aufnahme...')) ||
|
||||
(m.sender === 'user' && m.clientMsgId && !serverCmids.has(m.clientMsgId))
|
||||
);
|
||||
// Server-Stand + lokal-only (chronologisch sortiert)
|
||||
const merged = [...fromServer, ...localOnly].sort((a, b) => a.timestamp - b.timestamp);
|
||||
|
||||
+18
-7
@@ -1319,7 +1319,7 @@ class ARIABridge:
|
||||
await self.send_to_core(text, source="app-file+chat")
|
||||
return True
|
||||
|
||||
async def send_to_core(self, text: str, source: str = "bridge") -> None:
|
||||
async def send_to_core(self, text: str, source: str = "bridge", client_msg_id: Optional[str] = None) -> None:
|
||||
"""Sendet Text an aria-brain (HTTP /chat) und broadcastet die Antwort.
|
||||
|
||||
Nicht-Streaming: wir warten bis Brain fertig ist, dann pushen wir
|
||||
@@ -1333,8 +1333,13 @@ class ARIABridge:
|
||||
logger.info("[brain] chat ← %s '%s'", source, text[:80])
|
||||
|
||||
# User-Nachricht in chat_backup.jsonl loggen — wird beim App-Reconnect
|
||||
# / Diagnostic-Reload als History-Quelle gelesen.
|
||||
self._append_chat_backup({"role": "user", "text": text, "source": source})
|
||||
# / Diagnostic-Reload als History-Quelle gelesen. clientMsgId speichern
|
||||
# damit die App beim chat_history_response ihre lokale Bubble
|
||||
# dedupen kann (sonst verschwindet sie nach Offline→Online-Race).
|
||||
entry: dict = {"role": "user", "text": text, "source": source}
|
||||
if client_msg_id:
|
||||
entry["clientMsgId"] = client_msg_id
|
||||
self._append_chat_backup(entry)
|
||||
|
||||
# agent_activity → thinking. _emit_activity statt direktem _send_to_rvs
|
||||
# damit der State-Cache fuer die spaetere idle-Dedup richtig steht.
|
||||
@@ -1634,7 +1639,9 @@ class ARIABridge:
|
||||
" [BARGE-IN]" if interrupted else "",
|
||||
" [GPS]" if location else "",
|
||||
text[:80])
|
||||
await self.send_to_core(core_text, source="app" + (" [barge-in]" if interrupted else ""))
|
||||
await self.send_to_core(core_text,
|
||||
source="app" + (" [barge-in]" if interrupted else ""),
|
||||
client_msg_id=client_msg_id)
|
||||
return
|
||||
|
||||
if msg_type == "cancel_request":
|
||||
@@ -2234,7 +2241,8 @@ class ARIABridge:
|
||||
" [GPS]" if location else "",
|
||||
f" reqId={audio_request_id[:16]}" if audio_request_id else "")
|
||||
asyncio.create_task(self._process_app_audio(
|
||||
audio_b64, mime_type, interrupted, audio_request_id, location))
|
||||
audio_b64, mime_type, interrupted, audio_request_id, location,
|
||||
client_msg_id=client_msg_id))
|
||||
|
||||
elif msg_type == "stt_response":
|
||||
# Antwort der whisper-bridge auf unseren stt_request
|
||||
@@ -2293,7 +2301,8 @@ class ARIABridge:
|
||||
async def _process_app_audio(self, audio_b64: str, mime_type: str,
|
||||
interrupted: bool = False,
|
||||
audio_request_id: str = "",
|
||||
location: Optional[dict] = None) -> None:
|
||||
location: Optional[dict] = None,
|
||||
client_msg_id: Optional[str] = None) -> None:
|
||||
"""App-Audio → STT → aria-core. Primaer via whisper-bridge (RVS), Fallback lokal.
|
||||
|
||||
interrupted=True wenn der User waehrend ARIA noch sprach/dachte aufgenommen hat
|
||||
@@ -2349,7 +2358,9 @@ class ARIABridge:
|
||||
|
||||
# Dann an Brain — der blockt synchron bis ARIA fertig ist.
|
||||
core_text = self._build_core_text(text, interrupted, location)
|
||||
await self.send_to_core(core_text, source="app-voice" + (" [barge-in]" if interrupted else ""))
|
||||
await self.send_to_core(core_text,
|
||||
source="app-voice" + (" [barge-in]" if interrupted else ""),
|
||||
client_msg_id=client_msg_id)
|
||||
else:
|
||||
logger.info("[rvs] Keine Sprache erkannt — ignoriert")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user