klg-asutk-app/components/SemanticSearch.tsx
Yuriy d47baa1782 refactor: удалены ссылки на knowledge/ (не относится к КЛГ АСУ ТК)
- Удалены API routes, rewrites и ссылки на knowledge/reglaments
- knowledge/ удалена из git-истории (6 ГБ PDF не относящихся к проекту)
- Нормативная база обслуживается через модуль legal (routes/legal/)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-15 14:02:14 +03:00

141 lines
4.4 KiB
TypeScript
Raw Permalink 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.

'use client';
import { useState } from 'react';
interface SearchResult {
id: string;
content: string;
metadata: Record<string, any>;
type: string;
similarity: number;
}
interface SemanticSearchProps {
onResultSelect?: (result: SearchResult) => void;
placeholder?: string;
}
export default function SemanticSearch({
onResultSelect,
placeholder = 'Семантический поиск по базе знаний...'
}: SemanticSearchProps) {
const [query, setQuery] = useState('');
const [results, setResults] = useState<SearchResult[]>([]);
const [loading, setLoading] = useState(false);
const [type, setType] = useState<string>('all');
const handleSearch = async () => {
if (!query.trim()) {
return;
}
setLoading(true);
try {
// Модуль нормативной базы (knowledge) вынесен в отдельный сервис
setResults([]);
} catch {
setResults([]);
} finally {
setLoading(false);
}
};
return (
<div style={{
backgroundColor: 'white',
borderRadius: '8px',
padding: '20px',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
}}>
<div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
<select
value={type}
onChange={(e) => setType(e.target.value)}
style={{
padding: '8px 12px',
border: '1px solid #ccc',
borderRadius: '4px',
fontSize: '14px',
}}
>
<option value="all">Все типы</option>
<option value="aircraft">Воздушные суда</option>
<option value="audit">Аудиты</option>
<option value="risk">Риски</option>
<option value="regulation">Нормативы</option>
<option value="document">Документы</option>
<option value="insight">Инсайты</option>
</select>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
placeholder={placeholder}
style={{
flex: 1,
padding: '8px 12px',
border: '1px solid #ccc',
borderRadius: '4px',
fontSize: '14px',
}}
/>
<button
onClick={handleSearch}
disabled={loading || !query.trim()}
style={{
padding: '8px 16px',
backgroundColor: loading || !query.trim() ? '#ccc' : '#2196f3',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: loading || !query.trim() ? 'not-allowed' : 'pointer',
fontSize: '14px',
}}
>
{loading ? 'Поиск...' : 'Найти'}
</button>
</div>
{results.length > 0 && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<div style={{ fontSize: '12px', color: '#666', marginBottom: '8px' }}>
Найдено: {results.length} результатов
</div>
{results.map((result) => (
<div
key={result.id}
onClick={() => onResultSelect?.(result)}
style={{
padding: '12px',
backgroundColor: '#f5f5f5',
borderRadius: '4px',
cursor: onResultSelect ? 'pointer' : 'default',
borderLeft: `4px solid ${
result.type === 'risk' ? '#f44336' :
result.type === 'audit' ? '#ff9800' :
result.type === 'aircraft' ? '#2196f3' :
'#4caf50'
}`,
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
<span style={{ fontSize: '12px', color: '#666', textTransform: 'uppercase' }}>
{result.type}
</span>
<span style={{ fontSize: '12px', color: '#666' }}>
Релевантность: {Math.round(result.similarity * 100)}%
</span>
</div>
<div style={{ fontSize: '14px', lineHeight: '1.5' }}>
{result.content.substring(0, 200)}
{result.content.length > 200 && '...'}
</div>
</div>
))}
</div>
)}
</div>
);
}