Spaces:
Running
Running
Add ChatSettings component with slider-based parameter control
Browse filesmodified: README.md
modified: src/components/ChatInterface.jsx
new file: src/components/ChatSettings.jsx
new file: src/hooks/useChatSettings.js
- README.md +1 -0
- src/components/ChatInterface.jsx +15 -1
- src/components/ChatSettings.jsx +62 -0
- src/hooks/useChatSettings.js +24 -0
README.md
CHANGED
|
@@ -18,6 +18,7 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
|
|
| 18 |
## Features
|
| 19 |
|
| 20 |
- Support user input of Hugging Face Access Token.
|
|
|
|
| 21 |
- Support UI to send user input and get response of the chatbot.
|
| 22 |
- Keep user input and response in chat history.
|
| 23 |
|
|
|
|
| 18 |
## Features
|
| 19 |
|
| 20 |
- Support user input of Hugging Face Access Token.
|
| 21 |
+
- Support tuning system prompt and parameters: temperature, top_p, max_tokens.
|
| 22 |
- Support UI to send user input and get response of the chatbot.
|
| 23 |
- Keep user input and response in chat history.
|
| 24 |
|
src/components/ChatInterface.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import { useState } from "react";
|
|
|
|
| 2 |
import MessageInput from "./MessageInput";
|
| 3 |
import MessagePair from "./MessagePair";
|
| 4 |
import TokenInput from "./TokenInput";
|
|
@@ -6,16 +7,24 @@ import TokenInput from "./TokenInput";
|
|
| 6 |
export default function ChatInterface() {
|
| 7 |
const [hfClient, setHFClient] = useState(null);
|
| 8 |
const [chatHistory, setChatHistory] = useState([]);
|
|
|
|
| 9 |
|
| 10 |
const handleMessageSend = async (message) => {
|
| 11 |
if (!hfClient) {
|
| 12 |
alert("Please enter a valid Hugging Face token first.");
|
| 13 |
return;
|
| 14 |
}
|
|
|
|
| 15 |
|
| 16 |
const result = await hfClient.chatCompletion({
|
| 17 |
model: "openai/gpt-oss-20b",
|
| 18 |
-
messages: [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
});
|
| 20 |
|
| 21 |
const assistantReply = result.choices[0].message.content;
|
|
@@ -43,6 +52,11 @@ export default function ChatInterface() {
|
|
| 43 |
<TokenInput onHFClientReady={handleHFClientReady} />
|
| 44 |
</div>
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
{/* Input area */}
|
| 47 |
<div>
|
| 48 |
<MessageInput onSend={handleMessageSend} />
|
|
|
|
| 1 |
import { useState } from "react";
|
| 2 |
+
import ChatSettings from "./ChatSettings";
|
| 3 |
import MessageInput from "./MessageInput";
|
| 4 |
import MessagePair from "./MessagePair";
|
| 5 |
import TokenInput from "./TokenInput";
|
|
|
|
| 7 |
export default function ChatInterface() {
|
| 8 |
const [hfClient, setHFClient] = useState(null);
|
| 9 |
const [chatHistory, setChatHistory] = useState([]);
|
| 10 |
+
const [chatSettings, setChatSettings] = useState();
|
| 11 |
|
| 12 |
const handleMessageSend = async (message) => {
|
| 13 |
if (!hfClient) {
|
| 14 |
alert("Please enter a valid Hugging Face token first.");
|
| 15 |
return;
|
| 16 |
}
|
| 17 |
+
if (!chatSettings) return;
|
| 18 |
|
| 19 |
const result = await hfClient.chatCompletion({
|
| 20 |
model: "openai/gpt-oss-20b",
|
| 21 |
+
messages: [
|
| 22 |
+
{ role: "system", content: chatSettings.system },
|
| 23 |
+
{ role: "user", content: message },
|
| 24 |
+
],
|
| 25 |
+
temperature: chatSettings.temperature,
|
| 26 |
+
top_p: chatSettings.top_p,
|
| 27 |
+
max_tokens: chatSettings.max_tokens,
|
| 28 |
});
|
| 29 |
|
| 30 |
const assistantReply = result.choices[0].message.content;
|
|
|
|
| 52 |
<TokenInput onHFClientReady={handleHFClientReady} />
|
| 53 |
</div>
|
| 54 |
|
| 55 |
+
{/* Chat settings */}
|
| 56 |
+
<div>
|
| 57 |
+
<ChatSettings onChange={(s) => setChatSettings(s)} />
|
| 58 |
+
</div>
|
| 59 |
+
|
| 60 |
{/* Input area */}
|
| 61 |
<div>
|
| 62 |
<MessageInput onSend={handleMessageSend} />
|
src/components/ChatSettings.jsx
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useChatSettings } from "../hooks/useChatSettings";
|
| 2 |
+
|
| 3 |
+
export default function ChatSettings({ onChange }) {
|
| 4 |
+
const [settings, setSettings] = useChatSettings(onChange);
|
| 5 |
+
|
| 6 |
+
return (
|
| 7 |
+
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
|
| 8 |
+
<input
|
| 9 |
+
type="text"
|
| 10 |
+
value={settings.system}
|
| 11 |
+
onChange={(e) => setSettings({ ...settings, system: e.target.value })}
|
| 12 |
+
placeholder="System prompt (e.g. You are a helpful assistant)"
|
| 13 |
+
style={{ padding: "10px", fontSize: "16px" }}
|
| 14 |
+
/>
|
| 15 |
+
|
| 16 |
+
<label>
|
| 17 |
+
Temperature: {settings.temperature}
|
| 18 |
+
<input
|
| 19 |
+
type="range"
|
| 20 |
+
min="0"
|
| 21 |
+
max="2"
|
| 22 |
+
step="0.1"
|
| 23 |
+
value={settings.temperature}
|
| 24 |
+
onChange={(e) =>
|
| 25 |
+
setSettings({
|
| 26 |
+
...settings,
|
| 27 |
+
temperature: parseFloat(e.target.value),
|
| 28 |
+
})
|
| 29 |
+
}
|
| 30 |
+
/>
|
| 31 |
+
</label>
|
| 32 |
+
|
| 33 |
+
<label>
|
| 34 |
+
Top-p: {settings.top_p}
|
| 35 |
+
<input
|
| 36 |
+
type="range"
|
| 37 |
+
min="0"
|
| 38 |
+
max="1"
|
| 39 |
+
step="0.05"
|
| 40 |
+
value={settings.top_p}
|
| 41 |
+
onChange={(e) =>
|
| 42 |
+
setSettings({ ...settings, top_p: parseFloat(e.target.value) })
|
| 43 |
+
}
|
| 44 |
+
/>
|
| 45 |
+
</label>
|
| 46 |
+
|
| 47 |
+
<label>
|
| 48 |
+
Max tokens: {settings.max_tokens}
|
| 49 |
+
<input
|
| 50 |
+
type="range"
|
| 51 |
+
min="50"
|
| 52 |
+
max="1024"
|
| 53 |
+
step="50"
|
| 54 |
+
value={settings.max_tokens}
|
| 55 |
+
onChange={(e) =>
|
| 56 |
+
setSettings({ ...settings, max_tokens: parseInt(e.target.value) })
|
| 57 |
+
}
|
| 58 |
+
/>
|
| 59 |
+
</label>
|
| 60 |
+
</div>
|
| 61 |
+
);
|
| 62 |
+
}
|
src/hooks/useChatSettings.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useEffect, useRef, useState } from "react";
|
| 2 |
+
|
| 3 |
+
// Manage chat settings and trigger onChange when settings change
|
| 4 |
+
export function useChatSettings(onChange) {
|
| 5 |
+
const [settings, setSettings] = useState({
|
| 6 |
+
system: "You are a helpful assistant.",
|
| 7 |
+
temperature: 0.7,
|
| 8 |
+
top_p: 1,
|
| 9 |
+
max_tokens: 512,
|
| 10 |
+
});
|
| 11 |
+
|
| 12 |
+
// Always use the latest onChange without triggering effect
|
| 13 |
+
const stableOnChange = useRef(onChange);
|
| 14 |
+
useEffect(() => {
|
| 15 |
+
stableOnChange.current = onChange;
|
| 16 |
+
}, [onChange]);
|
| 17 |
+
|
| 18 |
+
// Trigger onChange only when settings change
|
| 19 |
+
useEffect(() => {
|
| 20 |
+
stableOnChange.current(settings);
|
| 21 |
+
}, [settings]);
|
| 22 |
+
|
| 23 |
+
return [settings, setSettings];
|
| 24 |
+
}
|