Files
social-app/apps/lib/features/chat/data/ai/ai_decision_engine.dart
T

101 lines
3.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
enum Intent { createEvent, searchEvent, unknown }
class AiDecisionEngine {
/// 意图匹配规则(顺序敏感:searchEvent 优先级高于 createEvent
static final List<(RegExp, Intent)> _orderedPatterns = [
(RegExp(r'^查看|^有什么|^今天.*日程|^明天.*安排|^查询'), Intent.searchEvent),
(RegExp(r'提醒|开会|预约|安排.*时间|创建.*日程'), Intent.createEvent),
(
RegExp(r'明天.*\d|今天.*\d|后天.*\d|\d{1,2}点|\d{1,2}:\d{2}'),
Intent.createEvent,
),
];
Intent matchIntent(String text) {
for (final (pattern, intent) in _orderedPatterns) {
if (pattern.hasMatch(text)) return intent;
}
return Intent.unknown;
}
Map<String, dynamic>? tryExtractEventArgs(String text) {
if (matchIntent(text) != Intent.createEvent) return null;
final args = <String, dynamic>{};
final titleMatch = RegExp(r'提醒(.+?)(?:明天|今天|几点|$)').firstMatch(text);
if (titleMatch != null) {
args['title'] = titleMatch.group(1)?.trim() ?? text;
} else if (RegExp(r'\d{1,2}[:点]|\d{1,2}点').hasMatch(text)) {
args['title'] = text
.replaceAll(RegExp(r'\d{1,2}[:点]\d{0,2}|明天|今天|后天'), '')
.trim();
}
if (args['title'] == null || (args['title'] as String).isEmpty) return null;
final timeMatch = RegExp(
r'(明天|今天|后天)?\s*(\d{1,2})[:点](\d{2})?',
).firstMatch(text);
if (timeMatch != null) {
final dayStr = timeMatch.group(1) ?? '今天';
final hour = int.parse(timeMatch.group(2)!);
final minute = int.parse(timeMatch.group(3) ?? '0');
final now = DateTime.now();
DateTime startAt;
switch (dayStr) {
case '明天':
startAt = DateTime(now.year, now.month, now.day + 1, hour, minute);
break;
case '后天':
startAt = DateTime(now.year, now.month, now.day + 2, hour, minute);
break;
default:
startAt = DateTime(now.year, now.month, now.day, hour, minute);
}
args['startAt'] = startAt.toIso8601String();
args['timezone'] = 'Asia/Shanghai';
}
if (!args.containsKey('startAt')) return null;
return args;
}
bool shouldTriggerToolCall(String text) =>
matchIntent(text) == Intent.createEvent;
Map<String, dynamic>? getToolCallArgs(String text) {
if (!shouldTriggerToolCall(text)) return null;
return tryExtractEventArgs(text);
}
ForceTriggerResult? tryForceTrigger(String text) {
final match = RegExp(r'#tool:(\w+)\s*(\{.*\})?').firstMatch(text);
if (match == null) return null;
final toolName = match.group(1)!;
final argsJson = match.group(2);
Map<String, dynamic>? args;
if (argsJson != null) {
try {
args = jsonDecode(argsJson) as Map<String, dynamic>;
} catch (_) {
args = {};
}
}
return ForceTriggerResult(toolName: toolName, args: args ?? {});
}
}
class ForceTriggerResult {
final String toolName;
final Map<String, dynamic> args;
ForceTriggerResult({required this.toolName, required this.args});
}