Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e12816ebd | |||
| 8f64f8fb30 | |||
| b3ff3991c4 | |||
| a4ea387c98 | |||
| 68fbf74a23 |
@@ -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 909
|
versionCode 10000
|
||||||
versionName "0.0.9.9"
|
versionName "0.1.0.0"
|
||||||
// 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.0.9.9",
|
"version": "0.1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
@@ -202,14 +202,19 @@ class PhoneCallService {
|
|||||||
audioService.endCallPause();
|
audioService.endCallPause();
|
||||||
wakeWordService.resumeFromCall().catch(() => {});
|
wakeWordService.resumeFromCall().catch(() => {});
|
||||||
ToastAndroid.show(toast, ToastAndroid.SHORT);
|
ToastAndroid.show(toast, ToastAndroid.SHORT);
|
||||||
// Auto-Resume: ab gemerkter Position weiterspielen wenn ARIA vor dem
|
// 800ms warten bevor Auto-Resume — sonst kollidiert ARIA's neuer Focus-
|
||||||
// Anruf gerade redete. Wartet bis zu 30s auf den WAV-Cache (falls
|
// Request mit Spotify's Auto-Resume nach Anruf-Ende. System haengt nach
|
||||||
// final-Marker erst nach dem Anruf-Ende kam).
|
// dem Auflegen noch im IN_CALL-Mode-Uebergang, Spotify schaut auf Focus-
|
||||||
audioService.resumeFromInterruption(30000).then(ok => {
|
// Gain und wuerde sofort wieder LOSS sehen → bleibt pausiert.
|
||||||
if (ok) {
|
// Mit Delay: Spotify resumed kurz, dann pausiert ARIA wieder ordnungs-
|
||||||
console.log('[PhoneCall] Auto-Resume von gemerkter Position gestartet');
|
// gemaess. Wenn ARIA nichts pending hat, bleibt Spotify einfach an.
|
||||||
}
|
setTimeout(() => {
|
||||||
}).catch(() => {});
|
audioService.resumeFromInterruption(30000).then(ok => {
|
||||||
|
if (ok) {
|
||||||
|
console.log('[PhoneCall] Auto-Resume von gemerkter Position gestartet');
|
||||||
|
}
|
||||||
|
}).catch(() => {});
|
||||||
|
}, 800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-2
@@ -786,13 +786,29 @@ class ARIABridge:
|
|||||||
await self._emit_activity("idle", "")
|
await self._emit_activity("idle", "")
|
||||||
if not text:
|
if not text:
|
||||||
logger.warning("[core] chat final ohne Text: %s", json.dumps(payload)[:200])
|
logger.warning("[core] chat final ohne Text: %s", json.dumps(payload)[:200])
|
||||||
|
# App+Diagnostic informieren statt stumm — sonst wartet die
|
||||||
|
# UI ewig auf eine Antwort die nicht kommt. Passiert z.B.
|
||||||
|
# wenn Claude-Vision das Bild ablehnt (leere Antwort)
|
||||||
|
# oder die Antwort nur aus Tool-Calls ohne Final-Text bestand.
|
||||||
|
await self._send_to_rvs({
|
||||||
|
"type": "chat",
|
||||||
|
"payload": {
|
||||||
|
"text": "[Hinweis] Antwort ohne Text — moeglicherweise Bild zu gross fuer Vision-API oder reine Tool-Ausfuehrung.",
|
||||||
|
"sender": "aria",
|
||||||
|
},
|
||||||
|
"timestamp": int(asyncio.get_event_loop().time() * 1000),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
logger.info("[core] Antwort: '%s'", text[:80])
|
logger.info("[core] Antwort: '%s'", text[:80])
|
||||||
await self._process_core_response(text, payload)
|
await self._process_core_response(text, payload)
|
||||||
return
|
return
|
||||||
|
|
||||||
if state == "error":
|
if state == "error":
|
||||||
error = payload.get("error", "Unbekannt")
|
# OpenClaw nutzt errorMessage statt error bei state=error.
|
||||||
|
error = (payload.get("error")
|
||||||
|
or payload.get("errorMessage")
|
||||||
|
or payload.get("message")
|
||||||
|
or "Unbekannt")
|
||||||
logger.error("[core] Chat-Fehler: %s", error)
|
logger.error("[core] Chat-Fehler: %s", error)
|
||||||
self._last_chat_final_at = asyncio.get_event_loop().time()
|
self._last_chat_final_at = asyncio.get_event_loop().time()
|
||||||
await self._emit_activity("idle", "")
|
await self._emit_activity("idle", "")
|
||||||
@@ -828,7 +844,12 @@ class ARIABridge:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if event_name == "chat:error":
|
if event_name == "chat:error":
|
||||||
error = payload.get("error", payload.get("message", "Unbekannt"))
|
# OpenClaw legt den echten Text manchmal in errorMessage ab
|
||||||
|
# (state=error). Vorher wurde nur error/message gechecked → "Unbekannt".
|
||||||
|
error = (payload.get("error")
|
||||||
|
or payload.get("errorMessage")
|
||||||
|
or payload.get("message")
|
||||||
|
or "Unbekannt")
|
||||||
logger.error("[core] Chat-Fehler (legacy): %s", error)
|
logger.error("[core] Chat-Fehler (legacy): %s", error)
|
||||||
await self._send_to_rvs({
|
await self._send_to_rvs({
|
||||||
"type": "chat",
|
"type": "chat",
|
||||||
@@ -1465,6 +1486,31 @@ class ARIABridge:
|
|||||||
size_kb = len(file_b64) // 1365
|
size_kb = len(file_b64) // 1365
|
||||||
logger.info("[rvs] Datei gespeichert: %s (%dKB)", file_path, size_kb)
|
logger.info("[rvs] Datei gespeichert: %s (%dKB)", file_path, size_kb)
|
||||||
|
|
||||||
|
# Pixel-Bilder fuer Claude-Vision shrinken wenn > 2 MB. SVG/PDF/ZIP
|
||||||
|
# bleiben unangetastet (Vision laeuft eh nur auf Raster-Formaten).
|
||||||
|
CLAUDE_VISION_FORMATS = ("image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif")
|
||||||
|
if file_type.lower() in CLAUDE_VISION_FORMATS:
|
||||||
|
file_size_bytes = os.path.getsize(file_path)
|
||||||
|
if file_size_bytes > 2 * 1024 * 1024:
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
with Image.open(file_path) as img:
|
||||||
|
orig_w, orig_h = img.size
|
||||||
|
# Anthropic-Empfehlung: max 1568px lange Seite. RGB-Konvertierung
|
||||||
|
# falls RGBA/Palette (JPEG braucht RGB).
|
||||||
|
img.thumbnail((1568, 1568), Image.Resampling.LANCZOS)
|
||||||
|
if img.mode in ("RGBA", "P"):
|
||||||
|
img = img.convert("RGB")
|
||||||
|
img.save(file_path, "JPEG", quality=85, optimize=True)
|
||||||
|
new_size_bytes = os.path.getsize(file_path)
|
||||||
|
logger.info("[rvs] Bild verkleinert: %dx%d → %dx%d, %.1fMB → %.1fMB",
|
||||||
|
orig_w, orig_h, img.size[0], img.size[1],
|
||||||
|
file_size_bytes / 1024 / 1024,
|
||||||
|
new_size_bytes / 1024 / 1024)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("[rvs] Bild-Resize fehlgeschlagen (%s) — Original wird genutzt: %s",
|
||||||
|
file_name, e)
|
||||||
|
|
||||||
# In Pending-Queue + Flush-Timer (anti-spam Buffering)
|
# In Pending-Queue + Flush-Timer (anti-spam Buffering)
|
||||||
self._pending_files.append((file_path, file_name, file_type, size_kb, int(width or 0), int(height or 0)))
|
self._pending_files.append((file_path, file_name, file_type, size_kb, int(width or 0), int(height or 0)))
|
||||||
if self._pending_files_flush_task and not self._pending_files_flush_task.done():
|
if self._pending_files_flush_task and not self._pending_files_flush_task.done():
|
||||||
|
|||||||
@@ -16,3 +16,6 @@ sounddevice
|
|||||||
|
|
||||||
# Wake-Word Erkennung
|
# Wake-Word Erkennung
|
||||||
openwakeword
|
openwakeword
|
||||||
|
|
||||||
|
# Bild-Resizing (zu grosse Pixel-Bilder shrinken bevor Claude-Vision sie sieht — 5MB-Limit)
|
||||||
|
Pillow
|
||||||
|
|||||||
Reference in New Issue
Block a user