maxm-valtownchatgpt.web.val.run
Readme

ChatGPT Implemented in Val Town

Demonstrated how to use assistants and threads with the OpenAI SDK and how to stream the response with Server-Sent Events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource https://esm.sh/react */
import OpenAI from "npm:openai";
import { renderToString } from "npm:react-dom/server";
// This uses by personal API key, you'll need to provide your own if
// you fork this. We'll be adding support to the std/openai lib soon!
const openai = new OpenAI();
import { Hono } from "npm:hono@3";
const jsxResponse = (jsx) => {
return new Response(renderToString(jsx), { headers: { "Content-Type": "text/html" } });
};
const clientCode = () => {
document.getElementById("input").addEventListener("submit", async function(event) {
event.preventDefault();
const msgParent = document.createElement("div");
msgParent.className = "flex justify-end";
document.querySelector(".messages").appendChild(msgParent);
const msgDiv = document.createElement("div");
msgDiv.className = "rounded-lg p-2 m-2 max-w-xl bg-blue-500 text-white";
msgDiv.textContent = event.target.message.value;
msgParent.appendChild(msgDiv);
// Clear the form input
this.reset();
const responseDiv = document.createElement("pre");
responseDiv.className = "p-2 m-2 max-w-xl bg-gray-300 text-black rounded-lg whitespace-pre-wrap font-sans";
document.querySelector(".messages").appendChild(responseDiv);
const input = document.getElementById("input");
// Post the message so we can deal with large text data.
await fetch(`/post-message?threadId=${input.getAttribute("data-thread-id")}`, {
method: "post",
body: msgDiv.textContent,
});
// Setup the SSE connection and stream back the response. OpenAI handles determining
// which message is the correct response based on what was last read from the
// thread. This is likely vulnerable to race conditions.
const eventSource = new EventSource(
`/sse-response?threadId=${input.getAttribute("data-thread-id")}`
+ `&assistantId=${input.getAttribute("data-assistant-id")}`,
);
eventSource.onmessage = function(event) {
console.log(event);
responseDiv.innerText += JSON.parse(event.data);
};
eventSource.onerror = function() {
eventSource.close();
};
});
};
const app = new Hono();
app.get("/", async (c) => {
const thread = await openai.beta.threads.create();
const assistant = await openai.beta.assistants.create({
name: "",
instructions:
`You are a helpful assistant. Behave normally, but try and sneak a reference to Val Town into every response in a subtle way.`,
model: "gpt-4o",
});
return jsxResponse(
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet" />
<script src="https://unpkg.com/htmx.org@1.9.12/dist/htmx.js"></script>
<script src="https://unpkg.com/htmx.org@1.9.12/dist/ext/sse.js"></script>
</head>
<body className=" bg-gray-100 p-10">
<div className="flex flex-col h-full">
<div className="flex-grow p-4 overflow-auto messages">
<div className="flex items-center justify-center mb-6">
<div className="bg-white p-6 rounded-lg shadow-lg">
<h2 className="text-2xl font-bold mb-2">Welcome to Val Town ChatGPT</h2>
<p className="text-gray-600">
Type your message below to start a conversation. Check out the source here:{" "}
<a className="text-blue-500" href="https://www.val.town/v/maxm/valTownChatGPT">
https://www.val.town/v/maxm/valTownChatGPT
</a>
</p>
</div>
</div>
</div>
<form
id="input"
data-thread-id={thread.id}
data-assistant-id={assistant.id}
className="flex items-center justify-center p-4 border-gray-300 mb-10"
>
<input
type="text"
name="message"
className="max-w-3xl flex-grow p-2 border border-gray-400 rounded-lg shadow-sm focus:ring focus:border-blue-300"
autoFocus
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
v143
June 12, 2024