diff --git a/Node/quickstarts/callable-functions-streaming/functions/index.js b/Node/quickstarts/callable-functions-streaming/functions/index.js index dc62d7de03..d3e6c79bd0 100644 --- a/Node/quickstarts/callable-functions-streaming/functions/index.js +++ b/Node/quickstarts/callable-functions-streaming/functions/index.js @@ -34,30 +34,34 @@ async function generateStream() { const sentence = "Hello from Cloud Functions for Firebase!"; for (const word of sentence.split(" ")) { - await new Promise((resolve) => setTimeout(resolve, Math.random() * 500)); + const randomDelay = Math.floor(Math.random() * 500); + await new Promise((resolve) => setTimeout(resolve, randomDelay)); yield {text: () => " " + word}; } + + return {text: () => sentence}; } - return { - metadata: { - acceptsStreaming: true}, - stream: mockAsyncIterable, - }; + return mockAsyncIterable; } exports.streamResponse = onCall(async (request, response) => { - console.log("I was called!!!"); - console.log("data", request.data); - const prompt = request.data.text || "hello"; + const prompt = request.data?.text || "hello world"; - const {metadata, stream} = await generateStream(prompt); + try { + // Call a streaming API, like an LLM + const stream = await generateStream(prompt); - for await (const chunk of stream()) { - console.log(chunk); - if (metadata.acceptsStreaming) { - response.sendChunk(chunk.text()); + if (request.acceptsStreaming) { + // Wait for each value of the returned Async Iterable + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator + for await (const chunk of stream()) { + response.sendChunk(chunk.text()); + } } + + return await stream.text(); + } catch (error) { + throw new HttpsError("internal", error.message); } - return true; }); diff --git a/Node/quickstarts/callable-functions-streaming/website/index.html b/Node/quickstarts/callable-functions-streaming/website/index.html index 3f7c03496a..1d1856da6e 100644 --- a/Node/quickstarts/callable-functions-streaming/website/index.html +++ b/Node/quickstarts/callable-functions-streaming/website/index.html @@ -15,6 +15,11 @@ connectFunctionsEmulator, } from "https://www.gstatic.com/firebasejs/11.2.0/firebase-functions.js"; + const callableButton = document.getElementById("btn-call-func"); + const resultElement = document.getElementById("p-result"); + + callableButton.onclick = handleClick; + // set your firebase config object const firebaseConfig = undefined; if (!firebaseConfig) { @@ -25,21 +30,27 @@ connectFunctionsEmulator(functions, "127.0.0.1", 5001); const streamResponse = httpsCallable(functions, "streamResponse"); - const callableButton = document.getElementById("btn-call-func"); - const resultElement = document.getElementById("p-result"); - callableButton.onclick = async () => { + async function handleClick() { // reset result - resultElement.innerHTML = ""; + clearOutput(); const resp = await streamResponse.stream({ text: "What is your favorite Firebase service and why?", }); - // append text each time - for await (const message of resp.stream) { - resultElement.innerHTML += message; + // add each new chunk to the output + for await (const chunk of resp.stream) { + appendToOutput(chunk); } }; + + function clearOutput() { + resultElement.innerHTML = ""; + } + + function appendToOutput(str) { + resultElement.innerHTML += str; + }