diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index cc75c36..fb0e319 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -42,6 +42,7 @@ export function streamChat( callbacks: ChatCallbacks, creator?: string, conversationId?: string, + personalityWeight?: number, ): AbortController { const controller = new AbortController(); @@ -67,6 +68,7 @@ export function streamChat( query, creator: creator ?? null, conversation_id: conversationId ?? null, + personality_weight: personalityWeight ?? 0, }), signal: controller.signal, }) diff --git a/frontend/src/components/ChatWidget.module.css b/frontend/src/components/ChatWidget.module.css index 3a36018..788906f 100644 --- a/frontend/src/components/ChatWidget.module.css +++ b/frontend/src/components/ChatWidget.module.css @@ -67,6 +67,68 @@ flex-shrink: 0; } +/* ── Personality slider ───────────────────────────────────── */ + +.sliderRow { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + border-bottom: 1px solid var(--color-border); + flex-shrink: 0; +} + +.sliderLabel { + font-size: 0.6875rem; + color: var(--color-text-secondary); + white-space: nowrap; + user-select: none; +} + +.slider { + flex: 1; + -webkit-appearance: none; + appearance: none; + height: 4px; + border-radius: 2px; + background: var(--color-border); + outline: none; + cursor: pointer; +} + +.slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 14px; + height: 14px; + border-radius: 50%; + background: var(--color-accent); + border: 2px solid var(--color-bg-surface); + box-shadow: 0 1px 4px var(--color-shadow-heavy); + cursor: pointer; + transition: transform 0.1s; +} + +.slider::-webkit-slider-thumb:hover { + transform: scale(1.15); +} + +.slider::-moz-range-thumb { + width: 14px; + height: 14px; + border-radius: 50%; + background: var(--color-accent); + border: 2px solid var(--color-bg-surface); + box-shadow: 0 1px 4px var(--color-shadow-heavy); + cursor: pointer; +} + +.slider::-moz-range-track { + height: 4px; + border-radius: 2px; + background: var(--color-border); +} + .headerTitle { font-size: 0.875rem; font-weight: 600; diff --git a/frontend/src/components/ChatWidget.tsx b/frontend/src/components/ChatWidget.tsx index 1f45a1e..65c2fc6 100644 --- a/frontend/src/components/ChatWidget.tsx +++ b/frontend/src/components/ChatWidget.tsx @@ -121,6 +121,7 @@ export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps) const [input, setInput] = useState(""); const [streaming, setStreaming] = useState(false); const [conversationId, setConversationId] = useState(undefined); + const [personalityWeight, setPersonalityWeight] = useState(0); const abortRef = useRef(null); const messagesEndRef = useRef(null); @@ -224,9 +225,10 @@ export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps) }, creatorName, cid, + personalityWeight, ); }, - [messages, streaming, creatorName, conversationId], + [messages, streaming, creatorName, conversationId, personalityWeight], ); const handleSubmit = (e: React.FormEvent) => { @@ -272,6 +274,22 @@ export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps) + {/* Personality slider */} +
+ Encyclopedic + setPersonalityWeight(parseFloat(e.target.value))} + aria-label="Personality weight" + /> + Creator Voice +
+ {/* Messages */}
{showSuggestions && (