feat: LLM provider switcher (Claude/Groq) in settings tab
All checks were successful
Deploy / deploy (push) Successful in 1m27s

This commit is contained in:
Cosmo
2026-05-01 12:42:24 +00:00
parent f8c842b474
commit 6199db2977
4 changed files with 224 additions and 130 deletions

View File

@@ -765,12 +765,57 @@ function SettingsTab({ city, onCityChange, onLogout, theme, onThemeChange }: { c
textAlign: 'center', letterSpacing: '4px',
}
const [voiceProvider, setVoiceProvider] = useState<'anthropic' | 'groq'>('anthropic')
useEffect(() => {
fetch('/api/settings').then(r => r.json()).then(s => {
setVoiceProvider(s.voiceProvider || 'anthropic')
}).catch(() => {})
}, [])
const handleProviderChange = async (p: 'anthropic' | 'groq') => {
setVoiceProvider(p)
await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ voiceProvider: p }),
}).catch(() => {})
}
const currentCity = CITIES.find(c => c.id === city) || CITIES[0]
return (
<div style={{ flex: 1, overflowY: 'auto', WebkitOverflowScrolling: 'touch' as any, touchAction: 'pan-y', padding: '24px', display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 560, margin: '0 auto', width: '100%' }}>
<h2 style={{ fontSize: 24, fontWeight: 800, color: 'var(--text-primary)', margin: '0 0 8px', letterSpacing: '-0.5px' }}>Настройки</h2>
{/* Голосовой агент */}
<div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
<span style={{ fontSize: 18 }}>🤖</span>
<span style={{ fontSize: 15, fontWeight: 600, color: 'var(--text-primary)' }}>Голосовой агент</span>
</div>
<div style={{ display: 'flex', gap: 10 }}>
{(['anthropic', 'groq'] as const).map(p => (
<button
key={p}
onClick={() => handleProviderChange(p)}
style={{
flex: 1, padding: '12px 0', borderRadius: 14,
background: voiceProvider === p ? 'rgba(99,102,241,0.15)' : 'rgba(255,255,255,0.03)',
border: `1px solid ${voiceProvider === p ? 'rgba(99,102,241,0.4)' : 'rgba(255,255,255,0.07)'}`,
color: voiceProvider === p ? '#a5b4fc' : 'var(--text-secondary)',
fontSize: 13, fontWeight: 600, cursor: 'pointer', transition: 'all 0.2s ease',
}}
>
{p === 'anthropic' ? '🧠 Claude Haiku' : '⚡ Groq Llama'}
</button>
))}
</div>
<div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 8, lineHeight: 1.5 }}>
{voiceProvider === 'anthropic' ? 'Claude Haiku — точнее, лучше с tools. Платный (~$0.001/запрос).' : 'Groq Llama — быстро, бесплатно. Иногда глючит с tools.'}
</div>
</div>
{/* City selector */}
<div style={{ background: 'var(--card-bg)', border: '1px solid var(--card-border)', borderRadius: 22, padding: '22px 24px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>