local ai killswitch
This commit is contained in:
+40
-24
@@ -25,6 +25,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/ta
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_chips.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_chips.dart';
|
||||||
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
|
import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/hooks/listenable_callback.dart';
|
import 'package:weblibre/presentation/hooks/listenable_callback.dart';
|
||||||
import 'package:weblibre/presentation/widgets/speech_to_text_button.dart';
|
import 'package:weblibre/presentation/widgets/speech_to_text_button.dart';
|
||||||
|
|
||||||
@@ -108,6 +109,12 @@ class _TabSheetHeader extends HookConsumerWidget {
|
|||||||
() => searchTextController.text.isNotEmpty,
|
() => searchTextController.text.isNotEmpty,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final enableAiFeatures = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(settings) => settings.enableLocalAiFeatures,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
useListenableCallback(searchTextController, () async {
|
useListenableCallback(searchTextController, () async {
|
||||||
await ref
|
await ref
|
||||||
.read(
|
.read(
|
||||||
@@ -160,27 +167,29 @@ class _TabSheetHeader extends HookConsumerWidget {
|
|||||||
.toggle();
|
.toggle();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Consumer(
|
if (enableAiFeatures)
|
||||||
builder: (context, ref, child) {
|
Consumer(
|
||||||
final tabSuggestionsEnabled = ref.watch(
|
builder: (context, ref, child) {
|
||||||
tabSuggestionsControllerProvider,
|
final tabSuggestionsEnabled = ref.watch(
|
||||||
);
|
tabSuggestionsControllerProvider,
|
||||||
|
);
|
||||||
|
|
||||||
return IconButton.filledTonal(
|
return IconButton.filledTonal(
|
||||||
icon: const Icon(MdiIcons.imageAutoAdjust),
|
icon: const Icon(MdiIcons.imageAutoAdjust),
|
||||||
isSelected: tabSuggestionsEnabled,
|
isSelected: tabSuggestionsEnabled,
|
||||||
iconSize: 18,
|
iconSize: 18,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ref
|
ref
|
||||||
.read(
|
.read(
|
||||||
tabSuggestionsControllerProvider.notifier,
|
tabSuggestionsControllerProvider
|
||||||
)
|
.notifier,
|
||||||
.toggle();
|
)
|
||||||
},
|
.toggle();
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
@@ -215,9 +224,9 @@ class _TabSheetHeader extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (result == true) {
|
if (result == true) {
|
||||||
await ref
|
await ref
|
||||||
.read(tabDataRepositoryProvider.notifier)
|
.read(tabDataRepositoryProvider.notifier)
|
||||||
.closeAllTabsByContainer(container);
|
.closeAllTabsByContainer(container);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(MdiIcons.closeBoxMultiple),
|
icon: const Icon(MdiIcons.closeBoxMultiple),
|
||||||
@@ -380,9 +389,16 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
final tabSuggestionsEnabled = ref.watch(
|
final tabSuggestionsEnabled = ref.watch(
|
||||||
tabSuggestionsControllerProvider,
|
tabSuggestionsControllerProvider,
|
||||||
);
|
);
|
||||||
|
final enableAiFeatures = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(settings) => settings.enableLocalAiFeatures,
|
||||||
|
),
|
||||||
|
);
|
||||||
final suggestedTabEntities = ref.watch(
|
final suggestedTabEntities = ref.watch(
|
||||||
suggestedTabEntitiesProvider(
|
suggestedTabEntitiesProvider(
|
||||||
tabSuggestionsEnabled ? containerId : null,
|
(enableAiFeatures && tabSuggestionsEnabled)
|
||||||
|
? containerId
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:synchronized/synchronized.dart';
|
|||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/utils/embedding_text_processing.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/utils/embedding_text_processing.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/utils/nearest_neighbor.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/utils/nearest_neighbor.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/utils/lru_cache.dart';
|
import 'package:weblibre/utils/lru_cache.dart';
|
||||||
|
|
||||||
part 'gecko_inference.g.dart';
|
part 'gecko_inference.g.dart';
|
||||||
@@ -41,6 +42,14 @@ class GeckoInferenceRepository extends _$GeckoInferenceRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> predictDocumentTopic(Set<String> titles) async {
|
Future<String?> predictDocumentTopic(Set<String> titles) async {
|
||||||
|
if (!ref.read(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(settings) => settings.enableLocalAiFeatures,
|
||||||
|
),
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (titles.isNotEmpty) {
|
if (titles.isNotEmpty) {
|
||||||
if (_topicCache.get(titles) case final String title) {
|
if (_topicCache.get(titles) case final String title) {
|
||||||
return title;
|
return title;
|
||||||
@@ -69,6 +78,14 @@ class GeckoInferenceRepository extends _$GeckoInferenceRepository {
|
|||||||
required List<String> assignedDocumentsInput,
|
required List<String> assignedDocumentsInput,
|
||||||
required List<String> unassignedDocumentsInput,
|
required List<String> unassignedDocumentsInput,
|
||||||
}) async {
|
}) async {
|
||||||
|
if (!ref.read(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(settings) => settings.enableLocalAiFeatures,
|
||||||
|
),
|
||||||
|
)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final processedDocuments = <String, String>{};
|
final processedDocuments = <String, String>{};
|
||||||
final unassignedDocumentsProcessed = unassignedDocumentsInput.map((doc) {
|
final unassignedDocumentsProcessed = unassignedDocumentsInput.map((doc) {
|
||||||
final processed = preprocessText(doc);
|
final processed = preprocessText(doc);
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ class _ContainerTabSuggestionsProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$geckoInferenceRepositoryHash() =>
|
String _$geckoInferenceRepositoryHash() =>
|
||||||
r'bdae6dab14c33c6503f37f2e17b8d50fb820ac26';
|
r'170bd0b67e5f1edc43ed97d4535f41353fb8796e';
|
||||||
|
|
||||||
/// See also [GeckoInferenceRepository].
|
/// See also [GeckoInferenceRepository].
|
||||||
@ProviderFor(GeckoInferenceRepository)
|
@ProviderFor(GeckoInferenceRepository)
|
||||||
|
|||||||
@@ -156,6 +156,22 @@ class GeneralSettingsScreen extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SwitchListTile.adaptive(
|
||||||
|
title: const Text('On Device AI'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Local on-device features including container topic and tab suggestions',
|
||||||
|
),
|
||||||
|
secondary: const Icon(MdiIcons.creation),
|
||||||
|
value: generalSettings.enableLocalAiFeatures,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) => currentSettings.copyWith
|
||||||
|
.enableLocalAiFeatures(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
SwitchListTile.adaptive(
|
SwitchListTile.adaptive(
|
||||||
title: const Text('Enable Reader Mode'),
|
title: const Text('Enable Reader Mode'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
|
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
|
||||||
final bool createChildTabsOption;
|
final bool createChildTabsOption;
|
||||||
final bool showExtensionShortcut;
|
final bool showExtensionShortcut;
|
||||||
|
final bool enableLocalAiFeatures;
|
||||||
|
|
||||||
final bool proxyPrivateTabsTor;
|
final bool proxyPrivateTabsTor;
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.createChildTabsOption,
|
required this.createChildTabsOption,
|
||||||
required this.proxyPrivateTabsTor,
|
required this.proxyPrivateTabsTor,
|
||||||
required this.showExtensionShortcut,
|
required this.showExtensionShortcut,
|
||||||
|
required this.enableLocalAiFeatures,
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneralSettings.withDefaults({
|
GeneralSettings.withDefaults({
|
||||||
@@ -59,6 +61,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? createChildTabsOption,
|
bool? createChildTabsOption,
|
||||||
bool? proxyPrivateTabsTor,
|
bool? proxyPrivateTabsTor,
|
||||||
bool? showExtensionShortcut,
|
bool? showExtensionShortcut,
|
||||||
|
bool? enableLocalAiFeatures,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
enableReadability = enableReadability ?? true,
|
enableReadability = enableReadability ?? true,
|
||||||
enforceReadability = enforceReadability ?? false,
|
enforceReadability = enforceReadability ?? false,
|
||||||
@@ -67,7 +70,8 @@ class GeneralSettings with FastEquatable {
|
|||||||
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
|
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
|
||||||
createChildTabsOption = createChildTabsOption ?? false,
|
createChildTabsOption = createChildTabsOption ?? false,
|
||||||
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
||||||
showExtensionShortcut = showExtensionShortcut ?? false;
|
showExtensionShortcut = showExtensionShortcut ?? false,
|
||||||
|
enableLocalAiFeatures = enableLocalAiFeatures ?? true;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
_$GeneralSettingsFromJson(json);
|
_$GeneralSettingsFromJson(json);
|
||||||
@@ -85,5 +89,6 @@ class GeneralSettings with FastEquatable {
|
|||||||
createChildTabsOption,
|
createChildTabsOption,
|
||||||
showExtensionShortcut,
|
showExtensionShortcut,
|
||||||
proxyPrivateTabsTor,
|
proxyPrivateTabsTor,
|
||||||
|
enableLocalAiFeatures,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings showExtensionShortcut(bool showExtensionShortcut);
|
GeneralSettings showExtensionShortcut(bool showExtensionShortcut);
|
||||||
|
|
||||||
|
GeneralSettings enableLocalAiFeatures(bool enableLocalAiFeatures);
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
///
|
///
|
||||||
/// Usage
|
/// Usage
|
||||||
@@ -45,6 +47,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool createChildTabsOption,
|
bool createChildTabsOption,
|
||||||
bool proxyPrivateTabsTor,
|
bool proxyPrivateTabsTor,
|
||||||
bool showExtensionShortcut,
|
bool showExtensionShortcut,
|
||||||
|
bool enableLocalAiFeatures,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +94,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings showExtensionShortcut(bool showExtensionShortcut) =>
|
GeneralSettings showExtensionShortcut(bool showExtensionShortcut) =>
|
||||||
this(showExtensionShortcut: showExtensionShortcut);
|
this(showExtensionShortcut: showExtensionShortcut);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings enableLocalAiFeatures(bool enableLocalAiFeatures) =>
|
||||||
|
this(enableLocalAiFeatures: enableLocalAiFeatures);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
///
|
///
|
||||||
@@ -108,6 +115,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
||||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
Object? showExtensionShortcut = const $CopyWithPlaceholder(),
|
Object? showExtensionShortcut = const $CopyWithPlaceholder(),
|
||||||
|
Object? enableLocalAiFeatures = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
themeMode: themeMode == const $CopyWithPlaceholder()
|
themeMode: themeMode == const $CopyWithPlaceholder()
|
||||||
@@ -151,6 +159,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.showExtensionShortcut
|
? _value.showExtensionShortcut
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: showExtensionShortcut as bool,
|
: showExtensionShortcut as bool,
|
||||||
|
enableLocalAiFeatures:
|
||||||
|
enableLocalAiFeatures == const $CopyWithPlaceholder()
|
||||||
|
? _value.enableLocalAiFeatures
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: enableLocalAiFeatures as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,6 +195,7 @@ GeneralSettings _$GeneralSettingsFromJson(Map<String, dynamic> json) =>
|
|||||||
createChildTabsOption: json['createChildTabsOption'] as bool?,
|
createChildTabsOption: json['createChildTabsOption'] as bool?,
|
||||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||||
showExtensionShortcut: json['showExtensionShortcut'] as bool?,
|
showExtensionShortcut: json['showExtensionShortcut'] as bool?,
|
||||||
|
enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
||||||
@@ -198,6 +212,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
|||||||
.defaultSearchSuggestionsProvider]!,
|
.defaultSearchSuggestionsProvider]!,
|
||||||
'createChildTabsOption': instance.createChildTabsOption,
|
'createChildTabsOption': instance.createChildTabsOption,
|
||||||
'showExtensionShortcut': instance.showExtensionShortcut,
|
'showExtensionShortcut': instance.showExtensionShortcut,
|
||||||
|
'enableLocalAiFeatures': instance.enableLocalAiFeatures,
|
||||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
'enableLocalAiFeatures': settings['enableLocalAiFeatures']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'general_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'eb5f27e0bd8f5def833e1c703cb42181acc2440f';
|
r'b3c60b14cdfba7e0bcf4817addc8295b5281a9b5';
|
||||||
|
|
||||||
/// See also [GeneralSettingsRepository].
|
/// See also [GeneralSettingsRepository].
|
||||||
@ProviderFor(GeneralSettingsRepository)
|
@ProviderFor(GeneralSettingsRepository)
|
||||||
|
|||||||
Reference in New Issue
Block a user