feat: LLM provider switcher (Claude/Groq) in settings tab
All checks were successful
Deploy / deploy (push) Successful in 1m27s
All checks were successful
Deploy / deploy (push) Successful in 1m27s
This commit is contained in:
45
app/page.tsx
45
app/page.tsx
@@ -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 }}>
|
||||
|
||||
Reference in New Issue
Block a user