toSupabaseJson method
Convert to JSON for Supabase (development) Uses column names expected by Supabase telemetry_events table Schema matches C++ telemetry_json.cpp rac_telemetry_manager_payload_to_json()
Only includes non-null values to match C++ behavior (add_string skips null). Events are sent one at a time, so each can have different keys.
Implementation
Map<String, dynamic> toSupabaseJson({
required String deviceId,
required String sdkVersion,
required String platform,
}) {
final json = <String, dynamic>{
// Required fields (Supabase-specific key names)
'sdk_event_id': id,
'event_type': type,
'event_timestamp': timestamp.toUtc().toIso8601String(),
'created_at': createdAt.toUtc().toIso8601String(),
// Development-only fields
'modality': category.value,
'device_id': deviceId,
// Device info
'platform': platform,
'sdk_version': sdkVersion,
};
// Helper to add non-null values only (matches C++ add_string/add_int behavior)
void addIfNotNull(String supabaseKey, dynamic value) {
if (value != null) {
json[supabaseKey] = value;
}
}
// Helper to get value from properties with fallback key
dynamic getValue(String key, [String? fallbackKey]) {
return properties[key] ?? (fallbackKey != null ? properties[fallbackKey] : null);
}
// Session tracking
addIfNotNull('session_id', getValue('session_id'));
// Model info
addIfNotNull('model_id', getValue('model_id'));
addIfNotNull('model_name', getValue('model_name'));
addIfNotNull('framework', getValue('framework'));
// Common metrics
addIfNotNull(
'processing_time_ms',
getValue('processing_time_ms') ??
getValue('load_time_ms') ??
getValue('latency_ms') ??
getValue('download_time_ms'));
addIfNotNull('success', getValue('success'));
addIfNotNull('error_message', getValue('error_message'));
addIfNotNull('error_code', getValue('error_code'));
// LLM fields
addIfNotNull('input_tokens', getValue('input_tokens', 'prompt_tokens'));
addIfNotNull('output_tokens', getValue('output_tokens', 'completion_tokens'));
addIfNotNull('total_tokens', getValue('total_tokens'));
addIfNotNull('tokens_per_second', getValue('tokens_per_second'));
addIfNotNull('time_to_first_token_ms', getValue('time_to_first_token_ms'));
addIfNotNull('generation_time_ms', getValue('generation_time_ms'));
addIfNotNull('context_length', getValue('context_length'));
addIfNotNull('temperature', getValue('temperature'));
addIfNotNull('max_tokens', getValue('max_tokens'));
addIfNotNull('is_streaming', getValue('is_streaming'));
// STT fields
addIfNotNull('audio_duration_ms', getValue('audio_duration_ms'));
addIfNotNull('real_time_factor', getValue('real_time_factor'));
addIfNotNull('word_count', getValue('word_count'));
addIfNotNull('confidence', getValue('confidence'));
addIfNotNull('language', getValue('language'));
// TTS fields
addIfNotNull('character_count', getValue('character_count', 'text_length'));
addIfNotNull('voice', getValue('voice', 'voice_id'));
addIfNotNull('sample_rate', getValue('sample_rate'));
addIfNotNull('characters_per_second', getValue('characters_per_second'));
// TTS uses output_duration_ms in Supabase (same as audio_duration_ms)
addIfNotNull('output_duration_ms', getValue('audio_duration_ms'));
addIfNotNull('audio_size_bytes', getValue('audio_size_bytes'));
return json;
}