This repository has been archived by the owner on Sep 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Add Streaming Functionality To Ocular Search (#94)
* Add Chat Streaming Functionality * Add Streaming Functionality * Add AI Streaming API * Ocular CoPilot Streaming * Add Streaming Functionality * Add Azure Open AI
- Loading branch information
1 parent
3b5ee4e
commit 737acc3
Showing
21 changed files
with
661 additions
and
244 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,46 @@ | ||
class NdJsonParserStream extends TransformStream<string, JSON> { | ||
private buffer: string = ''; | ||
constructor() { | ||
let controller: TransformStreamDefaultController<JSON>; | ||
super({ | ||
start: (_controller) => { | ||
controller = _controller; | ||
}, | ||
transform: (chunk) => { | ||
const jsonChunks = chunk.split('\n').filter(Boolean); | ||
for (const jsonChunk of jsonChunks) { | ||
try { | ||
this.buffer += jsonChunk; | ||
controller.enqueue(JSON.parse(this.buffer)); | ||
this.buffer = ''; | ||
} catch { | ||
// Invalid JSON, wait for next chunk | ||
} | ||
} | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
export function createReader(responseBody: ReadableStream<Uint8Array> | null) { | ||
return responseBody | ||
?.pipeThrough(new TextDecoderStream()) | ||
.pipeThrough(new NdJsonParserStream()) | ||
.getReader(); | ||
} | ||
|
||
export async function* readStream<T>(reader: any): AsyncGenerator<T, void> { | ||
if (!reader) { | ||
throw new Error('No response body or body is not readable'); | ||
} | ||
|
||
let value: JSON | undefined; | ||
let done: boolean; | ||
while ((({ value, done } = await reader.read()), !done)) { | ||
yield new Promise<T>((resolve) => { | ||
setTimeout(() => { | ||
resolve(value as T); | ||
}, 50); | ||
}); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Ocular uses Axios on all its services to make HTTP requests. However Axios does support client streaming in the | ||
// browser so we created this stream api as a workaround. The streaming api is a simple wrapper around the fetch api that allows you to make streaming requests to the server. | ||
export const OCULAR_BACKEND_URL = | ||
process.env.OCULAR_BACKEND_URL || 'http://localhost:9000/v1'; | ||
|
||
export default async function ocularStreamingRequest( | ||
method: | ||
| 'GET' | ||
| 'POST' | ||
| 'PUT' | ||
| 'DELETE' | ||
| 'PATCH' | ||
| 'OPTIONS' | ||
| 'HEAD' | ||
| 'CONNECT' | ||
| 'TRACE', | ||
path = '', | ||
payload = {}, | ||
stream = false, | ||
cancelTokenSource: AbortController | null | ||
) { | ||
const headers = { | ||
'Access-Control-Allow-Origin': '*', | ||
'Content-Type': 'application/json', | ||
}; | ||
|
||
const options = { | ||
method, | ||
headers, | ||
credentials: 'include', | ||
body: JSON.stringify(payload), | ||
signal: cancelTokenSource ? cancelTokenSource.signal : undefined, | ||
}; | ||
|
||
if (method === 'GET') { | ||
delete options.body; | ||
} | ||
|
||
const response = await fetch(`${OCULAR_BACKEND_URL}${path}`, options); | ||
|
||
if (!response.ok) { | ||
const error = await response.text(); | ||
console.error('Error', error); | ||
throw new Error(error); | ||
} | ||
|
||
return response; | ||
} |
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.