Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend service options #24

Merged
merged 3 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
"version": "1.0.0",
"description": "Sample Client app showing communication with OCI Generative AI services via Websocket",
"dependencies": {
"@oracle/oraclejet": "~16.0.0",
"@oracle/oraclejet-core-pack": "~16.0.0",
"@oracle/oraclejet": "~16.1.0",
"@oracle/oraclejet-core-pack": "~16.1.0",
"@stomp/stompjs": "^7.0.0",
"marked": "^4.3.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@oracle/ojet-cli": "~16.0.0",
"@oracle/oraclejet-audit": "^16.0.0",
"@oracle/ojet-cli": "~16.1.0",
"@oracle/oraclejet-audit": "^16.1.0",
"@types/uuid": "^9.0.7",
"express-http-proxy": "^2.0.0",
"extract-zip": "^1.7.0",
"fs-extra": "^8.1.0",
"glob": "7.2.0",
"typescript": "5.3.2",
"underscore": "^1.10.2",
"url": "^0.11.3",
"yargs-parser": "13.1.2"
},
"engines": {
Expand Down
11 changes: 11 additions & 0 deletions app/path_mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,17 @@
"path": "libs/chai/chai.js",
"cdnPath": "chai/chai-4.3.10.min"
}
},
"stompjs": {
"cwd": "node_modules/@stomp/stompjs/bundles",
"debug": {
"src": "stomp.umd.js",
"path": "libs/stompjs/stomp.umd.js"
},
"release": {
"src": "stomp.umd.min.js",
"path": "libs/stompjs/stomp.umd.min.js"
}
}
}
}
23 changes: 16 additions & 7 deletions app/scripts/hooks/before_serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,28 @@

*/

'use strict';
"use strict";

module.exports = function (configObj) {
return new Promise((resolve, reject) => {
console.log('Running before_serve hook.');
console.log("Running before_serve hook.");
// ojet custom connect and serve options
// { connectOpts, serveOpts } = configObj;
// const express = require('express');
// const http = require('http');
const { connectOpts, serveOpts } = configObj;
const express = require("express");
const http = require("http");
const proxy = require("express-http-proxy");
const url = require("url");

// New hostname+path as specified by question:
const apiProxy = proxy("http://localhost:8080", {
proxyReqPathResolver: (req) => url.parse("/api" + req.url).path,
});
const app = express();
app.use("/api", apiProxy);
// pass back custom http
// configObj['http'] = http;
configObj["http"] = http;
// pass back custom express app
// configObj['express'] = express();
configObj["express"] = app;
// pass back custom options for http.createServer
// const serverOptions = {...};
// configObj['serverOptions'] = serverOptions;
Expand Down
11 changes: 8 additions & 3 deletions app/src/components/app.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { Header } from "./header";
import Content from "./content/index";
import { registerCustomElement } from "ojs/ojvcomponent";
import "preact";
import { createContext } from "preact";

type Props = {
appName: string;
};
const convoUUID = window.crypto.randomUUID();
export const ConvoCtx = createContext(convoUUID);

export const App = registerCustomElement("app-root", (props: Props) => {
props.appName = "Generative AI JET UI";

return (
<div id="appContainer" class="oj-web-applayout-page">
<Header appName={props.appName} />
<Content />
<ConvoCtx.Provider value={convoUUID}>
{console.log("UUID: ", convoUUID)}
<Header appName={props.appName} />
<Content />
</ConvoCtx.Provider>
</div>
);
});
170 changes: 79 additions & 91 deletions app/src/components/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,44 @@ import "oj-c/drawer-popup";
import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
import { MessageToastItem } from "oj-c/message-toast";
import { InputSearchElement } from "ojs/ojinputsearch";
import { useState, useEffect, useRef } from "preact/hooks";
import { useState, useEffect, useRef, useContext } from "preact/hooks";
import * as Questions from "text!./data/questions.json";
import * as Answers from "text!./data/answers.json";
import { initWebSocket } from "./websocket-interface";
import { InitStomp, sendPrompt } from "./stomp-interface";
import { Client } from "@stomp/stompjs";
import { ConvoCtx } from "../app";

type ServiceTypes = "text" | "summary" | "sim";
type BackendTypes = "java" | "python";
type Chat = {
id?: number;
question?: string;
answer?: string;
loading?: string;
};

const defaultServiceType: string = localStorage.getItem("service") || "text";
const defaultBackendType: string = localStorage.getItem("backend") || "java";

const Content = () => {
const conversationId = useContext(ConvoCtx);
const [update, setUpdate] = useState<Array<object>>([]);
const [busy, setBusy] = useState<boolean>(false);
const [summaryResults, setSummaryResults] = useState<string | null>("");
const [summaryResults, setSummaryResults] = useState<string>("");
const [modelId, setModelId] = useState<string | null>(null);
const [summaryPrompt, setSummaryPrompt] = useState<string>();
const [serviceType, setServiceType] = useState<ServiceTypes>("summary");
const [serviceType, setServiceType] = useState<ServiceTypes>(
defaultServiceType as ServiceTypes
);
const [backendType, setBackendType] = useState<BackendTypes>(
defaultBackendType as BackendTypes
);
const [settingsOpened, setSettingsOpened] = useState<boolean>(false);
const question = useRef<string>();
const chatData = useRef<Array<object>>([]);
const socket = useRef<WebSocket>();
const [connState, setConnState] = useState<string>("Disconnected");
const [client, setClient] = useState<Client | null>(null);

const messagesDP = useRef(
new MutableArrayDataProvider<MessageToastItem["summary"], MessageToastItem>(
Expand All @@ -39,77 +55,6 @@ const Content = () => {
)
);

const gateway = `ws://${window.location.hostname}:1986`;
let sockTimer: any = null;

// setup the websocket connection
const initWebSocket = () => {
console.log("Trying to open a WebSocket connection...");
socket.current = new WebSocket(gateway);
socket.current.binaryType = "arraybuffer";
socket.current.onopen = onOpen;
socket.current.onerror = onError;
socket.current.onclose = onClose;
socket.current.onmessage = onMessage;
};

// handle all messages coming from the websocket service
const onMessage = (event: any) => {
const msg = JSON.parse(event.data);

switch (msg.msgType) {
// switch (Object.keys(msg)[0]) {
case "message":
console.log("message: ", msg.data);
return msg.data;
case "question":
console.log("question: ", msg.data);
return msg.data;
case "summary":
console.log("summary");
setSummaryResults(msg.data);
return;
case "answer":
console.log("answer: ", msg.data);
if (msg.data !== "connected") {
let tempArray = [...chatData.current];
// remove the animation item before adding answer
setBusy(false);
tempArray.pop();
messagesDP.current.data = [];
tempArray.push({
id: tempArray.length as number,
answer: msg.data,
});
chatData.current = tempArray;
setUpdate(chatData.current);
}
return msg.data;
default:
return "unknown";
}
};

const onOpen = () => {
clearInterval(sockTimer);
console.log("Connection opened");
socket.current?.send(
JSON.stringify({ msgType: "message", data: "connected" })
);
setConnState("Connected");
};

// if the connection is lost, wait one minute and try again.
const onError = () => {
sockTimer = setInterval(initWebSocket, 1000 * 60);
};
function onClose() {
console.log("Connection closed");
setConnState("Disconnected");
socket.current ? (socket.current.onclose = () => {}) : null;
socket.current?.close();
}

// Simulation code
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
const runSimulation = async () => {
Expand All @@ -121,7 +66,6 @@ const Content = () => {
if (Q) {
if (x > 0) tempArray.pop();
tempArray.push({ question: JSON.parse(Questions)[x] });
// tempArray.push({ loading: "loading" });
Q = false;
x++;
} else {
Expand All @@ -135,24 +79,52 @@ const Content = () => {
await sleep(2000);
}
};

useEffect(() => {
switch (serviceType) {
case "text":
initWebSocket();
console.log("Running Gen AI");
if (backendType === "python") {
initWebSocket(
setSummaryResults,
setBusy,
setUpdate,
messagesDP,
socket,
chatData
);
} else {
setClient(
InitStomp(setBusy, setUpdate, messagesDP, chatData, serviceType)
);
}
console.log("Running Generative service");
return;
case "sim":
runSimulation();
console.log("running simulation");
console.log("Running simulation");
return;
case "summary":
initWebSocket();
console.log("summary loading");
if (backendType === "python") {
initWebSocket(
setSummaryResults,
setBusy,
setUpdate,
messagesDP,
socket,
chatData
);
} else {
setClient(
InitStomp(setBusy, setUpdate, messagesDP, chatData, serviceType)
);
}
console.log("Running Summarization service");
return;
}
return () => {
socket.current ? (socket.current.onclose = () => {}) : null;
socket.current?.close();
client?.deactivate();
};
}, [serviceType]);

Expand All @@ -168,7 +140,6 @@ const Content = () => {
autoTimeout: "on",
},
];
//alert("Still waiting for an answer! Hang in there a little longer.");
return;
}
if (event.detail.value) {
Expand All @@ -191,12 +162,13 @@ const Content = () => {
setUpdate(chatData.current);
setBusy(true);

// simulating the delay for now just to show what the animation looks like.
setTimeout(() => {
if (backendType === "python") {
socket.current?.send(
JSON.stringify({ msgType: "question", data: question.current })
);
}, 300);
} else {
sendPrompt(client, question.current!, modelId!, conversationId!);
}
}
};

Expand All @@ -215,19 +187,32 @@ const Content = () => {
};

const serviceTypeChangeHandler = (service: ServiceTypes) => {
localStorage.setItem("service", service);
setUpdate([]);
chatData.current = [];
setServiceType(service);
toggleDrawer();
};

const backendTypeChangeHandler = (backend: BackendTypes) => {
setUpdate([]);
chatData.current = [];
setBackendType(backend);
localStorage.setItem("backend", backend);
location.reload();
};
const modelIdChangeHandler = (event: CustomEvent) => {
console.log("model Id: ", event.detail.value);
if (event.detail.value != null) setModelId(event.detail.value);
};
const clearSummary = () => {
setSummaryResults("");
};

const updateSummaryPrompt = (val: string) => {
setSummaryPrompt(val);
};
const updateSummaryResults = (summary: string) => {
setSummaryResults(summary);
};

return (
<div class="oj-web-applayout-max-width oj-web-applayout-content oj-flex oj-sm-flex-direction-column demo-bg-main">
Expand All @@ -238,8 +223,11 @@ const Content = () => {
aria-label="Settings Drawer"
>
<Settings
serviceType={serviceType}
serviceChange={serviceTypeChangeHandler}
aiServiceType={serviceType}
backendType={backendType}
aiServiceChange={serviceTypeChangeHandler}
backendChange={backendTypeChangeHandler}
modelIdChange={modelIdChangeHandler}
/>
</oj-c-drawer-popup>
<div class="oj-flex-bar oj-flex-item demo-header oj-sm-12">
Expand All @@ -248,9 +236,7 @@ const Content = () => {
position="top"
onojClose={handleToastClose}
></oj-c-message-toast>
{/* <h1 class="oj-typography-heading-lg oj-flex-bar-start"> </h1> */}
<div class="oj-flex-bar-end oj-color-invert demo-header-end">
{/* <h6 class="oj-sm-margin-2x-end">{connState}</h6> */}
<oj-button onojAction={toggleDrawer} label="Toggle" display="icons">
<span slot="startIcon" class="oj-ux-ico-menu"></span>
</oj-button>
Expand All @@ -273,9 +259,11 @@ const Content = () => {
{serviceType === "summary" && (
<Summary
fileChanged={handleFileUpload}
summaryChanged={updateSummaryResults}
summary={summaryResults}
clear={clearSummary}
prompt={updateSummaryPrompt}
backendType={backendType}
/>
)}
</div>
Expand Down
Loading