Files
Momento/architectural-grid10/src/components/settings/SettingsHeader.tsx
Antigravity 03e6a62b80
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m12s
feat: migrate semantic search to pgvector + full-text search
Replace JSON-string embeddings with native pgvector(1536) storage and
add PostgreSQL full-text search (tsvector/GIN) with Reciprocal Rank Fusion
for hybrid keyword + semantic ranking.

Changes:
- NoteEmbedding.embedding: String → vector(1536) via pgvector
- NoteEmbedding: added updatedAt for reindex tracking
- Note: added tsv (tsvector) with auto-update trigger for FTS
- semantic-search.service: hybrid FTS + vector search with RRF fusion
- embedding.service: toVectorString() for pgvector SQL literals
- Removed JS-side cosine similarity loops (now DB-side via <=>)
- Added HNSW index on NoteEmbedding.embedding (cosine distance)
- Added GIN index on Note.tsv for FTS queries

Schema migration in: prisma/migrations/20260512120000_pgvector_and_fts_search/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 07:03:56 +00:00

52 lines
2.2 KiB
TypeScript

import React from 'react';
import { Settings, Sparkles, Palette, User, Database, Code, Info } from 'lucide-react';
import { motion } from 'motion/react';
import { SettingsTab } from '../../types';
interface SettingsHeaderProps {
activeTab: SettingsTab;
setActiveTab: (tab: SettingsTab) => void;
}
export const SettingsHeader: React.FC<SettingsHeaderProps> = ({ activeTab, setActiveTab }) => {
const tabs = [
{ id: 'general', label: 'Paramètres généraux', icon: <Settings size={14} /> },
{ id: 'ai', label: 'Paramètres IA', icon: <Sparkles size={14} /> },
{ id: 'appearance', label: 'Apparence', icon: <Palette size={14} /> },
{ id: 'profile', label: 'Profil', icon: <User size={14} /> },
{ id: 'data', label: 'Gestion des données', icon: <Database size={14} /> },
{ id: 'mcp', label: 'Paramètres MCP', icon: <Code size={14} /> },
{ id: 'about', label: 'À propos', icon: <Info size={14} /> },
];
return (
<header className="px-12 pt-20 pb-16 space-y-12">
<div className="space-y-4">
<h1 className="text-[64px] font-serif text-ink tracking-tight leading-none italic font-medium">Paramètres</h1>
<p className="text-[10px] font-bold uppercase tracking-[0.4em] text-concrete opacity-60">Configuration & Préférences</p>
</div>
<nav className="flex items-center gap-1 border-b border-border/40 pb-px">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as SettingsTab)}
className={`flex items-center gap-2.5 px-6 py-5 text-[10px] font-bold uppercase tracking-[0.18em] transition-all relative whitespace-nowrap
${activeTab === tab.id ? 'text-ink' : 'text-concrete hover:text-ink/60'}`}
>
<span className={activeTab === tab.id ? 'text-ink' : 'text-concrete'}>{tab.icon}</span>
{tab.label}
{activeTab === tab.id && (
<motion.div
layoutId="activeSettingsTabLine"
className="absolute bottom-0 left-0 right-0 h-0.5 bg-ink"
transition={{ type: 'spring', bounce: 0.1, duration: 0.8 }}
/>
)}
</button>
))}
</nav>
</header>
);
};