Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2475ffef6 | |||
| 98982fea2f | |||
| 356f8b3171 | |||
| b4115bb345 |
@@ -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 10608
|
versionCode 10609
|
||||||
versionName "0.1.6.8"
|
versionName "0.1.6.9"
|
||||||
// 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.1.6.8",
|
"version": "0.1.6.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Modal,
|
Modal,
|
||||||
PermissionsAndroid,
|
PermissionsAndroid,
|
||||||
useWindowDimensions,
|
useWindowDimensions,
|
||||||
|
DeviceEventEmitter,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
import RNFS from 'react-native-fs';
|
import RNFS from 'react-native-fs';
|
||||||
@@ -62,7 +63,7 @@ import MemoryBrowser from '../components/MemoryBrowser';
|
|||||||
import TriggerBrowser from '../components/TriggerBrowser';
|
import TriggerBrowser from '../components/TriggerBrowser';
|
||||||
import SkillBrowser from '../components/SkillBrowser';
|
import SkillBrowser from '../components/SkillBrowser';
|
||||||
import OAuthBrowser from '../components/OAuthBrowser';
|
import OAuthBrowser from '../components/OAuthBrowser';
|
||||||
import { isVerboseLogging, setVerboseLogging } from '../services/logger';
|
import { isVerboseLogging, setVerboseLogging, isDebugLogsToBridge, setDebugLogsToBridge, APP_LOG_EVENT } from '../services/logger';
|
||||||
import {
|
import {
|
||||||
isWakeReadySoundEnabled,
|
isWakeReadySoundEnabled,
|
||||||
setWakeReadySoundEnabled,
|
setWakeReadySoundEnabled,
|
||||||
@@ -160,6 +161,7 @@ const SettingsScreen: React.FC = () => {
|
|||||||
const [apkCacheInfo, setApkCacheInfo] = useState<{count: number, totalMB: number} | null>(null);
|
const [apkCacheInfo, setApkCacheInfo] = useState<{count: number, totalMB: number} | null>(null);
|
||||||
const [ttsCacheInfo, setTtsCacheInfo] = useState<{count: number, totalMB: number} | null>(null);
|
const [ttsCacheInfo, setTtsCacheInfo] = useState<{count: number, totalMB: number} | null>(null);
|
||||||
const [verboseLogging, setVerboseLoggingState] = useState<boolean>(isVerboseLogging());
|
const [verboseLogging, setVerboseLoggingState] = useState<boolean>(isVerboseLogging());
|
||||||
|
const [debugLogsToBridge, setDebugLogsToBridgeState] = useState<boolean>(isDebugLogsToBridge());
|
||||||
const [ttsSpeed, setTtsSpeed] = useState<number>(TTS_SPEED_DEFAULT);
|
const [ttsSpeed, setTtsSpeed] = useState<number>(TTS_SPEED_DEFAULT);
|
||||||
const [wakeKeyword, setWakeKeyword] = useState<string>(DEFAULT_KEYWORD);
|
const [wakeKeyword, setWakeKeyword] = useState<string>(DEFAULT_KEYWORD);
|
||||||
const [wakeStatus, setWakeStatus] = useState<string>('');
|
const [wakeStatus, setWakeStatus] = useState<string>('');
|
||||||
@@ -387,6 +389,19 @@ const SettingsScreen: React.FC = () => {
|
|||||||
setConnLog(prev => [...prev.slice(-99), entry]);
|
setConnLog(prev => [...prev.slice(-99), entry]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Lokale App-Logs (reportAppDebug/Error) im Live-Logs-Tab anzeigen
|
||||||
|
// — damit Stefan ohne curl direkt in der App sieht was passiert.
|
||||||
|
const localLogSub = DeviceEventEmitter.addListener(APP_LOG_EVENT, (e: any) => {
|
||||||
|
const entry: LogEntry = {
|
||||||
|
id: `applog_${e.ts || Date.now()}_${logIdCounter++}`,
|
||||||
|
timestamp: e.ts || Date.now(),
|
||||||
|
source: e.scope || 'app',
|
||||||
|
message: e.message || '',
|
||||||
|
level: e.level || 'info',
|
||||||
|
};
|
||||||
|
setLogs(prev => [...prev.slice(-200), entry]);
|
||||||
|
});
|
||||||
|
|
||||||
const unsubMessage = rvs.onMessage((message: RVSMessage) => {
|
const unsubMessage = rvs.onMessage((message: RVSMessage) => {
|
||||||
if (message.type === 'log') {
|
if (message.type === 'log') {
|
||||||
const entry: LogEntry = {
|
const entry: LogEntry = {
|
||||||
@@ -522,6 +537,7 @@ const SettingsScreen: React.FC = () => {
|
|||||||
unsubState();
|
unsubState();
|
||||||
unsubMessage();
|
unsubMessage();
|
||||||
unsubLog();
|
unsubLog();
|
||||||
|
localLogSub.remove();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -1916,6 +1932,27 @@ const SettingsScreen: React.FC = () => {
|
|||||||
Warnungen und Fehler bleiben immer aktiv. Bei Bedarf einschalten zum
|
Warnungen und Fehler bleiben immer aktiv. Bei Bedarf einschalten zum
|
||||||
Debuggen via adb logcat.
|
Debuggen via adb logcat.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
{/* Debug-Logs an Bridge: scharf nur wenn aktiv gebraucht */}
|
||||||
|
<View style={[styles.toggleRow, {marginTop: 12, borderTopWidth: 1, borderTopColor: '#1E1E2E', paddingTop: 12}]}>
|
||||||
|
<Text style={styles.toggleLabel}>Debug-Logs an Bridge</Text>
|
||||||
|
<Switch
|
||||||
|
value={debugLogsToBridge}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setDebugLogsToBridge(v);
|
||||||
|
setDebugLogsToBridgeState(v);
|
||||||
|
}}
|
||||||
|
trackColor={{ false: '#3A3A52', true: '#FF9500' }}
|
||||||
|
thumbColor={debugLogsToBridge ? '#FFFFFF' : '#666680'}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.toggleHint}>
|
||||||
|
Schickt detaillierte Diagnose-Logs (Wake-Word-Pipeline, Audio-Focus,
|
||||||
|
Background-Service) per RVS an die Bridge — abrufbar via
|
||||||
|
`curl /api/app-log?lines=N` ohne ADB. Default AUS damit kein
|
||||||
|
unnoetiger Traffic + Disk-Schreiben. Crash-Reports (Errors) gehen
|
||||||
|
IMMER, dieser Toggle betrifft nur Info-Logs.
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.card}>
|
<View style={styles.card}>
|
||||||
|
|||||||
@@ -7,10 +7,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
import { Platform } from 'react-native';
|
import { Platform, DeviceEventEmitter } from 'react-native';
|
||||||
import rvs from './rvs';
|
import rvs from './rvs';
|
||||||
|
|
||||||
|
// Lokales Event damit die SettingsScreen Live Logs / Events Tabs
|
||||||
|
// auch das sehen was die App SELBST loggt (reportAppDebug/Error).
|
||||||
|
// Bisher gingen die nur via RVS an die Bridge. Lokal sichtbar = Mama-
|
||||||
|
// tauglich Debug ohne curl.
|
||||||
|
export const APP_LOG_EVENT = 'AriaLocalAppLog';
|
||||||
|
|
||||||
|
interface LocalLogEntry {
|
||||||
|
ts: number;
|
||||||
|
level: 'info' | 'warn' | 'error';
|
||||||
|
scope: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const VERBOSE_LOGGING_KEY = 'aria_verbose_logging';
|
export const VERBOSE_LOGGING_KEY = 'aria_verbose_logging';
|
||||||
|
// Eigener Toggle fuer Debug-Logs die ueber RVS an die Bridge gehen
|
||||||
|
// (/shared/logs/app.log → Diagnostic /api/app-log). Damit der Default-User
|
||||||
|
// nicht stuendlich Traffic + Disk-Schreiben hat, dieser ist DEFAULT AUS.
|
||||||
|
// Stefan schaltet's nur ein wenn er ein konkretes Problem debuggen muss.
|
||||||
|
export const DEBUG_LOGS_TO_BRIDGE_KEY = 'aria_debug_logs_to_bridge';
|
||||||
|
|
||||||
// Original-console.log retten, damit wir die Wrapper jederzeit wieder
|
// Original-console.log retten, damit wir die Wrapper jederzeit wieder
|
||||||
// "scharf" stellen koennen (sonst waere ein Toggle-an nach -aus tot).
|
// "scharf" stellen koennen (sonst waere ein Toggle-an nach -aus tot).
|
||||||
@@ -18,6 +36,7 @@ const originalLog = console.log.bind(console);
|
|||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|
||||||
let _verbose = true;
|
let _verbose = true;
|
||||||
|
let _debugLogsToBridge = false;
|
||||||
|
|
||||||
function applyState(): void {
|
function applyState(): void {
|
||||||
console.log = _verbose ? originalLog : noop;
|
console.log = _verbose ? originalLog : noop;
|
||||||
@@ -29,6 +48,10 @@ export async function initLogger(): Promise<void> {
|
|||||||
const v = await AsyncStorage.getItem(VERBOSE_LOGGING_KEY);
|
const v = await AsyncStorage.getItem(VERBOSE_LOGGING_KEY);
|
||||||
_verbose = v !== 'false'; // default: true
|
_verbose = v !== 'false'; // default: true
|
||||||
} catch {}
|
} catch {}
|
||||||
|
try {
|
||||||
|
const d = await AsyncStorage.getItem(DEBUG_LOGS_TO_BRIDGE_KEY);
|
||||||
|
_debugLogsToBridge = d === 'true'; // default: false
|
||||||
|
} catch {}
|
||||||
applyState();
|
applyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +65,15 @@ export function setVerboseLogging(verbose: boolean): void {
|
|||||||
AsyncStorage.setItem(VERBOSE_LOGGING_KEY, String(verbose)).catch(() => {});
|
AsyncStorage.setItem(VERBOSE_LOGGING_KEY, String(verbose)).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isDebugLogsToBridge(): boolean {
|
||||||
|
return _debugLogsToBridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setDebugLogsToBridge(enabled: boolean): void {
|
||||||
|
_debugLogsToBridge = enabled;
|
||||||
|
AsyncStorage.setItem(DEBUG_LOGS_TO_BRIDGE_KEY, String(enabled)).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
// ─── App-Crash-Reporting via RVS ────────────────────────────────────
|
// ─── App-Crash-Reporting via RVS ────────────────────────────────────
|
||||||
//
|
//
|
||||||
// Wenn die App crasht — egal ob React-Render-Fehler (ErrorBoundary) oder
|
// Wenn die App crasht — egal ob React-Render-Fehler (ErrorBoundary) oder
|
||||||
@@ -61,9 +93,10 @@ let _reportingInstalled = false;
|
|||||||
|
|
||||||
/** Schickt einen App-Fehler via RVS an die Bridge. */
|
/** Schickt einen App-Fehler via RVS an die Bridge. */
|
||||||
export function reportAppError(ev: AppErrorEvent): void {
|
export function reportAppError(ev: AppErrorEvent): void {
|
||||||
|
const ts = Date.now();
|
||||||
try {
|
try {
|
||||||
rvs.send('app_log' as any, {
|
rvs.send('app_log' as any, {
|
||||||
ts: Date.now(),
|
ts,
|
||||||
platform: Platform.OS,
|
platform: Platform.OS,
|
||||||
level: ev.level || 'error',
|
level: ev.level || 'error',
|
||||||
scope: ev.scope,
|
scope: ev.scope,
|
||||||
@@ -73,6 +106,14 @@ export function reportAppError(ev: AppErrorEvent): void {
|
|||||||
} catch {
|
} catch {
|
||||||
// RVS noch nicht connected — Fehler geht im console weiter.
|
// RVS noch nicht connected — Fehler geht im console weiter.
|
||||||
}
|
}
|
||||||
|
// Lokal in den App-Logs-Tab emitten — Errors gehen IMMER durch
|
||||||
|
// (unabhaengig vom Debug-Toggle).
|
||||||
|
try {
|
||||||
|
const entry: LocalLogEntry = {
|
||||||
|
ts, level: ev.level || 'error', scope: ev.scope, message: ev.message,
|
||||||
|
};
|
||||||
|
DeviceEventEmitter.emit(APP_LOG_EVENT, entry);
|
||||||
|
} catch {}
|
||||||
// Plus lokal: console.error, damit Stefan's adb (wenn doch mal verfuegbar)
|
// Plus lokal: console.error, damit Stefan's adb (wenn doch mal verfuegbar)
|
||||||
// den Crash sieht.
|
// den Crash sieht.
|
||||||
console.error(`[app-error scope=${ev.scope}]`, ev.message, '\n', ev.stack || '');
|
console.error(`[app-error scope=${ev.scope}]`, ev.message, '\n', ev.stack || '');
|
||||||
@@ -81,17 +122,31 @@ export function reportAppError(ev: AppErrorEvent): void {
|
|||||||
/** Schickt eine Debug-/Info-Message via RVS an die Bridge. Landet ebenfalls
|
/** Schickt eine Debug-/Info-Message via RVS an die Bridge. Landet ebenfalls
|
||||||
* in /shared/logs/app.log — abrufbar via `curl /api/app-log?lines=N`.
|
* in /shared/logs/app.log — abrufbar via `curl /api/app-log?lines=N`.
|
||||||
* Im Gegensatz zu reportAppError: keine Stacktrace, level=info, kein
|
* Im Gegensatz zu reportAppError: keine Stacktrace, level=info, kein
|
||||||
* console.error. Fuer Live-Diagnose im Hintergrund wenn ADB nicht da ist. */
|
* console.error. Fuer Live-Diagnose im Hintergrund wenn ADB nicht da ist.
|
||||||
|
*
|
||||||
|
* Nur aktiv wenn Settings → Protokoll → Debug-Logs an Bridge AN ist.
|
||||||
|
* Default aus damit Mama-Modus keine Disk-Schreiblast hat. Error-Reports
|
||||||
|
* (reportAppError) gehen weiterhin IMMER durch. */
|
||||||
export function reportAppDebug(scope: string, message: string): void {
|
export function reportAppDebug(scope: string, message: string): void {
|
||||||
|
if (!_debugLogsToBridge) return;
|
||||||
|
const ts = Date.now();
|
||||||
|
const trimmed = String(message).slice(0, 2000);
|
||||||
try {
|
try {
|
||||||
rvs.send('app_log' as any, {
|
rvs.send('app_log' as any, {
|
||||||
ts: Date.now(),
|
ts,
|
||||||
platform: Platform.OS,
|
platform: Platform.OS,
|
||||||
level: 'info',
|
level: 'info',
|
||||||
scope,
|
scope,
|
||||||
message: String(message).slice(0, 2000),
|
message: trimmed,
|
||||||
});
|
});
|
||||||
} catch {}
|
} catch {}
|
||||||
|
// Plus lokal in den App-Logs-Tab emitten — damit Stefan in der App
|
||||||
|
// selbst (Settings → Protokoll → Live Logs) sieht was passiert,
|
||||||
|
// ohne curl gegen Bridge.
|
||||||
|
try {
|
||||||
|
const entry: LocalLogEntry = { ts, level: 'info', scope, message: trimmed };
|
||||||
|
DeviceEventEmitter.emit(APP_LOG_EVENT, entry);
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Installiert einen globalen JS-Error-Handler der ungefangene Errors via
|
/** Installiert einen globalen JS-Error-Handler der ungefangene Errors via
|
||||||
|
|||||||
@@ -242,13 +242,20 @@ class WakeWordService {
|
|||||||
`keyword=${this.keyword} state=${this.state} barge=${this.bargeListening}`)).catch(()=>{});
|
`keyword=${this.keyword} state=${this.state} barge=${this.bargeListening}`)).catch(()=>{});
|
||||||
this.lastTriggerAt = now;
|
this.lastTriggerAt = now;
|
||||||
if (this.nativeReady && OpenWakeWord) {
|
if (this.nativeReady && OpenWakeWord) {
|
||||||
try { await OpenWakeWord.stop(); } catch {}
|
try {
|
||||||
|
await OpenWakeWord.stop();
|
||||||
|
import('./logger').then(m => m.reportAppDebug('wake.detect', 'native stop ok')).catch(()=>{});
|
||||||
|
} catch (e: any) {
|
||||||
|
import('./logger').then(m => m.reportAppDebug('wake.detect', `native stop FAIL ${e?.message}`)).catch(()=>{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.bargeListening = false;
|
this.bargeListening = false;
|
||||||
// Wenn wir bereits in 'conversing' sind und der Trigger waehrend ARIAs TTS
|
// Wenn wir bereits in 'conversing' sind und der Trigger waehrend ARIAs TTS
|
||||||
// kam (Barge-In via Wake-Word), feuern wir einen separaten Callback damit
|
// kam (Barge-In via Wake-Word), feuern wir einen separaten Callback damit
|
||||||
// ChatScreen das TTS abbrechen + neue Aufnahme starten kann. Sonst normal.
|
// ChatScreen das TTS abbrechen + neue Aufnahme starten kann. Sonst normal.
|
||||||
if (this.state === 'conversing') {
|
if (this.state === 'conversing') {
|
||||||
|
import('./logger').then(m => m.reportAppDebug('wake.detect',
|
||||||
|
`barge path: cbs=${this.bargeCallbacks.length}`)).catch(()=>{});
|
||||||
this.bargeCallbacks.forEach(cb => {
|
this.bargeCallbacks.forEach(cb => {
|
||||||
try { cb(); } catch (e) { console.warn('[WakeWord] barge cb err:', e); }
|
try { cb(); } catch (e) { console.warn('[WakeWord] barge cb err:', e); }
|
||||||
});
|
});
|
||||||
@@ -256,7 +263,11 @@ class WakeWordService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState('conversing');
|
this.setState('conversing');
|
||||||
|
import('./logger').then(m => m.reportAppDebug('wake.detect',
|
||||||
|
`state→conversing, wakeCallbacks.length=${this.wakeCallbacks.length}, scheduling 200ms timeout`)).catch(()=>{});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
import('./logger').then(m => m.reportAppDebug('wake.detect',
|
||||||
|
`timeout fired, state=${this.state}, cbs=${this.wakeCallbacks.length}`)).catch(()=>{});
|
||||||
if (this.state === 'conversing') {
|
if (this.state === 'conversing') {
|
||||||
this.wakeCallbacks.forEach(cb => cb());
|
this.wakeCallbacks.forEach(cb => cb());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user