Example of using Hono to stream OpenAI's streamed chat responses

Unfortunately this doesn't work on val.town — use Deno Deploy instead

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
import { Hono } from "npm:hono";
import { cors } from 'npm:hono/cors'
import { stream, streamText, streamSSE } from "npm:hono/streaming";
import { OpenAI } from "npm:openai";
const app = new Hono();
const openai = new OpenAI();
app.use('*', cors({
origin: '*',
allowMethods: ['GET'],
allowHeaders: ['Content-Type'],
}))
// Set CORS and headers for SSE
app.use('/chat, /chat/*', async (c, next) => {
c.header('Content-Type', 'text/event-stream');
c.header('Cache-Control', 'no-cache');
c.header('Connection', 'keep-alive');
await next();
});
// const SOURCE_URL = ""; // leave blank for deno deploy / native
// const SOURCE_URL = "https://yawnxyz-openAIHonoChatStreamSample.web.val.run"; // valtown as generator - no SSE
const SOURCE_URL = "https://funny-crow-81.deno.dev"; // deno deploy as generator
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>OpenAI Streaming Example</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#output {
white-space: pre-wrap;
border: 1px solid #ccc;
padding: 10px;
min-height: 100px;
}
</style>
</head>
<body>
<h1>OpenAI Streaming Example</h1>
<label for="prompt">Prompt:</label>
<input type="text" id="prompt" value="tell me a joke" />
<button onclick="getResponse()">Submit</button>
<div id="output"></div>
<script>
const outputDiv = document.getElementById('output');
function getResponse() {
const prompt = document.getElementById('prompt').value;
const url = "${SOURCE_URL}/chat?p=" + encodeURIComponent(prompt);
outputDiv.textContent = 'Loading...';
const eventSource = new EventSource(url);
let isFirstChunk = true;
eventSource.onmessage = (event) => {
if (event.data === "[DONE]") {
eventSource.close();
} else {
const data = JSON.parse(event.data);
if (data.error) {
outputDiv.textContent = "Error: " + data.error;
} else {
if (isFirstChunk) {
outputDiv.textContent = data.token;
isFirstChunk = false;
} else {
outputDiv.textContent += data.token;
}
}
}
};
eventSource.onerror = (error) => {
console.error('EventSource error:', error);
outputDiv.textContent = 'Error occurred.';
};
eventSource.addEventListener('close', () => {
console.log('Connection closed.');
});
}
</script>
</body>
</html>
`;
const htmlContent2 = `
<!DOCTYPE html>
<html>
1
Next