Implementation
Future<void> generate({required String sessionId, String? topicId}) async {
state = const SessionDigestState(isGenerating: true);
try {
final supabase = ref.read(supabaseDatasourceProvider);
final raw = await supabase.getMessages(sessionId);
if (raw.isEmpty) {
state = const SessionDigestState();
return;
}
final messages = raw
.map(
(m) => {
'role': m['role'] as String,
'content': m['content'] as String,
},
)
.toList();
// Route via proxy. On web the proxy is mandatory; otherwise honor
// the user's proxy toggle.
final useProxy = ref.read(useAiProxyProvider).valueOrNull ?? false;
final routeViaProxy = useProxy || kIsWeb;
final backendProvider =
ref.read(selectedAiProviderProvider).valueOrNull ?? AiProvider.claude;
late final AiDatasource ai;
if (routeViaProxy) {
final supabaseUrl = Supabase.instance.client.rest.url.replaceAll(
'/rest/v1',
'',
);
ai = ProxyAiDatasource(
Dio(),
backendProvider: backendProvider,
functionUrl: '$supabaseUrl/functions/v1/ai-proxy',
headersBuilder: () {
final session = Supabase.instance.client.auth.currentSession;
return {
'Authorization': 'Bearer ${session?.accessToken ?? ''}',
'Content-Type': 'application/json',
'apikey': Supabase.instance.client.rest.headers['apikey'] ?? '',
};
},
credentialProvider: () => getProviderCredential(ref, backendProvider),
mode: 'digest',
topicId: topicId,
sessionId: sessionId,
isCardGeneration: false,
);
} else {
ai = ref.read(aiDatasourceProvider);
}
final raw2 = await ai.sendMessage(
systemPrompt: '',
messages: messages,
maxTokens: 1024,
);
final digest = parseDigest(raw2);
await supabase.updateSession(sessionId, {'summary': digest.toJson()});
state = SessionDigestState(digest: digest);
} catch (e) {
state = SessionDigestState(
error: userFriendlyMessage(e, logName: 'SessionDigest'),
);
}
}