-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
304 additions
and
8 deletions.
There are no files selected for viewing
86 changes: 86 additions & 0 deletions
86
examples/next-openai/app/api/completion-speech-lmnt/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import OpenAI from 'openai'; | ||
import { | ||
OpenAIStream, | ||
StreamingTextResponse, | ||
experimental_StreamData, | ||
} from 'ai'; | ||
import Speech from 'lmnt-node'; | ||
|
||
// Create an OpenAI API client (that's edge friendly!) | ||
const openai = new OpenAI({ | ||
apiKey: process.env.OPENAI_API_KEY || '', | ||
}); | ||
|
||
const speech = new Speech(process.env.LMNT_API_KEY || ''); | ||
|
||
// IMPORTANT! Set the runtime to edge | ||
// export const runtime = 'edge'; | ||
|
||
export async function POST(req: Request) { | ||
// Extract the `prompt` from the body of the request | ||
const { prompt } = await req.json(); | ||
|
||
// Ask OpenAI for a streaming completion given the prompt | ||
const response = await openai.completions.create({ | ||
model: 'gpt-3.5-turbo-instruct', | ||
max_tokens: 2000, | ||
stream: true, | ||
prompt, | ||
}); | ||
|
||
const speechStreamingConnection = speech.synthesizeStreaming( | ||
'034b632b-df71-46c8-b440-86a42ffc3cf3', // Henry | ||
{}, | ||
); | ||
|
||
const data = new experimental_StreamData(); | ||
|
||
// create a promise to wait for the speech stream to finish | ||
let resolveSpeech: (value: unknown) => void = () => {}; | ||
const speechFinishedPromise = new Promise(resolve => { | ||
resolveSpeech = resolve; | ||
}); | ||
|
||
// run in parallel: | ||
(async () => { | ||
let i = 0; | ||
for await (const chunk of speechStreamingConnection) { | ||
try { | ||
const chunkAny = chunk as any; | ||
const audioBuffer: Buffer = chunkAny.audio; | ||
|
||
// base64 encode the audio buffer | ||
const base64Audio = audioBuffer.toString('base64'); | ||
|
||
console.log('streaming speech chunk #' + i++); | ||
|
||
data.appendSpeech(base64Audio); | ||
} catch (err) { | ||
console.error(err); | ||
} | ||
} | ||
console.log('done streaming speech'); | ||
|
||
resolveSpeech?.(undefined); | ||
})(); | ||
|
||
// Convert the response into a friendly text-stream | ||
const stream = OpenAIStream(response, { | ||
onToken(token) { | ||
speechStreamingConnection.appendText(token); | ||
speechStreamingConnection.flush(); | ||
}, | ||
async onFinal(completion) { | ||
speechStreamingConnection.finish(); | ||
|
||
await speechFinishedPromise; | ||
data.close(); | ||
|
||
console.log('done streaming text'); | ||
}, | ||
experimental_streamData: true, | ||
}); | ||
|
||
// Respond with the stream | ||
return new StreamingTextResponse(stream, {}, data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
'use client'; | ||
|
||
import { useCompletion } from 'ai/react'; | ||
|
||
export default function Chat() { | ||
const { | ||
completion, | ||
input, | ||
handleInputChange, | ||
handleSubmit, | ||
error, | ||
speechUrl, | ||
} = useCompletion({ | ||
api: '/api/completion-speech-lmnt', | ||
}); | ||
|
||
return ( | ||
<div className="flex flex-col w-full max-w-md py-24 mx-auto stretch"> | ||
<h4 className="text-xl font-bold text-gray-900 md:text-xl pb-4"> | ||
useCompletion Example | ||
</h4> | ||
{error && ( | ||
<div className="fixed top-0 left-0 w-full p-4 text-center bg-red-500 text-white"> | ||
{error.message} | ||
</div> | ||
)} | ||
|
||
{completion} | ||
|
||
<div className="flex justify-center mt-4"> | ||
{speechUrl != null && ( | ||
<> | ||
<audio | ||
controls | ||
controlsList="nodownload nofullscreen noremoteplayback" | ||
autoPlay={true} | ||
src={speechUrl} | ||
/> | ||
</> | ||
)} | ||
</div> | ||
|
||
<form onSubmit={handleSubmit}> | ||
<input | ||
className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl" | ||
value={input} | ||
placeholder="Say something..." | ||
onChange={handleInputChange} | ||
/> | ||
</form> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.