import React, { useState } from 'react'; import { UserSettings } from '../types'; import { X, Volume2, Check, Info, Mic2, Settings2, Key, Sparkles, Cpu } from 'lucide-react'; import Tooltip from './Tooltip'; import AudioDeviceSelector from './AudioDeviceSelector'; import { Button } from './ui/button'; import { Card } from './ui/card'; import { Badge } from './ui/badge'; import { ScrollArea } from './ui/scroll-area'; import { Input } from './ui/input'; import { Label } from './ui/label'; import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs'; interface SettingsModalProps { settings: UserSettings; onUpdate: (settings: UserSettings) => void; onClose: () => void; } interface VoiceOption { id: UserSettings['voiceName']; label: string; gender: 'Male' | 'Female' | 'Neutral'; style: string; description: string; } const VOICE_OPTIONS: VoiceOption[] = [ { id: 'Zephyr', label: 'Zephyr', gender: 'Neutral', style: 'Helpful', description: 'A balanced, clear, and professional tone suitable for most scenarios.' }, { id: 'Puck', label: 'Puck', gender: 'Male', style: 'Youthful', description: 'Energetic and friendly, ideal for peer-to-peer or informal interactions.' }, { id: 'Kore', label: 'Kore', gender: 'Female', style: 'Calm', description: 'Soothing and professional, perfect for clinical or high-stress roleplay.' }, { id: 'Charon', label: 'Charon', gender: 'Male', style: 'Authoritative', description: 'Deep and commanding, useful for workplace or boundary-testing scenarios.' }, { id: 'Fenrir', label: 'Fenrir', gender: 'Male', style: 'Rugged', description: 'Direct and matter-of-fact tone with a slightly more serious edge.' }, ]; const AVAILABLE_MODELS = [ { id: 'google/gemini-3.8-flash', name: 'Google Gemini 3.8 Flash', badge: 'Default • Frontier Ultra Low Latency' }, { id: 'google/gemini-3.7-flash', name: 'Google Gemini 3.7 Flash', badge: 'Fast • Hybrid Reasoning' }, { id: 'google/gemini-2.5-flash', name: 'Google Gemini 2.5 Flash', badge: 'Stable • Low Latency' }, { id: 'anthropic/claude-3.5-haiku', name: 'Anthropic Claude 3.5 Haiku', badge: 'Nuanced Reasoning' }, { id: 'meta-llama/llama-3.3-70b-instruct', name: 'Meta Llama 3.3 70B Instruct', badge: 'Open Weights' }, ]; const SettingsModal: React.FC = ({ settings, onUpdate, onClose }) => { const [activeTab, setActiveTab] = useState('voice'); const [openRouterKey, setOpenRouterKey] = useState(settings.openRouterApiKey || ''); const [selectedModel, setSelectedModel] = useState(settings.roleplayModel || 'google/gemini-3.8-flash'); const handleSave = () => { onUpdate({ ...settings, openRouterApiKey: openRouterKey.trim() || undefined, roleplayModel: selectedModel, supervisorModel: selectedModel, }); onClose(); }; return (

Application Settings

Powered by OpenRouter Engine

Voice & Audio OpenRouter AI

Vocal Profile

{VOICE_OPTIONS.map((voice) => ( onUpdate({ ...settings, voiceName: voice.id, genderPreference: voice.gender, vocalStyle: voice.style })} className={`flex flex-row items-center justify-between p-3.5 cursor-pointer transition-all ${settings.voiceName === voice.id ? 'bg-teal-50 border-teal-500 shadow-sm shadow-teal-100' : 'bg-white border-slate-200 hover:border-teal-200' }`} >
{voice.label} {voice.gender} • {voice.style}

{voice.description}

{settings.voiceName === voice.id && (
)}
))}

Input Microphone

onUpdate({ ...settings, preferredAudioDeviceId: deviceId })} />

OpenRouter API Key

Enter your OpenRouter API Key (sk-or-v1-...). All clinical roleplay, live insights, and scenario architect functions route through OpenRouter.

setOpenRouterKey(e.target.value)} className="font-mono text-xs" />
{AVAILABLE_MODELS.map((model) => ( setSelectedModel(model.id)} className={`p-3 cursor-pointer transition-all flex items-center justify-between border ${selectedModel === model.id ? 'bg-teal-50 border-teal-500 shadow-sm' : 'bg-white border-slate-200 hover:border-slate-300' }`} >

{model.name}

{model.id}

{model.badge}
))}

Your OpenRouter API Key is stored securely in your browser LocalStorage and is never shared or transmitted elsewhere.

); }; export default SettingsModal;