Skip to content

Commit 8c83449

Browse files
authored
server : (webui) revamp the input area, plus many small UI improvements (#13365)
* rework the input area * process selected file * change all icons to heroicons * fix thought process collapse * move conversation more menu to sidebar * sun icon --> moon icon * rm default system message * stricter upload file check, only allow image if server has mtmd * build it * add renaming * better autoscroll * build * add conversation group * fix scroll * extra context first, then user input in the end * fix <hr> tag * clean up a bit * build * add mb-3 for <pre> * throttle adjustTextareaHeight to make it less laggy * (nits) missing padding in sidebar * rm stray console log
1 parent 1a844be commit 8c83449

23 files changed

+1142
-320
lines changed

common/chat.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ std::vector<common_chat_msg> common_chat_msgs_parse_oaicompat(const json & messa
125125
msgs.push_back(msg);
126126
}
127127
} catch (const std::exception & e) {
128-
throw std::runtime_error("Failed to parse messages: " + std::string(e.what()) + "; messages = " + messages.dump(2));
128+
// @ngxson : disable otherwise it's bloating the API response
129+
// printf("%s\n", std::string("; messages = ") + messages.dump(2));
130+
throw std::runtime_error("Failed to parse messages: " + std::string(e.what()));
129131
}
130132

131133
return msgs;

tools/server/public/index.html.gz

25.9 KB
Binary file not shown.

tools/server/webui/package-lock.json

+92-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/server/webui/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"postcss": "^8.4.49",
2525
"react": "^18.3.1",
2626
"react-dom": "^18.3.1",
27+
"react-dropzone": "^14.3.8",
28+
"react-hot-toast": "^2.5.2",
2729
"react-markdown": "^9.0.3",
2830
"react-router": "^7.1.5",
2931
"rehype-highlight": "^7.0.2",

tools/server/webui/src/App.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Sidebar from './components/Sidebar';
44
import { AppContextProvider, useAppContext } from './utils/app.context';
55
import ChatScreen from './components/ChatScreen';
66
import SettingDialog from './components/SettingDialog';
7+
import { Toaster } from 'react-hot-toast';
78

89
function App() {
910
return (
@@ -40,6 +41,7 @@ function AppLayout() {
4041
onClose={() => setShowSettings(false)}
4142
/>
4243
}
44+
<Toaster />
4345
</>
4446
);
4547
}

tools/server/webui/src/Config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const CONFIG_DEFAULT = {
1212
// Note: in order not to introduce breaking changes, please keep the same data type (number, string, etc) if you want to change the default value. Do not use null or undefined for default value.
1313
// Do not use nested objects, keep it single level. Prefix the key if you need to group them.
1414
apiKey: '',
15-
systemMessage: 'You are a helpful assistant.',
15+
systemMessage: '',
1616
showTokensPerSecond: false,
1717
showThoughtInProgress: false,
1818
excludeThoughtOnReq: true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { DocumentTextIcon, XMarkIcon } from '@heroicons/react/24/outline';
2+
import { MessageExtra } from '../utils/types';
3+
import { useState } from 'react';
4+
import { classNames } from '../utils/misc';
5+
6+
export default function ChatInputExtraContextItem({
7+
items,
8+
removeItem,
9+
clickToShow,
10+
}: {
11+
items?: MessageExtra[];
12+
removeItem?: (index: number) => void;
13+
clickToShow?: boolean;
14+
}) {
15+
const [show, setShow] = useState(-1);
16+
const showingItem = show >= 0 ? items?.[show] : undefined;
17+
18+
if (!items) return null;
19+
20+
return (
21+
<div className="flex flex-row gap-4 overflow-x-auto py-2 px-1 mb-1">
22+
{items.map((item, i) => (
23+
<div
24+
className="indicator"
25+
key={i}
26+
onClick={() => clickToShow && setShow(i)}
27+
>
28+
{removeItem && (
29+
<div className="indicator-item indicator-top">
30+
<button
31+
className="btn btn-neutral btn-sm w-4 h-4 p-0 rounded-full"
32+
onClick={() => removeItem(i)}
33+
>
34+
<XMarkIcon className="h-3 w-3" />
35+
</button>
36+
</div>
37+
)}
38+
39+
<div
40+
className={classNames({
41+
'flex flex-row rounded-md shadow-sm items-center m-0 p-0': true,
42+
'cursor-pointer hover:shadow-md': !!clickToShow,
43+
})}
44+
>
45+
{item.type === 'imageFile' ? (
46+
<>
47+
<img
48+
src={item.base64Url}
49+
alt={item.name}
50+
className="w-14 h-14 object-cover rounded-md"
51+
/>
52+
</>
53+
) : (
54+
<>
55+
<div className="w-14 h-14 flex items-center justify-center">
56+
<DocumentTextIcon className="h-8 w-14 text-base-content/50" />
57+
</div>
58+
59+
<div className="text-xs pr-4">
60+
<b>{item.name ?? 'Extra content'}</b>
61+
</div>
62+
</>
63+
)}
64+
</div>
65+
</div>
66+
))}
67+
68+
{showingItem && (
69+
<dialog className="modal modal-open">
70+
<div className="modal-box">
71+
<div className="flex justify-between items-center mb-4">
72+
<b>{showingItem.name ?? 'Extra content'}</b>
73+
<button className="btn btn-ghost btn-sm">
74+
<XMarkIcon className="h-5 w-5" onClick={() => setShow(-1)} />
75+
</button>
76+
</div>
77+
{showingItem.type === 'imageFile' ? (
78+
<img src={showingItem.base64Url} alt={showingItem.name} />
79+
) : (
80+
<div className="overflow-x-auto">
81+
<pre className="whitespace-pre-wrap break-words text-sm">
82+
{showingItem.content}
83+
</pre>
84+
</div>
85+
)}
86+
</div>
87+
<div className="modal-backdrop" onClick={() => setShow(-1)}></div>
88+
</dialog>
89+
)}
90+
</div>
91+
);
92+
}

0 commit comments

Comments
 (0)