From 5601e8a874da79fd254b94b499a4320f6e56cb13 Mon Sep 17 00:00:00 2001 From: ForeverPyrite Date: Sat, 5 Oct 2024 16:55:53 -0400 Subject: [PATCH] Streaming Update (NEEDS OPTIMIZATIONS AND FAILSAFES!!!!!!!!!!!!!!!!!!!!!!) --- app.py | 37 ++++++++++++++++++++++++++++++------ main.py | 8 +++++++- screw-bardo.code-workspace | 10 ++++++++++ website/static/script.js | 39 +++++++++++++++++++++++++++++--------- 4 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 screw-bardo.code-workspace diff --git a/app.py b/app.py index a9f7a94..c3497d9 100644 --- a/app.py +++ b/app.py @@ -1,18 +1,43 @@ -from flask import Flask, render_template, request -from main import get_auto_transcript, get_video_id, create_and_stream +from flask import Flask, render_template, Response, request +from main import get_auto_transcript, get_video_id, create_and_stream, EventHandler from datetime import datetime +import sys +import io import pytz +import time app = Flask(__name__, static_folder="website/static", template_folder="website") +class StreamToLogger(io.StringIO): + def __init__(self): + super().__init__() + + def write(self, message): + # I could probably log stuff here + print(message, end='') # Print to standard output (console) + # You could also log this message or handle it differently. + + @app.route('/') def home(): return render_template('index.html') +@app.route('/streamtest', methods=['POST']) +def streaming(): + def generate(): + for i in range(10): + yield f"Data chunk {i}\n" + time.sleep(1) # Simulating a delay in data generation + + return Response(generate(), content_type='text/plain') + @app.route('/process_url', methods=['POST']) def process_url(): + old_stdout = sys.stdout + new_stdout = StreamToLogger() + sys.stdout = new_stdout # Opens a file to log the video id and the assistants respone to see if I can further improve instructions: - log = open("log.txt", "at", 1) + #log = open("log.txt", "at", 1) url = request.form['url'] # Extract the video ID from the URL @@ -26,10 +51,10 @@ def process_url(): return "Successfully parsed video ID from URL, however the ID was either invalid, the transcript was disabled by the video owner, or some other error was raised because of YouTube." # Process the transcript and stream the result. - response = create_and_stream(transcript) - log.write(f"\n\n\n### New Entry at {datetime.now(pytz.timezone('America/New_York')).strftime('%Y-%m-%d %H:%M:%S')}\n\n URL: {url}\n Video ID: {video_id}\n\nAssistant Response: \n{response}") + # response = create_and_stream(transcript) + # log.write(f"\n\n\n### New Entry at {datetime.now(pytz.timezone('America/New_York')).strftime('%Y-%m-%d %H:%M:%S')}\n\n URL: {url}\n Video ID: {video_id}\n\nAssistant Response: \n{response}") # Return a response - return response # Add more detailed output if needed + return Response(create_and_stream(transcript), content_type="text/plain", status=200, direct_passthrough=True) # Add more detailed output if needed if __name__ == '__main__': # Change this line to properly check for main app.run(debug=True) \ No newline at end of file diff --git a/main.py b/main.py index 71a7eda..cd59220 100644 --- a/main.py +++ b/main.py @@ -26,23 +26,29 @@ class EventHandler(AssistantEventHandler): @override def on_text_created(self, text) -> None: print(f"\nassistant > ", end="", flush=True) + @override def on_text_delta(self, delta, snapshot): print(delta.value, end="", flush=True) + def on_tool_call_created(self, tool_call): print(f"\nassistant > {tool_call.type}\n", flush=True) + def on_tool_call_delta(self, delta, snapshot): if delta.type == 'code_interpreter': if delta.code_interpreter.input: print(delta.code_interpreter.input, end="", flush=True) + if delta.code_interpreter.outputs: print(f"\n\noutput >", flush=True) + for output in delta.code_interpreter.outputs: if output.type == "logs": print(f"\n{output.logs}", flush=True) + # Setting up OpenAI Client with API Key @@ -69,7 +75,7 @@ def create_and_stream(transcript): }, event_handler=EventHandler() ) as stream: - stream.until_done() + stream.until_done() messages = stream.get_final_messages() return messages[0].content[0].text.value diff --git a/screw-bardo.code-workspace b/screw-bardo.code-workspace new file mode 100644 index 0000000..79a7cdb --- /dev/null +++ b/screw-bardo.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "html.format.enable": true + } +} \ No newline at end of file diff --git a/website/static/script.js b/website/static/script.js index 474c14c..e35feb3 100644 --- a/website/static/script.js +++ b/website/static/script.js @@ -8,10 +8,6 @@ document.addEventListener("DOMContentLoaded", (event) => { response_area.innerText = 'Please enter a URL.'; return; } - else{ - response_area.innerText = "Sending URL and retriving transcript." - } - fetch('/process_url', { method: 'POST', headers: { @@ -19,13 +15,38 @@ document.addEventListener("DOMContentLoaded", (event) => { }, body: new URLSearchParams({ url: url }) }) - .then(response => response.text()) - .then(data => { - response_area.innerText = data; + .then(response => { + const reader = response.body.getReader(); + const decoder = new TextDecoder("utf-8"); + + function readStream() { + reader.read().then(({ done, value }) => { + if (done) { + console.log("Stream finished."); + return; + } + + // Decode and process the chunk + const chunk = decoder.decode(value, { stream: true }); + + // Split the received chunk by new line to handle multiple lines (if any) + chunk.split('\n').forEach(data => { + if (data.trim()) { // Avoid empty strings + // Update the inner HTML of the output div + response_area.innerHTML += `

${data}

`; + } + }); + + // Continue reading + readStream(); + }); + } + + // Start reading the stream + readStream(); }) .catch(error => { - console.error('Error:', error); - response_area.innerText = 'An error occurred. Please try again.'; + console.error('Error fetching stream:', error); }); }); });