Created
January 1, 2024 03:29
-
-
Save vincentopensourcetaiwan/fbbd9653723408d82569b05f67c90fc8 to your computer and use it in GitHub Desktop.
app/javascript/controllers/chat_controller.js
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
import {Controller} from "@hotwired/stimulus" | |
// Connects to data-controller="chat" | |
export default class extends Controller { | |
static targets = ["prompt", "conversation"] | |
disconnect() { | |
if (this.eventSource) { | |
this.eventSource.close() | |
} | |
} | |
generateResponse(event) { | |
// 1. Prevent the default form submission behavior | |
event.preventDefault() | |
this.#createLabel('You') | |
// 2. Create a new <pre> element and append it to the conversation | |
// the content of the <pre> element should be the prompt | |
this.#createMessage(this.promptTarget.value) | |
this.#createLabel('ChatGPT') | |
// 3. Create a new <pre> element and append it to the conversation | |
// the content of the <pre> element should be the response | |
this.currentPre = this.#createMessage() | |
// 4. setup event source | |
this.#setupEventSource() | |
this.promptTarget.value = "" | |
} | |
#createLabel(text) { | |
const label = document.createElement('strong'); | |
label.innerHTML = `${text}:`; | |
this.conversationTarget.appendChild(label); | |
} | |
#createMessage(text = '') { | |
const preElement = document.createElement('pre'); | |
preElement.innerHTML = text; | |
this.conversationTarget.appendChild(preElement); | |
return preElement | |
} | |
#setupEventSource() { | |
// 5. setup event source | |
this.eventSource = new EventSource(`/chat_responses?prompt=${this.promptTarget.value}`) | |
// 6. add event listeners | |
this.eventSource.addEventListener("message", this.#handleMessage.bind(this)) | |
this.eventSource.addEventListener("error", this.#handleError.bind(this)) | |
} | |
#handleMessage(event) { | |
const parsedData = JSON.parse(event.data); | |
this.currentPre.innerHTML += parsedData.message; | |
// Scroll to bottom of conversation | |
this.conversationTarget.scrollTop = this.conversationTarget.scrollHeight; | |
} | |
#handleError(event) { | |
if (event.eventPhase === EventSource.CLOSED) { | |
this.eventSource.close() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment