Last active
August 22, 2024 08:42
-
-
Save KevinBatdorf/717afd8f52e9242210f34122d8dc98a8 to your computer and use it in GitHub Desktop.
useStreaming hook and Server Sent Svents (SSE) basic parser
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
const parseEvent = (eventData) => { | |
const lines = eventData.split('\n'); | |
const eventType = ( | |
lines.find((line) => line.startsWith('event:')) || 'event:message' | |
) | |
.slice(6) | |
.trim(); | |
const eventDataExtracted = lines | |
.filter((line) => line.startsWith('data:')) | |
.map((line) => line.slice(5).trim()) | |
.join(''); | |
return { type: eventType, data: eventDataExtracted }; | |
}; | |
export const createParser = (onParse) => { | |
let eventString = ''; | |
return { | |
async feed(chunk) { | |
eventString += chunk; | |
while (eventString.includes('\n\n')) { | |
const eventEnd = eventString.indexOf('\n\n'); | |
await new Promise((resolve) => setTimeout(resolve, 50)); | |
onParse(parseEvent(eventString.slice(0, eventEnd))); | |
eventString = eventString.slice(eventEnd + 2); | |
} | |
}, | |
}; | |
}; |
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
// Simple example. not well tested or complete | |
export const useStreaming = (response) => { | |
const [stream, setStream] = useState(''); | |
const onParse = (event) => { | |
if (event.type !== 'message') return; | |
const data = event.data; | |
if (data === '[DONE]') return; | |
try { | |
const json = JSON.parse(data); | |
const text = json.choices[0]?.delta?.content || ''; | |
if (!text) return; | |
setStream((prev) => prev + text); | |
} catch (e) { | |
console.error(e); | |
} | |
}; | |
useEffect(() => { | |
if (!response) return; | |
setStream(''); | |
const reader = response.body.getReader(); | |
const decoder = new TextDecoder(); | |
const parser = createParser(onParse); | |
(async () => { | |
while (true) { | |
const { done, value } = await reader.read(); | |
if (done) break; | |
await parser.feed(decoder.decode(value)); | |
} | |
})(); | |
}, [response]); | |
return { stream, error: undefined }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment