Switching to CRUD instead of ws://

This commit is contained in:
James Ketr 2025-03-28 12:51:50 -07:00
parent 1343557f3d
commit 2393c74890
5 changed files with 95 additions and 106 deletions

View File

@ -1,2 +1,3 @@
*
!src
**/node_modules

View File

@ -9,6 +9,23 @@ div {
flex-direction: column;
}
.ChatBox {
display: flex;
flex-direction: "row";
flex-grow: 1;
}
.Controls {
display: flex;
background-color: #F5F5F5;
border: 1px solid #E0E0E0;
overflow-y: auto;
padding: 10px;
flex-direction: column;
margin-left: 10px;
box-sizing: border-box;
overflow-x: visible;
}
.container {
display: flex;
flex-grow: 1;
@ -42,14 +59,13 @@ div {
cursor: pointer;
}
.conversation {
.Conversation {
display: flex;
background-color: #F5F5F5;
border: 1px solid #E0E0E0;
flex-grow: 1;
overflow-y: auto;
padding: 10px;
margin-bottom: 20px;
flex-direction: column;
}

View File

@ -2,14 +2,31 @@ import React, { useState, useEffect, useRef, useCallback } from 'react';
import PropagateLoader from "react-spinners/PropagateLoader";
import Markdown from 'react-markdown';
import './App.css';
import remarkGfm from 'remark-gfm'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
import 'katex/dist/katex.min.css' // `rehype-katex` does not import the CSS for you
const welcome_message = "Welcome to Ketr-Chat. I have real-time access to a lot of information. Ask things like 'What are the headlines from cnn.com?' or 'What is the weather in Portland, OR?'";
const url: string = "https://ai.ketrenos.com"
//const url: string = "https://ai.ketrenos.com"
const getConnectionBase = (url: string): string => {
console.log(url);
if (!url.match(/.*battle-linux.*/)) {
return url;
} else {
return 'battle-linux.ketrenos.com:5000';
}
}
const Controls = () => {
const tools = ["get_stock_price", "get_weather", "site_summary", "RAG JPK", "RAG LKML"]
return (<div className="Controls">{
tools.map((tool, index) => {
return (<div key={index}>{tool}</div>);
})
}</div>);
}
const App = () => {
const [query, setQuery] = useState('');
@ -20,9 +37,7 @@ const App = () => {
const [loaded, setLoaded] = useState<boolean>(false);
const [connection, setConnection] = useState<any | undefined>(undefined);
const [sessionId, setSessionId] = useState<string | undefined>(undefined);
const [users, setUsers] = useState<string[]>([]);
const [user, setUser] = useState<string>("");
const [userChange, setUserChange] = useState<string>("");
const [loc,] = useState<Location>(window.location)
// Scroll to bottom of conversation when conversation updates
useEffect(() => {
@ -37,7 +52,12 @@ const App = () => {
if (!pathParts.length) {
console.log("No session id -- creating a new session")
fetch('/api/session')
fetch(loc.protocol + "//" + getConnectionBase(loc.host) + `/api/context`, {
method: 'CREATE',
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(data => {
console.log(`Session id: ${data.id} -- returned from server`)
@ -50,7 +70,7 @@ const App = () => {
setSessionId(pathParts[0]);
}
}, [setSessionId]);
}, [setSessionId, loc.host, loc.protocol]);
const onWsOpen = (event: any) => {
console.log(`ws: open`);
@ -101,22 +121,6 @@ const App = () => {
}
break;
case 'user':
if (!loaded) {
setLoaded(true);
}
setUser(data.update);
console.log(`user = ${data.update}`)
break;
case 'users':
if (!loaded) {
setLoaded(true);
}
setUsers(data.update);
console.log(`users = ${data.update}`)
break;
case 'processing':
console.log(`processing = ${data.value}`)
setProcessing(data.value);
@ -185,14 +189,14 @@ const App = () => {
let socket = ws;
if (!socket && !connection) {
let loc = window.location, new_uri;
let new_uri;
if (loc.protocol === "https:") {
new_uri = "wss://";
} else {
new_uri = "ws://";
}
new_uri += loc.host + `/api/ws/${sessionId}`;
//new_uri += `battle-linux.ketrenos.com:5000/api/ws/${sessionId}`;
let host = getConnectionBase(loc.host)
new_uri += host + `/api/ws/${sessionId}`;
console.log(`Attempting WebSocket connection to ${new_uri}`);
socket = new WebSocket(new_uri)
setWs(socket);
@ -223,7 +227,7 @@ const App = () => {
ws.removeEventListener('message', cbMessage);
}
}
}, [ setWs, connection, setConnection, sessionId, ws, refWsOpen, refWsMessage, refWsClose, refWsError ]);
}, [setWs, connection, setConnection, sessionId, ws, refWsOpen, refWsMessage, refWsClose, refWsError, loc.host, loc.protocol]);
const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
@ -231,9 +235,6 @@ const App = () => {
case 'query-input':
sendQuery();
break;
case 'user-input':
sendUserChange();
break;
}
}
};
@ -267,7 +268,7 @@ const App = () => {
try {
setProcessing(true);
// Send query to server
const response = await fetch(`/api/chat/${sessionId}`, {
const response = await fetch(loc.protocol + "//" + getConnectionBase(loc.host) + `/api/chat/${sessionId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@ -291,78 +292,60 @@ const App = () => {
}
};
const sendUserChange = async () => {
if (!userChange.trim()) return;
setUserChange('');
connection.send(JSON.stringify({
session: sessionId,
type: 'user-change',
value: userChange
}));
};
return (
<div className="container" style={{ display: "flex", flexDirection: "column" }}>
<div className="conversation" ref={conversationRef}>
{conversation.map((message, index) => {
const formattedContent = message.content
.split("\n")
.map((line) => line.replace(/^[^\s:]+:\s*/, ''))
.join("\n");
<div className="ChatBox">
<div className="Conversation" ref={conversationRef}>
{conversation.map((message, index) => {
const formattedContent = message.content
.split("\n")
.map((line) => line.replace(/^[^\s:]+:\s*/, ''))
.join("\n");
return (
<div key={index} className={message.role === 'user' ? 'user-message' : 'assistant-message'}>
{message.metadata ? (
<>
<div className="metadata">{message.metadata.title}</div>
{message.user && (
<div>{message.user}</div>
)}
{message.role === 'assistant' ? (
<div className="markdown-content">
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]} children={formattedContent} />
</div>
) : (
<div>{formattedContent}</div>
)}
</>
) : (
<>
return (
<div key={index} className={message.role === 'user' ? 'user-message' : 'assistant-message'}>
{message.metadata ? (
<>
<div className="metadata">{message.metadata.title}</div>
{message.user && (
<div>{message.user}</div>
<div>{message.user}</div>
)}
{message.role === 'assistant' ? (
<div className="markdown-content">
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]} children={formattedContent} />
</div>
) : (
<div>{formattedContent}</div>
<div>{formattedContent}</div>
)}
</>
)}
</div>
);
})}
<div style={{ justifyContent: "center", display: "flex", paddingBottom: "0.5rem" }}>
<PropagateLoader
size="10px"
loading={processing}
aria-label="Loading Spinner"
data-testid="loader"
/>
</div>
</div>
<div className="users" style={{ display: "flex", flexDirection: "row" }}>
<div>Users in this session: </div>
{users.map((name, index) => (
<div key={index} className={user === name ? `user-active` : `user`}>
{name}
</>
) : (
<>
{message.user && (
<div>{message.user}</div>
)}
{message.role === 'assistant' ? (
<div className="markdown-content">
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]} children={formattedContent} />
</div>
) : (
<div>{formattedContent}</div>
)}
</>
)}
</div>
);
})}
<div style={{ justifyContent: "center", display: "flex", paddingBottom: "0.5rem" }}>
<PropagateLoader
size="10px"
loading={processing}
aria-label="Loading Spinner"
data-testid="loader"
/>
</div>
))}
</div>
<Controls />
</div>
<div className="query-box">
@ -377,19 +360,6 @@ const App = () => {
/>
<button onClick={sendQuery}>Send</button>
</div>
<div className="user-box">
<input
disabled={connection ? false : true}
type="text"
value={userChange}
onChange={(e) => setUserChange(e.target.value)}
onKeyDown={handleKeyPress}
placeholder="Change your name..."
id="user-input"
/>
<button onClick={sendUserChange}>Send</button>
</div>
</div>
);
};

View File

@ -6,7 +6,9 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow: hidden;
padding: 0;
padding: 0;
height: 100%;
width: 100%;
}
code {