From 45edad98da3614f6bb064062ffcd1fb1a08b96c1 Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Wed, 22 Jan 2025 13:46:34 +0900 Subject: [PATCH] Deploy `@nestia/chat` on the website --- packages/chat/index.html | 6 +- packages/chat/package.json | 11 +- packages/chat/shopping/index.html | 14 ++ packages/chat/src/NestiaChatUploader.tsx | 158 ++++++++++++++ .../chat/src/components/MarkdownViewer.tsx | 5 + packages/chat/src/index.ts | 1 + packages/chat/src/main.tsx | 104 +--------- packages/chat/src/movies/NestiaChatMovie.tsx | 11 +- .../NestiaChatDescribeMessageMovie.tsx | 12 +- .../messages/NestiaChatSelectMessageMovie.tsx | 8 +- .../messages/NestiaChatTextMessageMovie.tsx | 3 + .../NestiaChatFunctionStackSideMovie.tsx | 3 +- .../uploader/NestiaChatFileUploadMovie.tsx | 77 +++++++ packages/chat/src/shopping.tsx | 196 ++++++++++++++++++ packages/chat/tsconfig.app.tsbuildinfo | 2 +- packages/chat/tsconfig.lib.json | 2 +- packages/chat/vite.config.ts | 13 ++ website/.gitignore | 1 + website/build/chat.js | 45 ++++ website/next.config.js | 14 ++ website/package.json | 8 +- website/pages/_meta.js | 5 - website/pages/chat.tsx | 3 - .../applications/ShoppingChatApplication.tsx | 166 --------------- 24 files changed, 582 insertions(+), 286 deletions(-) create mode 100644 packages/chat/shopping/index.html create mode 100644 packages/chat/src/NestiaChatUploader.tsx create mode 100644 packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx create mode 100644 packages/chat/src/shopping.tsx create mode 100644 website/build/chat.js delete mode 100644 website/pages/chat.tsx delete mode 100644 website/src/applications/ShoppingChatApplication.tsx diff --git a/packages/chat/index.html b/packages/chat/index.html index db72a82a8..a220427d6 100644 --- a/packages/chat/index.html +++ b/packages/chat/index.html @@ -5,10 +5,10 @@ name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1.0, maximum-scale=3.0s" /> - Nestia A.I. Chatbot + Nestia A.I. Chatbot Uploader
- + - \ No newline at end of file +; diff --git a/packages/chat/package.json b/packages/chat/package.json index ff035c00d..8a5a978da 100644 --- a/packages/chat/package.json +++ b/packages/chat/package.json @@ -1,6 +1,6 @@ { "name": "@nestia/chat", - "version": "0.2.4", + "version": "0.3.1", "type": "module", "main": "./lib/index.mjs", "typings": "./lib/index.d.ts", @@ -35,12 +35,19 @@ }, "homepage": "https://nestia.io", "dependencies": { + "@mui/icons-material": "^6.4.1", "@mui/material": "^6.4.0", "@nestia/agent": "^0.3.7", "@samchon/openapi": "^2.4.0", "html2canvas": "^1.4.1", "js-file-download": "^0.4.12", + "js-yaml": "^4.1.0", + "react-json-editor-ajrm": "^2.5.14", "react-markdown": "^9.0.3", + "react-mui-fileuploader": "^0.5.2", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-mermaid-plugin": "^1.0.2", "typia": "^7.6.0" }, "devDependencies": { @@ -56,6 +63,7 @@ "@types/node": "^22.10.5", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", + "@types/react-json-editor-ajrm": "^2.5.6", "@vitejs/plugin-react": "^4.3.3", "eslint": "^9.13.0", "eslint-plugin-react-hooks": "^5.0.0", @@ -78,6 +86,7 @@ "dist", "lib", "src", + "!src/main.ts", "!src/shopping.ts" ] } \ No newline at end of file diff --git a/packages/chat/shopping/index.html b/packages/chat/shopping/index.html new file mode 100644 index 000000000..ab5866aff --- /dev/null +++ b/packages/chat/shopping/index.html @@ -0,0 +1,14 @@ + + + + + Nestia A.I. Chatbot (Shopping Mall Demonstration) + + +
+ + +;= diff --git a/packages/chat/src/NestiaChatUploader.tsx b/packages/chat/src/NestiaChatUploader.tsx new file mode 100644 index 000000000..70a37dfc8 --- /dev/null +++ b/packages/chat/src/NestiaChatUploader.tsx @@ -0,0 +1,158 @@ +import { + Button, + FormControl, + FormControlLabel, + FormLabel, + Radio, + RadioGroup, + TextField, + Typography, +} from "@mui/material"; +import { INestiaAgentProvider, NestiaAgent } from "@nestia/agent"; +import { IHttpLlmApplication } from "@samchon/openapi"; +import OpenAI from "openai"; +import React, { useState } from "react"; +import JsonInput from "react-json-editor-ajrm"; +// @ts-ignore +import locale from "react-json-editor-ajrm/locale/en.js"; + +import { NestiaChatApplication } from "./NestiaChatApplication"; +import { NestiaChatFileUploadMovie } from "./movies/uploader/NestiaChatFileUploadMovie"; + +export const NestiaChatUploader = (props: NestiaChatUploader.IProps) => { + // PARAMETERS + const [host, setHost] = useState("http://localhost:37001"); + const [headers, setHeaders] = useState>({ + Authorization: "YOUR_SERVER_API_KEY", + }); + const [model, setModel] = useState("gpt-4o"); + const [apiKey, setApiKey] = useState("YOUR-OPENAI-API-KEY"); + + // RESULT + const [application, setApplication] = + useState | null>(null); + const [progress, setProgress] = useState(false); + + // HANDLERS + const handleApplication = ( + application: IHttpLlmApplication<"chatgpt"> | null, + error: string | null, + ) => { + setApplication(application); + if (error !== null) handleError(error); + }; + const handleError = (error: string) => { + if (props.onError) props.onError(error); + else alert(error); + }; + + const open = async () => { + if (application === null) return; + setProgress(true); + try { + const provider: INestiaAgentProvider = { + type: "chatgpt", + api: new OpenAI({ + apiKey, + dangerouslyAllowBrowser: true, + }), + model: model as "gpt-4o", + }; + const agent: NestiaAgent = new NestiaAgent({ + provider, + controllers: [ + { + protocol: "http", + name: "main", + application, + connection: { + host, + headers, + }, + }, + ], + }); + props.onSuccess(); + } catch (error) { + handleError(error instanceof Error ? error.message : "unknown error"); + setProgress(false); + } + }; + + return ( + + +
+ + HTTP Connection +
+ setHost(e.target.value)} + defaultValue={host} + label="Host URL" + variant="outlined" + /> +
+ Headers + +
+
+ LLM Arguments +
+ LLM Provider + + } + label="OpenAI (ChatGPT)" + /> + + OpenAI Model + setModel(value)} + style={{ paddingLeft: 15 }} + > + } label="GPT-4o" /> + } + label="GPT-4o Mini" + /> + +
+ setApiKey(e.target.value)} + defaultValue={apiKey} + label="OpenAI API Key" + variant="outlined" + /> +
+
+
+ +
+ ); +}; +export namespace NestiaChatUploader { + export interface IProps { + onError?: (error: string) => void; + onSuccess: (element: JSX.Element) => void; + } +} diff --git a/packages/chat/src/components/MarkdownViewer.tsx b/packages/chat/src/components/MarkdownViewer.tsx index 94d39cbda..30810c537 100644 --- a/packages/chat/src/components/MarkdownViewer.tsx +++ b/packages/chat/src/components/MarkdownViewer.tsx @@ -1,8 +1,13 @@ import Markdown from "react-markdown"; +import rehypeRaw from "rehype-raw"; +import rehypeStringify from "rehype-stringify"; +import remarkMermaidPlugin from "remark-mermaid-plugin"; export const MarkdownViewer = (props: MarkdownViewer.IProps) => { return ( ( => { - const query: IQuery = ((): IQuery => { - const index: number = window.location.href.indexOf("?"); - if (index === -1) return {}; - const search = new URLSearchParams(window.location.href.substr(index + 1)); - return { - server: search.get("server") as "local" | "real" | undefined, - }; - })(); - - // COMPOSE LLM APPLICATION SCHEMA - const swagger: - | SwaggerV2.IDocument - | OpenApiV3.IDocument - | OpenApiV3_1.IDocument = await fetch( - query.server === "local" - ? "http://127.0.0.1:37001/editor/swagger.json" - : "https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/packages/api/customer.swagger.json", - ).then((r) => r.json()); - const document: OpenApi.IDocument = OpenApi.convert(swagger); - const application: IHttpLlmApplication<"chatgpt"> = HttpLlm.application({ - model: "chatgpt", - document, - }); - application.functions = application.functions.filter((func) => - func.path.startsWith("/shoppings/customers"), - ); - - // HANDSHAKE WITH SHOPPING BACKEND - const connection: IHttpConnection = { - host: - query.server === "local" - ? "http://127.0.0.1:37001" - : "https://shopping-be.wrtn.ai", - }; - await ShoppingApi.functional.shoppings.customers.authenticate.create( - connection, - { - channel_code: "samchon", - external_user: null, - href: "https://127.0.0.1/NodeJS", - referrer: null, - }, - ); - await ShoppingApi.functional.shoppings.customers.authenticate.activate( - connection, - { - mobile: "821012345678", - name: "John Doe", - }, - ); - - // COMPOSE CHAT AGENT - const agent: NestiaAgent = new NestiaAgent({ - provider: { - type: "chatgpt", - api: new OpenAI({ - apiKey: import.meta.env.VITE_CHATGPT_API_KEY, - dangerouslyAllowBrowser: true, - }), - model: "gpt-4o-mini", - }, - controllers: [ - { - protocol: "http", - name: "shopping", - application, - connection, - }, - ], - config: { - locale: "en-US", - }, - }); - createRoot(window.document.getElementById("root")!).render( - , - ); -}; -main().catch(console.error); +createRoot(window.document.getElementById("root")!).render( + { + createRoot(window.document.getElementById("root")!).render(element); + }} + />, +); diff --git a/packages/chat/src/movies/NestiaChatMovie.tsx b/packages/chat/src/movies/NestiaChatMovie.tsx index 97c80a9f6..37d930b7a 100644 --- a/packages/chat/src/movies/NestiaChatMovie.tsx +++ b/packages/chat/src/movies/NestiaChatMovie.tsx @@ -1,3 +1,5 @@ +import AddAPhotoIcon from "@mui/icons-material/AddAPhoto"; +import SendIcon from "@mui/icons-material/Send"; import { AppBar, Button, @@ -155,8 +157,12 @@ export const NestiaChatMovie = ({ agent }: NestiaChatMovie.IProps) => { Nestia A.I. Chatbot - @@ -229,6 +235,7 @@ export const NestiaChatMovie = ({ agent }: NestiaChatMovie.IProps) => { diff --git a/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx b/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx index 1229bdd15..5e3eabf9b 100644 --- a/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx +++ b/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx @@ -1,3 +1,4 @@ +import GradingIcon from "@mui/icons-material/Grading"; import { Button, Card, @@ -25,7 +26,12 @@ export const NestiaChatSelectMessageMovie = ({ }} > - + } + label="Function Selector" + variant="outlined" + color="warning" + />

Operation: diff --git a/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx b/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx index 9258bb06b..37662aefa 100644 --- a/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx +++ b/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx @@ -1,3 +1,5 @@ +import FaceIcon from "@mui/icons-material/Face"; +import SmartToyIcon from "@mui/icons-material/SmartToy"; import { Card, CardContent, Chip } from "@mui/material"; import { INestiaAgentPrompt } from "@nestia/agent"; @@ -26,6 +28,7 @@ export const NestiaChatTextMessageMovie = ({ > : } label={prompt.role === "user" ? "User" : "Assistant"} variant="outlined" color={prompt.role === "user" ? "primary" : "success"} diff --git a/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx b/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx index b9b314fc2..282818616 100644 --- a/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx +++ b/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx @@ -1,3 +1,4 @@ +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { Accordion, AccordionDetails, @@ -18,7 +19,7 @@ export const NestiaChatFunctionStackSideMovie = (
{props.selections.map((select) => ( - + }> {select.protocol === "http" ? `${select.function.method.toUpperCase()} ${select.function.path}` diff --git a/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx b/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx new file mode 100644 index 000000000..ca50d0b53 --- /dev/null +++ b/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx @@ -0,0 +1,77 @@ +import { createHttpLlmApplication } from "@nestia/agent"; +import { OpenApiV3, OpenApiV3_1, SwaggerV2 } from "@samchon/openapi"; +import { IHttpLlmApplication } from "@samchon/openapi"; +import { load } from "js-yaml"; +import React from "react"; +// @ts-ignore +import FileUpload from "react-mui-fileuploader"; +// @ts-ignore +import { ExtendedFileProps } from "react-mui-fileuploader/dist/types/index.types"; +import { IValidation } from "typia"; + +export const NestiaChatFileUploadMovie = ( + props: NestiaChatFileUploadMovie.IProps, +) => { + const [elements, setElements] = React.useState([]); + const onChange = async (array: ExtendedFileProps[]) => { + if (array.length === 0) { + props.onChange(null, null); + return; + } + + const file: ExtendedFileProps = array[array.length - 1]!; + const buffer: ArrayBuffer = await file.arrayBuffer(); + const content: string = new TextDecoder().decode(buffer); + const extension: "json" | "yaml" = file.name.split(".").pop()! as + | "json" + | "yaml"; + + try { + const document: + | SwaggerV2.IDocument + | OpenApiV3.IDocument + | OpenApiV3_1.IDocument = + extension === "json" ? JSON.parse(content) : load(content); + const application: IValidation> = + createHttpLlmApplication({ + model: "chatgpt", + document, + options: { + reference: true, + }, + }); + if (application.success === true) props.onChange(application.data, null); + else props.onChange(null, JSON.stringify(application.errors, null, 2)); + } catch { + props.onChange( + null, + extension === "json" ? "Invalid JSON file" : "Invalid YAML file", + ); + return; + } + if (array.length > 1) setElements([file]); + }; + return ( + + ); +}; +export namespace NestiaChatFileUploadMovie { + export interface IProps { + onChange: ( + application: IHttpLlmApplication<"chatgpt"> | null, + error: string | null, + ) => void; + } +} diff --git a/packages/chat/src/shopping.tsx b/packages/chat/src/shopping.tsx new file mode 100644 index 000000000..6913e51a5 --- /dev/null +++ b/packages/chat/src/shopping.tsx @@ -0,0 +1,196 @@ +import { + Button, + Divider, + FormControl, + FormControlLabel, + Link, + Radio, + RadioGroup, + TextField, + Typography, +} from "@mui/material"; +import { NestiaAgent } from "@nestia/agent"; +import { + HttpLlm, + IHttpConnection, + IHttpLlmApplication, + OpenApi, +} from "@samchon/openapi"; +import ShoppingApi from "@samchon/shopping-api"; +import OpenAI from "openai"; +import { useState } from "react"; +import { createRoot } from "react-dom/client"; + +import { NestiaChatApplication } from "./NestiaChatApplication"; + +function ShoppingChatApplication() { + const [apiKey, setApiKey] = useState(""); + const [model, setModel] = useState("gpt-4o-mini"); + + const [locale, setLocale] = useState(window.navigator.language); + const [name, setName] = useState("John Doe"); + const [mobile, setMobile] = useState("821012345678"); + + const [agent, setAgent] = useState(null); + const [progress, setProgress] = useState(false); + + const startChatApplication = async () => { + setProgress(true); + // PREPARE LLM APPLICATION + const application: IHttpLlmApplication<"chatgpt"> = HttpLlm.application({ + model: "chatgpt", + document: OpenApi.convert( + await fetch( + "https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/packages/api/customer.swagger.json", + ).then((r) => r.json()), + ), + }); + + // HANDLESHAKE WITH SHOPPING BACKEND + const connection: IHttpConnection = { + host: "https://shopping-be.wrtn.ai", + }; + await ShoppingApi.functional.shoppings.customers.authenticate.create( + connection, + { + channel_code: "samchon", + external_user: null, + href: window.location.href, + referrer: window.document.referrer, + }, + ); + await ShoppingApi.functional.shoppings.customers.authenticate.activate( + connection, + { + mobile, + name, + }, + ); + + // COMPOSE CHAT AGENT + setAgent( + new NestiaAgent({ + provider: { + type: "chatgpt", + api: new OpenAI({ + apiKey, + dangerouslyAllowBrowser: true, + }), + model: "gpt-4o-mini", + }, + controllers: [ + { + protocol: "http", + name: "shopping", + application, + connection, + }, + ], + }), + ); + }; + + return ( +
+ {agent ? ( + + ) : ( + + Shopping A.I. Chatbot +
+ +
+ Demonstration of Nestia A.I. Chatbot with Shopping Backend API. +
+
+ + https://github.com/samchon/shopping-backend + +
+
+ OpenAI Configuration + setApiKey(e.target.value)} + defaultValue={apiKey} + label="OpenAI API Key" + variant="outlined" + /> +
+ setModel(value)} + style={{ paddingLeft: 15 }} + > + } + label="GPT-4o Mini" + value="gpt-4o-mini" + /> + } + label="GPT-4o" + value="gpt-4o" + /> + +
+ Membership Information +
+ setLocale(e.target.value)} + defaultValue={locale} + label="Locale" + variant="outlined" + /> +
+ setName(e.target.value)} + defaultValue={name} + label="Name" + variant="outlined" + /> +
+ setMobile(e.target.value)} + defaultValue={mobile} + label="Mobile" + variant="outlined" + /> +
+
+ +
+ )} +
+ ); +} + +const main = async (): Promise => { + createRoot(window.document.getElementById("root")!).render( + , + ); +}; +main().catch(console.error); diff --git a/packages/chat/tsconfig.app.tsbuildinfo b/packages/chat/tsconfig.app.tsbuildinfo index 1a2e293c8..b05b1481e 100644 --- a/packages/chat/tsconfig.app.tsbuildinfo +++ b/packages/chat/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/nestiachatapplication.tsx","./src/index.ts","./src/main.tsx","./src/vite-env.d.ts","./src/components/markdownviewer.tsx","./src/movies/nestiachatmovie.tsx","./src/movies/messages/nestiachatdescribemessagemovie.tsx","./src/movies/messages/nestiachatexecutemessagemovie.tsx","./src/movies/messages/nestiachatmessagemovie.tsx","./src/movies/messages/nestiachatselectmessagemovie.tsx","./src/movies/messages/nestiachattextmessagemovie.tsx","./src/movies/sides/nestiachatfunctionstacksidemovie.tsx","./src/movies/sides/nestiachatsidemovie.tsx","./src/movies/sides/nestiachattokenusagesidemovie.tsx"],"version":"5.7.3"} \ No newline at end of file +{"root":["./src/nestiachatapplication.tsx","./src/nestiachatuploader.tsx","./src/index.ts","./src/main.tsx","./src/shopping.tsx","./src/vite-env.d.ts","./src/components/markdownviewer.tsx","./src/movies/nestiachatmovie.tsx","./src/movies/messages/nestiachatdescribemessagemovie.tsx","./src/movies/messages/nestiachatexecutemessagemovie.tsx","./src/movies/messages/nestiachatmessagemovie.tsx","./src/movies/messages/nestiachatselectmessagemovie.tsx","./src/movies/messages/nestiachattextmessagemovie.tsx","./src/movies/sides/nestiachatfunctionstacksidemovie.tsx","./src/movies/sides/nestiachatsidemovie.tsx","./src/movies/sides/nestiachattokenusagesidemovie.tsx","./src/movies/uploader/nestiachatfileuploadmovie.tsx"],"version":"5.7.3"} \ No newline at end of file diff --git a/packages/chat/tsconfig.lib.json b/packages/chat/tsconfig.lib.json index 054a7b15c..19a09302e 100644 --- a/packages/chat/tsconfig.lib.json +++ b/packages/chat/tsconfig.lib.json @@ -102,5 +102,5 @@ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": ["./src"], - "exclude": ["./src/shopping.tsx"], + "exclude": ["./src/main.tsx", "./src/shopping.tsx"], } diff --git a/packages/chat/vite.config.ts b/packages/chat/vite.config.ts index 581248e21..bdf6b6ece 100644 --- a/packages/chat/vite.config.ts +++ b/packages/chat/vite.config.ts @@ -1,9 +1,22 @@ import react from "@vitejs/plugin-react"; +import path from "path"; +import { fileURLToPath } from "url"; import { defineConfig } from "vite"; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + // https://vite.dev/config/ export default defineConfig({ base: "./", + build: { + rollupOptions: { + input: { + index: path.resolve(__dirname, "index.html"), + "shopping/index.html": path.resolve(__dirname, "shopping/index.html"), + }, + }, + }, plugins: [ react(), { diff --git a/website/.gitignore b/website/.gitignore index ca1693355..15d2605ac 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -2,6 +2,7 @@ node_modules/ out/ public/api/ +public/chat/ typedoc-json/ public/downloads diff --git a/website/build/chat.js b/website/build/chat.js new file mode 100644 index 000000000..38ee8b5e3 --- /dev/null +++ b/website/build/chat.js @@ -0,0 +1,45 @@ +import cp from "child_process"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const AGENT = `${__dirname}/../../packages/agent`; +const CHAT = `${__dirname}/../../packages/chat`; +const PUBLIC = `${__dirname}/../public/chat`; + +const copy = async (src, dest) => { + try { + if (fs.existsSync(dest)) await fs.promises.rm(dest, { recursive: true }); + } catch {} + try { + await fs.promises.mkdir(dest); + } catch {} + + const directory = await fs.promises.readdir(src); + for (const file of directory) { + const x = path.join(src, file); + const y = path.join(dest, file); + const stat = await fs.promises.stat(x); + if (stat.isDirectory()) await copy(x, y); + else await fs.promises.writeFile(y, await fs.promises.readFile(x)); + } +}; + +const main = async () => { + cp.execSync("npm run build", { + stdio: "ignore", + cwd: AGENT, + }); + cp.execSync("npm run build:static", { + stdio: "ignore", + cwd: CHAT, + }); + await copy(`${CHAT}/dist`, PUBLIC); +}; +main().catch((error) => { + console.error(error); + process.exit(-1); +}); diff --git a/website/next.config.js b/website/next.config.js index 4301fb651..ae2bf287f 100644 --- a/website/next.config.js +++ b/website/next.config.js @@ -12,5 +12,19 @@ const nextConfig = { unoptimized: true, }, output: "export", + rewrites: async () => [ + { + source: "/api", + destination: "/api/index.html", + }, + { + source: "/chat", + destination: "/chat/index.html", + }, + { + source: "/chat/shopping", + destination: "/chat/shopping/index.html", + }, + ], }; export default nextConfig; diff --git a/website/package.json b/website/package.json index 3ee679037..5ed98c65f 100644 --- a/website/package.json +++ b/website/package.json @@ -5,9 +5,10 @@ "description": "Nestia Guide Documents", "private": true, "scripts": { - "build": "rimraf .next && rimraf .out && node build/editor && node build/typedoc && next build && node build/sitemap", + "build": "rimraf .next && rimraf .out && node build/chat && node build/editor && node build/typedoc && next build && node build/sitemap", "deploy": "node build/deploy", - "dev": "next dev" + "dev": "next dev", + "prepare": "node build/chat" }, "repository": { "type": "git", @@ -24,11 +25,8 @@ "@mui/icons-material": "^6.4.0", "@mui/material": "^6.4.0", "@mui/system": "^6.4.0", - "@nestia/agent": "^0.3.7", - "@nestia/chat": "^0.2.4", "@nestia/editor": "^4.6.1", "@samchon/openapi": "^2.4.0", - "@samchon/shopping-api": "^0.14.0", "next": "14.2.21", "nextra": "^3.2.4", "nextra-theme-docs": "^3.2.4", diff --git a/website/pages/_meta.js b/website/pages/_meta.js index e67db2ea3..ceed37508 100644 --- a/website/pages/_meta.js +++ b/website/pages/_meta.js @@ -15,11 +15,6 @@ export default { title: "💻 Playground", type: "page", }, - chat: { - title: "💬 Nestia Super A.I. Chatbot", - display: "hidden", - href: "/chat/", - }, editor: { title: "🛠️ Nestia Editor", display: "hidden", diff --git a/website/pages/chat.tsx b/website/pages/chat.tsx deleted file mode 100644 index 286c11ab6..000000000 --- a/website/pages/chat.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import ShoppingChatApplication from "../src/applications/ShoppingChatApplication"; - -export default ShoppingChatApplication; diff --git a/website/src/applications/ShoppingChatApplication.tsx b/website/src/applications/ShoppingChatApplication.tsx deleted file mode 100644 index 5174221c0..000000000 --- a/website/src/applications/ShoppingChatApplication.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { - Button, - FormControl, - FormControlLabel, - FormLabel, - Radio, - RadioGroup, - TextField, - Typography, -} from "@mui/material"; -import { NestiaAgent } from "@nestia/agent"; -import { NestiaChatApplication } from "@nestia/chat"; -import { - HttpLlm, - IHttpConnection, - IHttpLlmApplication, - OpenApi, -} from "@samchon/openapi"; -import ShoppingApi from "@samchon/shopping-api"; -import OpenAI from "openai"; -import { useState } from "react"; - -export default function ShoppingChatApplication() { - const [apiKey, setApiKey] = useState(""); - const [model, setModel] = useState("gpt-4o-mini"); - const [name, setName] = useState("John Doe"); - const [mobile, setMobile] = useState("821012345678"); - const [progress, setProgress] = useState(false); - const [agent, setAgent] = useState(null); - - const openChatApplication = async () => { - setProgress(true); - // PREPARE LLM APPLICATION - const application: IHttpLlmApplication<"chatgpt"> = HttpLlm.application({ - model: "chatgpt", - document: OpenApi.convert( - await fetch( - "https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/packages/api/customer.swagger.json", - ).then((r) => r.json()), - ), - }); - - // HANDLESHAKE WITH SHOPPING BACKEND - const connection: IHttpConnection = { - host: "https://shopping-be.wrtn.ai", - }; - await ShoppingApi.functional.shoppings.customers.authenticate.create( - connection, - { - channel_code: "samchon", - external_user: null, - href: window.location.href, - referrer: window.document.referrer, - }, - ); - await ShoppingApi.functional.shoppings.customers.authenticate.activate( - connection, - { - mobile, - name, - }, - ); - - // COMPOSE CHAT AGENT - setAgent( - new NestiaAgent({ - provider: { - type: "chatgpt", - api: new OpenAI({ - apiKey, - dangerouslyAllowBrowser: true, - }), - model: "gpt-4o-mini", - }, - controllers: [ - { - protocol: "http", - name: "shopping", - application, - connection, - }, - ], - }), - ); - }; - - return ( -
-
- {agent ? ( - - ) : ( - - Shopping A.I. Chatbot -
-
- Demonstration of Nestia A.I. Chatbot with Shopping Backend API. -
-
- OpenAI Configuration - setApiKey(e.target.value)} - defaultValue={apiKey} - label="OpenAI API Key" - variant="outlined" - /> -
- setModel(value)} - style={{ paddingLeft: 15 }} - > - } - label="GPT-4o Mini" - value="gpt-4o-mini" - /> - } - label="GPT-4o" - value="gpt-4o" - /> - -
- Membership Information - setName(e.target.value)} - defaultValue={name} - label="Name" - variant="outlined" - /> - setMobile(e.target.value)} - defaultValue={mobile} - label="Mobile" - variant="outlined" - /> -
-
- -
- )} -
-
- ); -}