Files
OllaHub/hooks/use-query-preprocessor.ts
T
Evandro Fonseca Junior 84ea2dec19 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.
2025-11-26 16:12:16 -03:00

183 lines
4.9 KiB
TypeScript

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,
};
}