refactor: unused files

This commit is contained in:
cogwheel0
2025-08-20 22:41:55 +05:30
parent 4dc9ce1762
commit 6cea654b88
6 changed files with 20 additions and 2161 deletions

View File

@@ -1,397 +0,0 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/models/conversation.dart';
import '../../../core/models/chat_message.dart';
/// Advanced conversation search service with multiple search strategies
class ConversationSearchService {
static const int maxResults = 50;
static const int contextLines = 2; // Lines before/after match for context
/// Search through conversations with various criteria
Future<ConversationSearchResults> searchConversations({
required List<Conversation> conversations,
required String query,
ConversationSearchOptions options = const ConversationSearchOptions(),
}) async {
if (query.trim().isEmpty) {
return ConversationSearchResults.empty();
}
final normalizedQuery = query.toLowerCase().trim();
final results = <ConversationSearchMatch>[];
// Search through each conversation
for (final conversation in conversations) {
final matches = await _searchInConversation(
conversation: conversation,
query: normalizedQuery,
options: options,
);
results.addAll(matches);
}
// Sort results by relevance and date
results.sort((a, b) {
// First by relevance score (higher is better)
final relevanceCompare = b.relevanceScore.compareTo(a.relevanceScore);
if (relevanceCompare != 0) return relevanceCompare;
// Then by date (newer first)
return b.timestamp.compareTo(a.timestamp);
});
// Limit results
final limitedResults = results.take(maxResults).toList();
return ConversationSearchResults(
query: query,
results: limitedResults,
totalMatches: results.length,
searchDuration: DateTime.now().difference(DateTime.now()),
);
}
/// Search within a single conversation
Future<List<ConversationSearchMatch>> _searchInConversation({
required Conversation conversation,
required String query,
required ConversationSearchOptions options,
}) async {
final matches = <ConversationSearchMatch>[];
// Search in conversation title
if (options.searchTitles && _containsQuery(conversation.title, query)) {
matches.add(
ConversationSearchMatch(
conversationId: conversation.id,
conversationTitle: conversation.title,
matchType: SearchMatchType.title,
snippet: conversation.title,
highlightedSnippet: _highlightQuery(conversation.title, query),
relevanceScore: _calculateTitleRelevance(conversation.title, query),
timestamp: conversation.updatedAt,
),
);
}
// Search in messages
if (options.searchMessages) {
final messageMatches = await _searchInMessages(
conversation: conversation,
query: query,
options: options,
);
matches.addAll(messageMatches);
}
// Search in tags
if (options.searchTags) {
for (final tag in conversation.tags) {
if (_containsQuery(tag, query)) {
matches.add(
ConversationSearchMatch(
conversationId: conversation.id,
conversationTitle: conversation.title,
matchType: SearchMatchType.tag,
snippet: tag,
highlightedSnippet: _highlightQuery(tag, query),
relevanceScore: _calculateTagRelevance(tag, query),
timestamp: conversation.updatedAt,
additionalInfo: {'tag': tag},
),
);
}
}
}
return matches;
}
/// Search within messages of a conversation
Future<List<ConversationSearchMatch>> _searchInMessages({
required Conversation conversation,
required String query,
required ConversationSearchOptions options,
}) async {
final matches = <ConversationSearchMatch>[];
for (int i = 0; i < conversation.messages.length; i++) {
final message = conversation.messages[i];
// Skip system messages if not enabled
if (!options.includeSystemMessages && message.role == 'system') {
continue;
}
// Filter by role if specified
if (options.roleFilter != null && message.role != options.roleFilter) {
continue;
}
// Check if message contains query
if (_containsQuery(message.content, query)) {
final snippet = _extractSnippet(message.content, query);
final contextMessages = _getContextMessages(conversation.messages, i);
matches.add(
ConversationSearchMatch(
conversationId: conversation.id,
conversationTitle: conversation.title,
messageId: message.id,
matchType: SearchMatchType.message,
snippet: snippet,
highlightedSnippet: _highlightQuery(snippet, query),
relevanceScore: _calculateMessageRelevance(message.content, query),
timestamp: message.timestamp,
messageRole: message.role,
messageIndex: i,
contextMessages: contextMessages,
),
);
}
}
return matches;
}
/// Extract relevant snippet around the query match
String _extractSnippet(String content, String query) {
const maxSnippetLength = 200;
final queryIndex = content.toLowerCase().indexOf(query);
if (queryIndex == -1) {
return content.substring(0, maxSnippetLength.clamp(0, content.length));
}
// Calculate snippet bounds
final start = (queryIndex - 50).clamp(0, content.length);
final end = (queryIndex + query.length + 50).clamp(0, content.length);
String snippet = content.substring(start, end);
// Add ellipsis if needed
if (start > 0) snippet = '...$snippet';
if (end < content.length) snippet = '$snippet...';
return snippet;
}
/// Get context messages around a matched message
List<ChatMessage> _getContextMessages(List<ChatMessage> messages, int index) {
final start = (index - contextLines).clamp(0, messages.length);
final end = (index + contextLines + 1).clamp(0, messages.length);
return messages.sublist(start, end);
}
/// Highlight query matches in text
String _highlightQuery(String text, String query) {
if (query.isEmpty) return text;
final regex = RegExp(RegExp.escape(query), caseSensitive: false);
return text.replaceAllMapped(regex, (match) {
return '<mark>${match.group(0)}</mark>';
});
}
/// Check if text contains the query
bool _containsQuery(String text, String query) {
return text.toLowerCase().contains(query);
}
/// Calculate relevance score for title matches
double _calculateTitleRelevance(String title, String query) {
final titleLower = title.toLowerCase();
final queryLower = query.toLowerCase();
// Exact match gets highest score
if (titleLower == queryLower) return 100.0;
// Title starts with query gets high score
if (titleLower.startsWith(queryLower)) return 90.0;
// Title contains query as whole word gets medium score
if (RegExp(
r'\b' + RegExp.escape(queryLower) + r'\b',
).hasMatch(titleLower)) {
return 70.0;
}
// Partial match gets lower score
return 50.0;
}
/// Calculate relevance score for message matches
double _calculateMessageRelevance(String content, String query) {
final contentLower = content.toLowerCase();
final queryLower = query.toLowerCase();
// Count occurrences
final occurrences = queryLower.allMatches(contentLower).length;
// Base score for containing the query
double score = 30.0;
// Bonus for multiple occurrences
score += (occurrences - 1) * 10.0;
// Bonus for whole word matches
if (RegExp(
r'\b' + RegExp.escape(queryLower) + r'\b',
).hasMatch(contentLower)) {
score += 20.0;
}
// Penalty for very long messages (relevance dilution)
if (content.length > 1000) {
score *= 0.8;
}
return score.clamp(0.0, 100.0);
}
/// Calculate relevance score for tag matches
double _calculateTagRelevance(String tag, String query) {
final tagLower = tag.toLowerCase();
final queryLower = query.toLowerCase();
// Exact match gets highest score
if (tagLower == queryLower) return 80.0;
// Tag starts with query gets high score
if (tagLower.startsWith(queryLower)) return 70.0;
// Partial match gets medium score
return 50.0;
}
}
/// Search options for conversation search
@immutable
class ConversationSearchOptions {
final bool searchTitles;
final bool searchMessages;
final bool searchTags;
final bool includeSystemMessages;
final String? roleFilter; // 'user', 'assistant', 'system'
final DateTime? dateFrom;
final DateTime? dateTo;
final bool caseSensitive;
const ConversationSearchOptions({
this.searchTitles = true,
this.searchMessages = true,
this.searchTags = true,
this.includeSystemMessages = false,
this.roleFilter,
this.dateFrom,
this.dateTo,
this.caseSensitive = false,
});
ConversationSearchOptions copyWith({
bool? searchTitles,
bool? searchMessages,
bool? searchTags,
bool? includeSystemMessages,
String? roleFilter,
DateTime? dateFrom,
DateTime? dateTo,
bool? caseSensitive,
}) {
return ConversationSearchOptions(
searchTitles: searchTitles ?? this.searchTitles,
searchMessages: searchMessages ?? this.searchMessages,
searchTags: searchTags ?? this.searchTags,
includeSystemMessages:
includeSystemMessages ?? this.includeSystemMessages,
roleFilter: roleFilter ?? this.roleFilter,
dateFrom: dateFrom ?? this.dateFrom,
dateTo: dateTo ?? this.dateTo,
caseSensitive: caseSensitive ?? this.caseSensitive,
);
}
}
/// Search results container
@immutable
class ConversationSearchResults {
final String query;
final List<ConversationSearchMatch> results;
final int totalMatches;
final Duration searchDuration;
const ConversationSearchResults({
required this.query,
required this.results,
required this.totalMatches,
required this.searchDuration,
});
factory ConversationSearchResults.empty() {
return ConversationSearchResults(
query: '',
results: const [],
totalMatches: 0,
searchDuration: Duration.zero,
);
}
bool get isEmpty => results.isEmpty;
bool get isNotEmpty => results.isNotEmpty;
int get length => results.length;
}
/// Individual search match
@immutable
class ConversationSearchMatch {
final String conversationId;
final String conversationTitle;
final String? messageId;
final SearchMatchType matchType;
final String snippet;
final String highlightedSnippet;
final double relevanceScore;
final DateTime timestamp;
final String? messageRole;
final int? messageIndex;
final List<ChatMessage>? contextMessages;
final Map<String, dynamic>? additionalInfo;
const ConversationSearchMatch({
required this.conversationId,
required this.conversationTitle,
this.messageId,
required this.matchType,
required this.snippet,
required this.highlightedSnippet,
required this.relevanceScore,
required this.timestamp,
this.messageRole,
this.messageIndex,
this.contextMessages,
this.additionalInfo,
});
}
/// Types of search matches
enum SearchMatchType { title, message, tag }
/// Provider for conversation search service
final conversationSearchServiceProvider = Provider<ConversationSearchService>((
ref,
) {
return ConversationSearchService();
});
/// Provider for search results
final conversationSearchResultsProvider =
StateProvider<ConversationSearchResults?>((ref) {
return null;
});
/// Provider for search options
final searchOptionsProvider = StateProvider<ConversationSearchOptions>((ref) {
return const ConversationSearchOptions();
});