Skip to content

Commit 37314fc

Browse files
Add streaming chat TS example (#144)
* Add streaming chat TS example * Update README.md Co-authored-by: Fredrik Enestad <[email protected]> --------- Co-authored-by: Fredrik Enestad <[email protected]>
1 parent 9139b94 commit 37314fc

32 files changed

+4404
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ environment. Use the appropriate command for your system:
5353
|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|
5454
| [ts/hello-world](ts/hello-world) | REST API Starter | APIs |
5555
| [ts/ai-chat](ts/ai-chat) | LLM chat application which let's you create and chat with personalized bots. Integrates with OpenAI, Anthropic and Slack | Microservices, APIs, SQL Database, Pub/Sub, External Requests, Configs |
56+
| [ts/streaming-chat](ts/streaming-chat) | Simple Chat app using the Streaming API to create a WebSocket stream | Streaming API, Static Endpoint, Frontend |
5657
| [ts/simple-event-driven](ts/simple-event-driven) | Simple Event-Driven Application | Microservices, SQL Database, Pub/Sub, Secrets |
5758
| [ts/uptime](ts/uptime) | Event-Driven Architecture Starter (Uptime Monitor) | Microservices, SQL Databases, Pub/Sub, Cron Jobs |
5859
| [ts/gpt-functions](ts/gpt-functions) | ChatGPT Functions with Encore Example | APIs |

ts/streaming-chat/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.encore
2+
encore.gen.go
3+
encore.gen.cue
4+
/.encore
5+
node_modules
6+
/encore.gen

ts/streaming-chat/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Encore.ts Streaming Chat Example
2+
3+
This is an example of how to use the Streaming API in Encore.ts to create a WebSocket stream from a web frontend to a Encore.ts backend.
4+
5+
Learn more in our [Streaming API docs](https://encore.dev/docs/ts/primitives/streaming-apis)
6+
7+
![Chat app screenshot](./chat-room.png)
8+
9+
## Developing locally
10+
### Prerequisite: Installing Encore
11+
12+
If this is the first time you're using Encore, you first need to install the CLI that runs the local development
13+
environment. Use the appropriate command for your system:
14+
15+
- **macOS:** `brew install encoredev/tap/encore`
16+
- **Linux:** `curl -L https://encore.dev/install.sh | bash`
17+
- **Windows:** `iwr https://encore.dev/install.ps1 | iex`
18+
19+
When you have installed Encore, run to clone this example:
20+
21+
```bash
22+
encore app create --example=ts/streaming-chat
23+
```
24+
25+
## Running locally
26+
```bash
27+
encore run
28+
```
29+
30+
While `encore run` is running, open <http://localhost:4000/> to view the chat frontend.
31+
32+
You can also access Encore's [local developer dashboard](https://encore.dev/docs/observability/dev-dash) on <http://localhost:9400/> to view traces, API documentation, and more.
33+
34+
In you change the frontend then run `npm run build` to build a new frontend in the `dist` folder.
35+
36+
## Deployment
37+
38+
Deploy your application to a staging environment in Encore's free development cloud:
39+
40+
```bash
41+
git add -A .
42+
git commit -m 'Commit message'
43+
git push encore
44+
```
45+
46+
Then head over to the [Cloud Dashboard](https://app.encore.dev) to monitor your deployment and find your production URL.
47+
48+
From there you can also connect your own AWS or GCP account to use for deployment.
49+
50+
Now off you go into the clouds!

ts/streaming-chat/chat-room.png

304 KB
Loading

ts/streaming-chat/chat/chat.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { api, StreamInOut } from "encore.dev/api";
2+
import log from "encore.dev/log";
3+
4+
// Map to hold all connected streams
5+
const connectedStreams: Map<
6+
string,
7+
StreamInOut<PostMessage, ChatMessage>
8+
> = new Map();
9+
10+
// Object sent from the client to the server when establishing a connection
11+
interface HandshakeRequest {
12+
id: string;
13+
}
14+
15+
// Object sent from the client to the server when posting a message
16+
interface PostMessage {
17+
username: string;
18+
msg: string;
19+
}
20+
21+
// Object sent from the server to the client when receiving a message
22+
interface ChatMessage {
23+
userID: string;
24+
username: string;
25+
msg: string;
26+
}
27+
28+
export const chat = api.streamInOut<HandshakeRequest, PostMessage, ChatMessage>(
29+
{ expose: true, auth: false, path: "/chat" },
30+
async (handshake, stream) => {
31+
connectedStreams.set(handshake.id, stream);
32+
log.info("user connected", handshake);
33+
34+
try {
35+
// The stream object is an AsyncIterator that yields incoming messages.
36+
// The loop will continue as long as the client keeps the connection open.
37+
for await (const chatMessage of stream) {
38+
for (const [key, val] of connectedStreams) {
39+
try {
40+
// Send the users message to all connected clients.
41+
await val.send({ ...chatMessage, userID: handshake.id });
42+
} catch (err) {
43+
// If there is an error sending the message, remove the client from the map.
44+
connectedStreams.delete(key);
45+
log.error("error sending", err);
46+
}
47+
}
48+
}
49+
} catch (err) {
50+
// If there is an error reading from the stream, remove the client from the map.
51+
connectedStreams.delete(handshake.id);
52+
log.error("stream error", err);
53+
}
54+
55+
// When the client disconnects, remove them from the map.
56+
connectedStreams.delete(handshake.id);
57+
},
58+
);

ts/streaming-chat/encore.app

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"id": "",
3+
"lang": "typescript"
4+
}

ts/streaming-chat/frontend/dist/assets/index-37bfce13.js

Lines changed: 69 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ts/streaming-chat/frontend/dist/assets/index-e22bcfaf.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
7.71 KB
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<script src="https://cdn.tailwindcss.com"></script>
8+
<title>Encore.ts streaming chat example</title>
9+
<script type="module" crossorigin src="/assets/index-37bfce13.js"></script>
10+
<link rel="stylesheet" href="/assets/index-e22bcfaf.css">
11+
</head>
12+
<body>
13+
<div id="root"></div>
14+
15+
</body>
16+
</html>

0 commit comments

Comments
 (0)