Files
flutter_server_box/lib/view/page/setting/entries/ai.dart
lollipopkit🏳️‍⚧️ 729b76177e feat: ask ai (#936)
* feat: ask ai in ssh terminal
Fixes #934

* new(ask_ai): settings

* fix: app hot reload

* new: l10n

* chore: deps.

* opt.
2025-10-18 01:15:43 +08:00

96 lines
2.9 KiB
Dart

part of '../entry.dart';
extension _AI on _AppSettingsPageState {
Widget _buildAskAiConfig() {
final l10n = context.l10n;
return ExpandTile(
leading: const Icon(LineAwesome.robot_solid, size: _kIconSize),
title: TipText(l10n.askAi, l10n.askAiUsageHint),
children: [
_setting.askAiBaseUrl.listenable().listenVal((val) {
final display = val.isEmpty ? libL10n.empty : val;
return ListTile(
leading: const Icon(MingCute.link_2_line),
title: Text(l10n.askAiBaseUrl),
subtitle: Text(display, style: UIs.textGrey, maxLines: 2, overflow: TextOverflow.ellipsis),
onTap: () => _showAskAiFieldDialog(
prop: _setting.askAiBaseUrl,
title: l10n.askAiBaseUrl,
hint: 'https://api.openai.com',
),
);
}),
_setting.askAiModel.listenable().listenVal((val) {
final display = val.isEmpty ? libL10n.empty : val;
return ListTile(
leading: const Icon(Icons.view_module),
title: Text(l10n.askAiModel),
subtitle: Text(display, style: UIs.textGrey),
onTap: () => _showAskAiFieldDialog(
prop: _setting.askAiModel,
title: l10n.askAiModel,
hint: 'gpt-4o-mini',
),
);
}),
_setting.askAiApiKey.listenable().listenVal((val) {
final hasKey = val.isNotEmpty;
return ListTile(
leading: const Icon(MingCute.key_2_line),
title: Text(l10n.askAiApiKey),
subtitle: Text(hasKey ? '••••••••' : libL10n.empty, style: UIs.textGrey),
onTap: () => _showAskAiFieldDialog(
prop: _setting.askAiApiKey,
title: l10n.askAiApiKey,
hint: 'sk-...',
obscure: true,
),
);
}),
],
).cardx;
}
Future<void> _showAskAiFieldDialog({
required HiveProp<String> prop,
required String title,
required String hint,
bool obscure = false,
}) async {
return withTextFieldController((ctrl) async {
final fetched = prop.fetch();
if (fetched != null && fetched.isNotEmpty) ctrl.text = fetched;
void onSave() {
prop.put(ctrl.text.trim());
context.pop();
}
await context.showRoundDialog(
title: title,
child: Input(
controller: ctrl,
autoFocus: true,
label: title,
hint: hint,
icon: obscure ? MingCute.key_2_line : Icons.edit,
obscureText: obscure,
suggestion: !obscure,
onSubmitted: (_) => onSave(),
),
actions: [
TextButton(
onPressed: () {
prop.delete();
context.pop();
},
child: Text(libL10n.clear),
),
TextButton(onPressed: onSave, child: Text(libL10n.ok)),
],
);
});
}
}