KBaba7/llama.cpp
0
1import { useState } from 'react';2import { useAppContext } from '../utils/app.context';3import { CONFIG_DEFAULT, CONFIG_INFO } from '../Config';4import { isDev } from '../Config';5import StorageUtils from '../utils/storage';6 7type SettKey = keyof typeof CONFIG_DEFAULT;8 9const COMMON_SAMPLER_KEYS: SettKey[] = [10 'temperature',11 'top_k',12 'top_p',13 'min_p',14 'max_tokens',15];16const OTHER_SAMPLER_KEYS: SettKey[] = [17 'dynatemp_range',18 'dynatemp_exponent',19 'typical_p',20 'xtc_probability',21 'xtc_threshold',22];23const PENALTY_KEYS: SettKey[] = [24 'repeat_last_n',25 'repeat_penalty',26 'presence_penalty',27 'frequency_penalty',28 'dry_multiplier',29 'dry_base',30 'dry_allowed_length',31 'dry_penalty_last_n',32];33 34export default function SettingDialog({35 show,36 onClose,37}: {38 show: boolean;39 onClose: () => void;40}) {41 const { config, saveConfig } = useAppContext();42 43 // clone the config object to prevent direct mutation44 const [localConfig, setLocalConfig] = useState<typeof CONFIG_DEFAULT>(45 JSON.parse(JSON.stringify(config))46 );47 48 const resetConfig = () => {49 if (window.confirm('Are you sure to reset all settings?')) {50 setLocalConfig(CONFIG_DEFAULT);51 }52 };53 54 const handleSave = () => {55 saveConfig(localConfig);56 onClose();57 };58 59 const debugImportDemoConv = async () => {60 const res = await fetch('/demo-conversation.json');61 const demoConv = await res.json();62 StorageUtils.remove(demoConv.id);63 for (const msg of demoConv.messages) {64 StorageUtils.appendMsg(demoConv.id, msg);65 }66 onClose();67 };68 69 return (70 <dialog className={`modal ${show ? 'modal-open' : ''}`}>71 <div className="modal-box">72 <h3 className="text-lg font-bold mb-6">Settings</h3>73 <div className="h-[calc(90vh-12rem)] overflow-y-auto">74 <p className="opacity-40 mb-6">75 Settings below are saved in browser's localStorage76 </p>77 78 <SettingsModalShortInput79 configKey="apiKey"80 configDefault={CONFIG_DEFAULT}81 value={localConfig.apiKey}82 onChange={(value) =>83 setLocalConfig({ ...localConfig, apiKey: value })84 }85 />86 87 <label className="form-control mb-2">88 <div className="label">89 System Message (will be disabled if left empty)90 </div>91 <textarea92 className="textarea textarea-bordered h-24"93 placeholder={`Default: ${CONFIG_DEFAULT.systemMessage}`}94 value={localConfig.systemMessage}95 onChange={(e) =>96 setLocalConfig({97 ...localConfig,98 systemMessage: e.target.value,99 })100 }101 />102 </label>103 104 {COMMON_SAMPLER_KEYS.map((key) => (105 <SettingsModalShortInput106 key={key}107 configKey={key}108 configDefault={CONFIG_DEFAULT}109 value={localConfig[key]}110 onChange={(value) =>111 setLocalConfig({ ...localConfig, [key]: value })112 }113 />114 ))}115 116 <details className="collapse collapse-arrow bg-base-200 mb-2 overflow-visible">117 <summary className="collapse-title font-bold">118 Other sampler settings119 </summary>120 <div className="collapse-content">121 <SettingsModalShortInput122 label="Samplers queue"123 configKey="samplers"124 configDefault={CONFIG_DEFAULT}125 value={localConfig.samplers}126 onChange={(value) =>127 setLocalConfig({ ...localConfig, samplers: value })128 }129 />130 {OTHER_SAMPLER_KEYS.map((key) => (131 <SettingsModalShortInput132 key={key}133 configKey={key}134 configDefault={CONFIG_DEFAULT}135 value={localConfig[key]}136 onChange={(value) =>137 setLocalConfig({ ...localConfig, [key]: value })138 }139 />140 ))}141 </div>142 </details>143 144 <details className="collapse collapse-arrow bg-base-200 mb-2 overflow-visible">145 <summary className="collapse-title font-bold">146 Penalties settings147 </summary>148 <div className="collapse-content">149 {PENALTY_KEYS.map((key) => (150 <SettingsModalShortInput151 key={key}152 configKey={key}153 configDefault={CONFIG_DEFAULT}154 value={localConfig[key]}155 onChange={(value) =>156 setLocalConfig({ ...localConfig, [key]: value })157 }158 />159 ))}160 </div>161 </details>162 163 <details className="collapse collapse-arrow bg-base-200 mb-2 overflow-visible">164 <summary className="collapse-title font-bold">165 Reasoning models166 </summary>167 <div className="collapse-content">168 <div className="flex flex-row items-center mb-2">169 <input170 type="checkbox"171 className="checkbox"172 checked={localConfig.showThoughtInProgress}173 onChange={(e) =>174 setLocalConfig({175 ...localConfig,176 showThoughtInProgress: e.target.checked,177 })178 }179 />180 <span className="ml-4">181 Expand though process by default for generating message182 </span>183 </div>184 <div className="flex flex-row items-center mb-2">185 <input186 type="checkbox"187 className="checkbox"188 checked={localConfig.excludeThoughtOnReq}189 onChange={(e) =>190 setLocalConfig({191 ...localConfig,192 excludeThoughtOnReq: e.target.checked,193 })194 }195 />196 <span className="ml-4">197 Exclude thought process when sending request to API198 (Recommended for DeepSeek-R1)199 </span>200 </div>201 </div>202 </details>203 204 <details className="collapse collapse-arrow bg-base-200 mb-2 overflow-visible">205 <summary className="collapse-title font-bold">206 Advanced config207 </summary>208 <div className="collapse-content">209 {/* this button only shows in dev mode, used to import a demo conversation to test message rendering */}210 {isDev && (211 <div className="flex flex-row items-center mb-2">212 <button className="btn" onClick={debugImportDemoConv}>213 (debug) Import demo conversation214 </button>215 </div>216 )}217 <div className="flex flex-row items-center mb-2">218 <input219 type="checkbox"220 className="checkbox"221 checked={localConfig.showTokensPerSecond}222 onChange={(e) =>223 setLocalConfig({224 ...localConfig,225 showTokensPerSecond: e.target.checked,226 })227 }228 />229 <span className="ml-4">Show tokens per second</span>230 </div>231 <label className="form-control mb-2">232 <div className="label inline">233 Custom JSON config (For more info, refer to{' '}234 <a235 className="underline"236 href="https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md"237 target="_blank"238 rel="noopener noreferrer"239 >240 server documentation241 </a>242 )243 </div>244 <textarea245 className="textarea textarea-bordered h-24"246 placeholder='Example: { "mirostat": 1, "min_p": 0.1 }'247 value={localConfig.custom}248 onChange={(e) =>249 setLocalConfig({ ...localConfig, custom: e.target.value })250 }251 />252 </label>253 </div>254 </details>255 </div>256 257 <div className="modal-action">258 <button className="btn" onClick={resetConfig}>259 Reset to default260 </button>261 <button className="btn" onClick={onClose}>262 Close263 </button>264 <button className="btn btn-primary" onClick={handleSave}>265 Save266 </button>267 </div>268 </div>269 </dialog>270 );271}272 273function SettingsModalShortInput({274 configKey,275 configDefault,276 value,277 onChange,278 label,279}: {280 configKey: SettKey;281 configDefault: typeof CONFIG_DEFAULT;282 // eslint-disable-next-line @typescript-eslint/no-explicit-any283 value: any;284 onChange: (value: string) => void;285 label?: string;286}) {287 return (288 <label className="input input-bordered join-item grow flex items-center gap-2 mb-2">289 <div className="dropdown dropdown-hover">290 <div tabIndex={0} role="button" className="font-bold">291 {label || configKey}292 </div>293 <div className="dropdown-content menu bg-base-100 rounded-box z-10 w-64 p-2 shadow mt-4">294 {CONFIG_INFO[configKey] ?? '(no help message available)'}295 </div>296 </div>297 <input298 type="text"299 className="grow"300 placeholder={`Default: ${configDefault[configKey] || 'none'}`}301 value={value}302 onChange={(e) => onChange(e.target.value)}303 />304 </label>305 );306}307 