diff --git a/app/backend/InputBackend.tsx b/app/backend/InputBackend.tsx deleted file mode 100644 index a00ceeb..0000000 --- a/app/backend/InputBackend.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useState } from 'react'; -import InputFrontend from '../components/InputFrontend'; -import ConversationFrontend from '../components/ConversationFrontend'; -import { Mistral } from '@mistralai/mistralai'; - - - -const handleMicClick = () => { - console.log('Mic clicked!'); - // Do something when the mic button is clicked -}; - - -const handleResendClick = () => { - console.log('Resend button clicked'); - // Handle resend action -}; - -const handleEditClick = () => { - console.log('Edit button clicked'); - // Handle edit action -}; - -const handleCopyClick = () => { - console.log('Copy button clicked'); - // Handle copy action -}; - -const InputBackend: React.FC = () => { - async function prompt_mistral(model: string, prompt: string, system: string) { - const apiKey = "m3kZRjN8DRSIo88r8Iti9hmKGWIklrLY"; - - const client = new Mistral({ apiKey: apiKey }); - - var chatResponse = await client.chat.complete({ - model: model, - messages: [{ role: 'user', content: prompt }, { role: 'system', content: system, }], - }); - - if (chatResponse && chatResponse.choices && chatResponse.choices.length > 0) { - if (chatResponse.choices[0].message.content) { - addMessage('AI: ' + chatResponse.choices[0].message.content); - } - } else { - console.error('Error: Unexpected API response:', chatResponse); - } - } - - const handleSendClick = (message: string) => { - var system = "You are a helpful assistant. The following is the chat history." - for (let index = 0; index < messages.length; index++) { - system += messages[index] + " "; - }; - - addMessage('User: ' + message); - prompt_mistral("mistral-large-latest", message, system) - }; - - const [messages, setMessages] = useState([ - 'User: Hello!', - 'AI: Hi there!', - 'User: How are you?', - 'AI: I’m good, thank you!' - ]); - - const addMessage = (message: string) => { - setMessages((prevMessages) => [...prevMessages, message]); - }; - return ( -
- - -
- ); -}; - -export default InputBackend; diff --git a/app/backend/InputOutputHandler.tsx b/app/backend/InputOutputHandler.tsx index 86bb594..02a227b 100644 --- a/app/backend/InputOutputHandler.tsx +++ b/app/backend/InputOutputHandler.tsx @@ -3,34 +3,28 @@ import React, { useEffect, useRef, useState } from "react"; import ConversationFrontend from "../components/ConversationFrontend"; import InputFrontend from "../components/InputFrontend"; import axios from "axios"; +import { skip } from "node:test"; const InputOutputBackend: React.FC = () => { type Message = { role: string - content:string + content: string } const [accessToken, setAccessToken] = useState("") - const postWorkerRef = useRef(null) + const postWorkerRef = useRef(null) const getWorkerRef = useRef(null) - const [messages, setMessages] = useState([{role:"assistant", content:"Hello! How can I help you?"}]) + const [messages, setMessages] = useState([{ role: "assistant", content: "Hello! How can I help you?" }]) const [liveMessage, setLiveMessage] = useState("") + const [inputMessage, setInputMessage] = useState("") const [inputDisabled, setInputDisabled] = useState(false) + const [lastMessage, setLastMessage] = useState({ role: "user", content: "Not supposed to happen." }) console.log(messages); - + useEffect(() => { - console.log("getting access"); - axios.get("http://localhost:5000/interstellar/api/ai_create") - .then(response => { - setAccessToken(response.data.access_token) - console.log(response.data.access_token); - }) - .catch(error => { - console.log("error:", error.message); - - }) + getNewToken() postWorkerRef.current = new Worker(new URL("./threads/PostWorker.js", import.meta.url)) @@ -48,7 +42,7 @@ const InputOutputBackend: React.FC = () => { } } } - + return () => { if (postWorkerRef.current) { postWorkerRef.current.terminate() @@ -58,20 +52,33 @@ const InputOutputBackend: React.FC = () => { getWorkerRef.current.terminate() } } - },[]) + }, []) + + const getNewToken = () => { + console.log("getting access"); + axios.get("http://localhost:5000/interstellar_ai/api/ai_create") + .then(response => { + setAccessToken(response.data.access_token) + console.log(response.data.access_token); + }) + .catch(error => { + console.log("error:", error.message); + + }) + } const startGetWorker = () => { if (!getWorkerRef.current) { getWorkerRef.current = new Worker(new URL("./threads/GetWorker.js", import.meta.url)) - - getWorkerRef.current.postMessage({ action: "start", access_token:accessToken}) - - addMessage("assistant","") + + getWorkerRef.current.postMessage({ action: "start", access_token: accessToken }) + + addMessage("assistant", "") getWorkerRef.current.onmessage = (event) => { const data = event.data - + if (event.data == "error") { - setLiveMessage("error getting AI response: "+ data.error) + setLiveMessage("error getting AI response: " + data.error) } else { console.log("Received data:", data); editLastMessage(data.response) @@ -81,12 +88,12 @@ const InputOutputBackend: React.FC = () => { getWorkerRef.current.onerror = (error) => { console.error("Worker error:", error) } - } + } } const endGetWorker = () => { if (getWorkerRef.current) { - getWorkerRef.current.postMessage({action:"terminate"}) + getWorkerRef.current.postMessage({ action: "terminate" }) getWorkerRef.current.terminate() getWorkerRef.current = null console.log(messages); @@ -97,31 +104,32 @@ const InputOutputBackend: React.FC = () => { if (newContent == "") { newContent = "Generating answer..." } - setMessages((prevMessages) => { - const updatedMessages = prevMessages.slice(); // Create a shallow copy of the current messages - if (updatedMessages.length > 0) { - const lastMessage = updatedMessages[updatedMessages.length - 1]; - updatedMessages[updatedMessages.length - 1] = { - ...lastMessage, // Keep the existing role and other properties - content: newContent, // Update only the content - }; - } - return updatedMessages; // Return the updated array - }); -}; + setMessages((prevMessages) => { + const updatedMessages = prevMessages.slice(); // Create a shallow copy of the current messages + if (updatedMessages.length > 0) { + const lastMessage = updatedMessages[updatedMessages.length - 1]; + updatedMessages[updatedMessages.length - 1] = { + ...lastMessage, // Keep the existing role and other properties + content: newContent, // Update only the content + }; + } + return updatedMessages; // Return the updated array + }); + }; const addMessage = (role: string, content: string) => { - setMessages(previous => [...previous,{role,content}]) - } - const handleSendClick = (inputValue: string) => { + setMessages(previous => [...previous, { role, content }]) + } + const handleSendClick = (inputValue: string, override: boolean) => { if (inputValue != "") { - if (!inputDisabled) { + console.log(inputDisabled) + if (!inputDisabled || override) { setInputDisabled(true) if (postWorkerRef.current) { addMessage("user", inputValue) - console.log("input:",inputValue); - postWorkerRef.current.postMessage({messages:[...messages, { role: "user", content: inputValue }], ai_model:"phi3.5", access_token:accessToken}) + console.log("input:", inputValue); + postWorkerRef.current.postMessage({ messages: [...messages, { role: "user", content: inputValue }], ai_model: "phi3.5", access_token: accessToken }) startGetWorker() } } @@ -133,18 +141,33 @@ const InputOutputBackend: React.FC = () => { } const handleResendClick = () => { - // do stuff + var temporary_message = messages[messages.length - 2]['content'] + const updatedMessages = messages.slice(0, -2) + setMessages(updatedMessages) + endGetWorker() + getNewToken() + setInputDisabled(false) + handleSendClick(temporary_message, true) } const handleEditClick = () => { - // do stuff + setInputMessage(messages[messages.length - 2]['content']) + const updatedMessages = messages.slice(0, -2) + setMessages(updatedMessages) + endGetWorker() + getNewToken() + setInputDisabled(false) } - const handleCopyClick = () => { - // do stuff + const handleCopyClick = async () => { + try { + await navigator.clipboard.writeText(messages[messages.length - 1]['content']); + } catch (err) { + console.error('Failed to copy: ', err); + } } - return ( + return (
{ onCopyClick={handleCopyClick} />
- ) + ) } export default InputOutputBackend @@ -168,4 +191,3 @@ export default InputOutputBackend - \ No newline at end of file diff --git a/app/backend/threads/GetWorker.js b/app/backend/threads/GetWorker.js index fcdcc2f..e035407 100644 --- a/app/backend/threads/GetWorker.js +++ b/app/backend/threads/GetWorker.js @@ -3,8 +3,8 @@ import axios from "axios"; let accesstoken onmessage = (event) => { const { action, access_token } = event.data - accesstoken=access_token - + accesstoken = access_token + if (action === "start") { fetchData() } else if (action === "terminate") { @@ -15,20 +15,20 @@ console.log('starting get loop'); const fetchData = () => { console.log(accesstoken); - - - const apiURL = "http://localhost:5000/interstellar/api/ai_get?access_token="+accesstoken - + + + const apiURL = "http://localhost:5000/interstellar_ai/api/ai_get?access_token=" + accesstoken + axios.get(apiURL) .then(response => { const data = response.data console.log(data); postMessage(data) - setTimeout(fetchData,100) + setTimeout(fetchData, 100) }) .catch(error => { console.log('Error fetching data:', error); - postMessage({error:"failed fetching data"}) - setTimeout(() => fetchData(),1000) - }) + postMessage({ error: "failed fetching data" }) + setTimeout(() => fetchData(), 1000) + }) } \ No newline at end of file diff --git a/app/backend/threads/PostWorker.js b/app/backend/threads/PostWorker.js index d6f6b04..1127d0d 100644 --- a/app/backend/threads/PostWorker.js +++ b/app/backend/threads/PostWorker.js @@ -7,23 +7,23 @@ onmessage = (e) => { const Message = { messages: messages, ai_model: "phi3.5", - model_type:"local", - access_token:access_token + model_type: "local", + access_token: access_token } console.log(Message); - - axios.post("http://localhost:5000/interstellar/api/ai_send",Message) + + axios.post("http://localhost:5000/interstellar_ai/api/ai_send", Message) .then(response => { const status = response.data.status console.log(status); postMessage({ status }) console.log('message posted'); - + }) .catch(error => { console.log("Error calling API:", error) - postMessage({status:500}) - }) + postMessage({ status: 500 }) + }) } \ No newline at end of file diff --git a/app/components/InputFrontend.tsx b/app/components/InputFrontend.tsx index f22ee57..e50e916 100644 --- a/app/components/InputFrontend.tsx +++ b/app/components/InputFrontend.tsx @@ -1,16 +1,19 @@ -import React, { useState, ForwardedRef } from 'react'; +import React, { useState, ForwardedRef, useEffect } from 'react'; interface InputProps { message: string; - onSendClick: (message: string) => void; + onSendClick: (message: string, override: boolean) => void; onMicClick: () => void; - inputDisabled:boolean + inputDisabled: boolean } const InputFrontend = React.forwardRef( ({ message, onSendClick, onMicClick, inputDisabled }, ref: ForwardedRef) => { const [inputValue, setInputValue] = useState(''); - + + useEffect(() => { + setInputValue(message); + }, [message]); const handleInputChange = (e: React.ChangeEvent) => { setInputValue(e.target.value); @@ -19,7 +22,7 @@ const InputFrontend = React.forwardRef( const handleKeyDown = (event: React.KeyboardEvent) => { if (!inputDisabled) { if (event.key === 'Enter') { - onSendClick(inputValue); // Call the function passed via props + onSendClick(inputValue, false); // Call the function passed via props setInputValue(''); // Optionally clear input after submission event.preventDefault(); // Prevent default action (e.g., form submission) } @@ -36,7 +39,7 @@ const InputFrontend = React.forwardRef( onChange={handleInputChange} onKeyDown={handleKeyDown} /> -