Skip to content

Commit 20185f1

Browse files
committed
htmx for suggestions
1 parent cf60235 commit 20185f1

9 files changed

+99
-152
lines changed

src/components/ChatBox.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { Suggestions } from "./Suggestions";
2+
13
export const ChatBox = () => (
24
<form
35
hx-post="/chat"
46
style={{
57
width: "100%",
6-
display: "flex",
78
}}
89
hx-target="#nextMessage"
910
hx-swap="beforebegin scroll:bottom"
@@ -51,5 +52,6 @@ export const ChatBox = () => (
5152
<span>Send</span>
5253
</button>
5354
</div>
55+
<Suggestions />
5456
</form>
5557
);

src/components/ChatView.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export const ChatView = () => (
4242
</div>
4343

4444
<ChatBox />
45-
<Suggestions />
4645
<Footer />
4746
</div>
4847
);

src/components/Footer.tsx

+15-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@ export const Footer = () => (
99
padding: "1rem",
1010
}}
1111
>
12-
<button class="toggle-button" onclick="toggleShowControls()">
12+
<button
13+
style={{
14+
border: "1px solid #ddd",
15+
borderRadius: "20rem",
16+
flexBasis: "content",
17+
fontSize: "1rem",
18+
backgroundColor: "white",
19+
position: "absolute",
20+
left: "1rem",
21+
width: "55px",
22+
height: "55px",
23+
}}
24+
class="toggle-button"
25+
onclick="toggleShowControls()"
26+
>
1327
<span class="up-caret"></span>
1428
<span class="down-caret"></span>
1529
</button>

src/components/LandingView.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const LandingView = () => (
3636
A distraction-free LLM chat web app optimized for Kindle. The perfect companion for your book. Powered by
3737
Mixtral from Mistral AI. Mainly tested on Kindle Paperwhites.
3838
</p>
39-
4039
<p
4140
style={{
4241
margin: "2rem 0",

src/components/Message.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
export const Message = ({ message, suggestions }: { message: string; suggestions?: string }) => (
2-
<p class="message">
2+
<p
3+
style={{
4+
whiteSpace: "pre-wrap",
5+
}}
6+
>
37
<b>Kindllm</b>: {message}
48
</p>
59
);

src/components/Suggestions.tsx

+40-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
export const Suggestions = () => (
1+
export const Suggestions = ({ suggestions }: { suggestions?: string[] }) => (
22
<div
3+
id="suggestions-container"
34
class="suggestions-container"
45
style={{
56
padding: "0.5rem 1rem",
67
}}
78
>
8-
<div id="suggestions-retry">
9+
<div id="suggestions">
10+
{(suggestions || []).map((suggestion) => (
11+
<Suggestion suggestion={suggestion} />
12+
))}
13+
</div>
14+
<div
15+
id="suggestions-retry"
16+
style={{
17+
opacity: suggestions?.length == 0 ? 1 : 0,
18+
textAlign: "center",
19+
}}
20+
>
921
No good follow-up suggestions found
1022
<button
23+
id="suggestions-retry-button"
1124
style={{
1225
border: "1px solid #ddd",
1326
marginLeft: "1rem",
@@ -17,11 +30,34 @@ export const Suggestions = () => (
1730
fontSize: "1rem",
1831
backgroundColor: "white",
1932
}}
20-
onclick="retrySuggestions()"
33+
hx-post="/suggestions"
34+
hx-trigger="click,retry"
35+
hx-target="#suggestions-container"
36+
hx-swap="outerHTML"
2137
>
2238
Retry
2339
</button>
2440
</div>
25-
<div id="suggestions"></div>
2641
</div>
2742
);
43+
44+
const Suggestion = ({ suggestion }: { suggestion: string }) => (
45+
<button
46+
onclick={`setMessageAndSubmit("${suggestion}")`}
47+
style={{
48+
border: "1px solid black",
49+
padding: "1rem 2rem",
50+
borderRadius: "10rem",
51+
textAlign: "left",
52+
fontSize: "0.8rem",
53+
marginBottom: "0.5rem",
54+
overflow: "hidden",
55+
width: "100%",
56+
height: "55px",
57+
display: "table-cell",
58+
verticalAlign: "middle",
59+
}}
60+
>
61+
{suggestion}
62+
</button>
63+
);

src/index.tsx

+3-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { LandingView } from "./components/LandingView";
88
import { PrivacyView } from "./components/Privacy";
99
import { About } from "./components/About";
1010
import { getNextMessage, getSuggestions } from "./llm";
11+
import { Suggestions } from "./components/Suggestions";
1112

1213
const ENABLE_NON_KINDLE = true; // Set to true to test on non-Kindle devices
1314

@@ -65,14 +66,9 @@ app.post(
6566
}
6667

6768
const { messages } = c.req.valid("form");
69+
const suggestions = await getSuggestions(c.env.API_KEY, messages);
6870

69-
const suggestionsCompletion = await getSuggestions(c.env.API_KEY, messages);
70-
71-
if (!suggestionsCompletion) {
72-
return c.text("");
73-
}
74-
75-
return c.text(suggestionsCompletion.choices[0].message.content || "");
71+
return c.html(<Suggestions suggestions={suggestions.slice(0, 3)} />);
7672
}
7773
);
7874

src/llm.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export async function getNextMessage(apiKey: string, messages: string, message:
4444
return messageContent;
4545
}
4646

47-
export async function getSuggestions(apiKey: string, messages: string) {
47+
export async function getSuggestions(apiKey: string, messages: string): Promise<string[]> {
4848
const messageHistory = messages.split("||||").map((m) => {
4949
if (m.startsWith("<b>Kindllm</b>: ")) {
5050
return {
@@ -62,7 +62,7 @@ export async function getSuggestions(apiKey: string, messages: string) {
6262
const message = messageHistory[messageHistory.length - 1].content;
6363
const lastMessage = messageHistory[messageHistory.length - 2];
6464

65-
if (!message || !lastMessage) return;
65+
if (!message || !lastMessage) return [];
6666

6767
const suggestionsSystemPrompt = {
6868
role: "system",
@@ -82,13 +82,14 @@ export async function getSuggestions(apiKey: string, messages: string) {
8282
apiKey: apiKey,
8383
});
8484

85-
const suggestions = await openai.chat.completions.create({
85+
const response = await openai.chat.completions.create({
8686
messages: suggestionsPrompt,
8787
model: MODEL,
8888
response_format: {
8989
type: "json_object",
9090
},
9191
});
9292

93-
return suggestions;
93+
const jsonContent = JSON.parse(response.choices[0].message.content || "{}");
94+
return jsonContent?.suggestions || [];
9495
}

0 commit comments

Comments
 (0)