feat: add emoji-regex and remove-accents dependencies; enhance chat and setup pages
- Added `emoji-regex` and `remove-accents` packages to improve text processing capabilities. - Implemented automatic Ollama startup in the chat page for better user experience. - Enhanced setup page to include GPU selection based on hardware specifications. - Updated chat input to support real-time validation and improved user feedback. - Refactored message handling in chat to incorporate new processing features.
This commit is contained in:
1 parent
4275295e4f
commit
84ea2dec19
51 files changed
+7857
-573
No files matched your search
@@ -0,0 +1,182 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { normalizeText } from '@/lib/text-normalization';
|
||||
import { validateQuery, ValidationResult } from '@/lib/query-validation';
|
||||
import { splitQuestions, SplitResult } from '@/lib/question-splitter';
|
||||
import { useSettingsStore } from '@/store/settings-store';
|
||||
|
||||
export type QueryIntent =
|
||||
| 'factual'
|
||||
| 'conversational'
|
||||
| 'technical'
|
||||
| 'opinion'
|
||||
| 'calculation'
|
||||
| 'unknown';
|
||||
|
||||
export interface PreprocessedQuery {
|
||||
original: string;
|
||||
normalized: string;
|
||||
questions: string[];
|
||||
intent: QueryIntent;
|
||||
validation: ValidationResult;
|
||||
shouldSearch: boolean;
|
||||
splitResult: SplitResult;
|
||||
}
|
||||
|
||||
export interface PreprocessOptions {
|
||||
skipValidation?: boolean;
|
||||
skipSplit?: boolean;
|
||||
skipIntentClassification?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook para pré-processamento de queries do usuário
|
||||
* Orquestra normalização, validação, split e classificação de intenção
|
||||
*/
|
||||
export function useQueryPreprocessor() {
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
const settings = useSettingsStore();
|
||||
|
||||
/**
|
||||
* Pré-processa uma query do usuário
|
||||
*
|
||||
* @param text - Texto original da query
|
||||
* @param options - Opções de pré-processamento
|
||||
* @returns Query pré-processada
|
||||
*/
|
||||
const preprocess = useCallback(
|
||||
async (
|
||||
text: string,
|
||||
options: PreprocessOptions = {}
|
||||
): Promise<PreprocessedQuery> => {
|
||||
setIsProcessing(true);
|
||||
|
||||
try {
|
||||
const original = text;
|
||||
const normalized = normalizeText(text);
|
||||
|
||||
// 1. Validação
|
||||
let validation: ValidationResult;
|
||||
if (options.skipValidation) {
|
||||
validation = {
|
||||
isValid: true,
|
||||
errors: [],
|
||||
warnings: [],
|
||||
normalizedLength: normalized.length,
|
||||
};
|
||||
} else {
|
||||
const preprocessingConfig = settings.queryPreprocessing || {
|
||||
enabled: true,
|
||||
minLength: 3,
|
||||
maxLength: 2000,
|
||||
autoSplitQuestions: true,
|
||||
irrelevantPatterns: [],
|
||||
};
|
||||
|
||||
validation = validateQuery(text, {
|
||||
minLength: preprocessingConfig.minLength,
|
||||
maxLength: preprocessingConfig.maxLength,
|
||||
irrelevantPatterns: preprocessingConfig.irrelevantPatterns.length > 0
|
||||
? preprocessingConfig.irrelevantPatterns
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
// Se inválida, retornar com erro
|
||||
if (!validation.isValid) {
|
||||
return {
|
||||
original,
|
||||
normalized,
|
||||
questions: [],
|
||||
intent: 'unknown',
|
||||
validation,
|
||||
shouldSearch: false,
|
||||
splitResult: {
|
||||
questions: [],
|
||||
originalText: original,
|
||||
splitCount: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 2. Split de perguntas
|
||||
let splitResult: SplitResult;
|
||||
if (options.skipSplit) {
|
||||
splitResult = {
|
||||
questions: [original],
|
||||
originalText: original,
|
||||
splitCount: 1,
|
||||
};
|
||||
} else {
|
||||
splitResult = splitQuestions(original);
|
||||
}
|
||||
|
||||
// 3. Classificação de intenção
|
||||
let intent: QueryIntent = 'unknown';
|
||||
if (!options.skipIntentClassification) {
|
||||
try {
|
||||
const intentStr = await invoke<string>('classify_intent', {
|
||||
query: normalized,
|
||||
});
|
||||
intent = intentStr as QueryIntent;
|
||||
} catch (error) {
|
||||
console.error('Erro ao classificar intent:', error);
|
||||
// Fallback para unknown
|
||||
intent = 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Decidir se deve buscar
|
||||
// Busca é necessária se:
|
||||
// - Intent é factual ou technical (e webSearch está habilitado)
|
||||
// - Intent é unknown (comportamento padrão: permitir busca)
|
||||
const shouldSearch =
|
||||
settings.webSearch.enabled &&
|
||||
(intent === 'factual' ||
|
||||
intent === 'technical' ||
|
||||
intent === 'unknown');
|
||||
|
||||
return {
|
||||
original,
|
||||
normalized,
|
||||
questions: splitResult.questions,
|
||||
intent,
|
||||
validation,
|
||||
shouldSearch,
|
||||
splitResult,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Erro no pré-processamento:', error);
|
||||
// Retornar resultado com erro
|
||||
return {
|
||||
original: text,
|
||||
normalized: normalizeText(text),
|
||||
questions: [],
|
||||
intent: 'unknown',
|
||||
validation: {
|
||||
isValid: false,
|
||||
errors: ['Erro ao pré-processar query'],
|
||||
warnings: [],
|
||||
normalizedLength: 0,
|
||||
},
|
||||
shouldSearch: false,
|
||||
splitResult: {
|
||||
questions: [],
|
||||
originalText: text,
|
||||
splitCount: 0,
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
}
|
||||
},
|
||||
[settings]
|
||||
);
|
||||
|
||||
return {
|
||||
preprocess,
|
||||
isProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user