Skip to content

Commit d70f76f

Browse files
committed
👌 IMPROVE: Examples and Nextjs
1 parent 7cb88f9 commit d70f76f

File tree

18 files changed

+1333
-588
lines changed

18 files changed

+1333
-588
lines changed

examples/everything/.env.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
# Pipes.
22
PIPE_LESS_WORDY=""
3-
PIPE_LESS_WORDY_STREAM=""

examples/everything/stream-text.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ console.log('STREAM-ON: streamText()');
66

77
// 1. Initiate the Pipe.
88
const pipeStreaming = new Pipe({
9-
apiKey: process.env.PIPE_LESS_WORDY_STREAM!,
9+
apiKey: process.env.PIPE_LESS_WORDY!,
1010
});
1111

1212
// 2. Generate a stream by asking a question

examples/nextjs/.env.local.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# !! SERVER SIDE ONLY !!
2+
# Pipes.
3+
LANGBASE_PIPE_LESS_WORDY=""
Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,21 @@
1-
import {Pipe} from 'langbase';
2-
import {NextRequest} from 'next/server';
1+
// import {Pipe} from 'langbase';
2+
import {Pipe} from './../../../../../../../packages/langbase/src/';
33

4-
export const runtime = 'edge';
4+
import {NextRequest} from 'next/server';
55

66
export async function POST(req: NextRequest) {
77
const {prompt} = await req.json();
88

99
// 1. Initiate the Pipe.
1010
const pipe = new Pipe({
11-
apiKey: process.env.LANGBASE_PIPE_LESS_WORDY_STREAM!,
11+
apiKey: process.env.LANGBASE_PIPE_LESS_WORDY!,
1212
});
1313

1414
// 2. Generate a stream by asking a question
1515
const stream = await pipe.streamText({
1616
messages: [{role: 'user', content: prompt}],
1717
});
1818

19-
// 3. Create a ReadableStream from the Langbase stream
20-
const readableStream = new ReadableStream({
21-
async start(controller) {
22-
for await (const chunk of stream) {
23-
controller.enqueue(JSON.stringify(chunk) + '\n');
24-
}
25-
controller.close();
26-
},
27-
});
28-
29-
// 4. Return the stream
30-
return new Response(readableStream, {
31-
headers: {
32-
'Content-Type': 'application/x-ndjson',
33-
},
34-
});
19+
// 3. Done, return the stream in a readable stream format.
20+
return new Response(stream.toReadableStream());
3521
}

examples/nextjs/app/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import GenerateTextRouteHandler from '@/components/langbase/generate-text-route-handler';
12
import StreamTextRouteHandler from '@/components/langbase/stream-text-route-handler';
23

34
export default function Home() {
@@ -12,9 +13,8 @@ export default function Home() {
1213
An AI agent that responds to your prompts.
1314
</p>
1415
</div>
15-
{/* <GenerateTextRouteHandler /> */}
16+
<GenerateTextRouteHandler />
1617
<StreamTextRouteHandler />
17-
{/* <GenerateTextServerAction /> */}
1818
</div>
1919
</div>
2020
);

examples/nextjs/components/langbase/action.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples/nextjs/components/langbase/generate-text-route-handler.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default function GenerateTextRouteHandler() {
3838
};
3939

4040
return (
41-
<>
41+
<div className="bg-neutral-200 rounded-md p-2 flex flex-col gap-2 w-full">
4242
<div className="flex flex-col gap-2 w-full">
4343
<p className="text-lg font-semibold">
4444
1. Generate Text{' '}
@@ -76,6 +76,6 @@ export default function GenerateTextRouteHandler() {
7676
<strong>Completion:</strong> {completion}
7777
</p>
7878
)}
79-
</>
79+
</div>
8080
);
8181
}

examples/nextjs/components/langbase/generate-text-server-action.tsx

Lines changed: 0 additions & 70 deletions
This file was deleted.

examples/nextjs/components/langbase/stream-text-route-handler.tsx

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,77 +3,55 @@
33
import {Button} from '@/components/ui/button';
44
import {Input} from '@/components/ui/input';
55
import {useState} from 'react';
6+
import {fromReadableStream} from './../../../../packages/langbase/src/lib/browser/stream';
67

7-
export default function ExampleGenerateTextRouteHandler() {
8+
export default function StreamTextRouteHandler() {
89
const [prompt, setPrompt] = useState('');
910
const [completion, setCompletion] = useState('');
1011
const [loading, setLoading] = useState(false);
1112

1213
const handleSubmit = async (e: React.FormEvent) => {
1314
e.preventDefault();
14-
if (!prompt.trim()) return;
15+
if (!prompt.trim() || loading) return;
1516

1617
setLoading(true);
1718
setCompletion('');
1819

1920
try {
2021
const response = await fetch('/api/langbase/pipe/stream-text', {
2122
method: 'POST',
22-
headers: {
23-
'Content-Type': 'application/json',
24-
},
25-
body: JSON.stringify({prompt: prompt}),
23+
body: JSON.stringify({prompt}),
24+
headers: {'Content-Type': 'text/plain'},
2625
});
2726

28-
if (!response.ok) {
29-
throw new Error('Network response was not ok');
30-
}
31-
32-
const reader = response.body?.getReader();
33-
34-
if (!reader) {
35-
throw new Error('Unable to read stream');
36-
}
37-
38-
const decoder = new TextDecoder();
39-
let buffer = '';
40-
41-
while (true) {
42-
const {done, value} = await reader.read();
43-
if (done) break;
27+
if (response.body) {
28+
const stream = fromReadableStream(response.body);
4429

45-
buffer += decoder.decode(value, {stream: true});
46-
const lines = buffer.split('\n');
47-
buffer = lines.pop() || '';
48-
49-
for (const line of lines) {
50-
if (line.trim()) {
51-
const chunk = JSON.parse(line);
52-
const content = chunk.choices[0]?.delta?.content || '';
53-
setCompletion(prev => prev + content);
54-
}
30+
// Method #1 to get all of the chunk.
31+
for await (const chunk of stream) {
32+
console.log('✨ ~ chunk:', chunk);
33+
const content = chunk?.choices[0]?.delta?.content;
34+
content && setCompletion(prev => prev + content);
5535
}
56-
}
5736

58-
// Process any remaining data in the buffer
59-
if (buffer.trim()) {
60-
const chunk = JSON.parse(buffer);
61-
const content = chunk.choices[0]?.delta?.content || '';
62-
setCompletion(prev => prev + content);
37+
// Method #2 to get only the chunk's content as delta of the chunks
38+
// stream.on('content', content => {
39+
// setCompletion(prev => prev + content);
40+
// });
6341
}
6442
} catch (error) {
43+
setLoading(false);
6544
console.error('Error:', error);
66-
setCompletion('An error occurred while generating the completion.');
6745
} finally {
6846
setLoading(false);
6947
}
7048
};
7149

7250
return (
73-
<>
51+
<div className="bg-neutral-200 rounded-md p-2 flex flex-col gap-2 w-full">
7452
<div className="flex flex-col gap-2 w-full">
7553
<p className="text-lg font-semibold">
76-
2. Generate Text{' '}
54+
2. Stream Text{' '}
7755
<a
7856
className="text-indigo-500"
7957
href="https://langbase.com/docs"
@@ -97,17 +75,15 @@ export default function ExampleGenerateTextRouteHandler() {
9775
value={prompt}
9876
required
9977
/>
100-
10178
<Button type="submit" className="w-full" disabled={loading}>
10279
{loading ? 'AI is thinking...' : 'Ask AI'}
10380
</Button>
10481
</form>
105-
10682
{completion && (
10783
<p className="mt-4">
108-
<strong>Completion:</strong> {completion}
84+
<strong>Stream:</strong> {completion}
10985
</p>
11086
)}
111-
</>
87+
</div>
11288
);
11389
}

examples/nextjs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"lucide-react": "^0.416.0",
1717
"mxcn": "^2.0.0",
1818
"next": "14.2.5",
19+
"openai": "^4.53.0",
1920
"react": "^18",
2021
"react-dom": "^18",
2122
"tailwind-merge": "^2.4.0",

0 commit comments

Comments
 (0)