From 77872e23dfd4e9e2650dcae02b1d9ce1143c562c Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Tue, 21 Jan 2025 23:55:22 +0900 Subject: [PATCH] Demonstration by Shopping Mall in website --- packages/agent/package.json | 2 +- packages/agent/src/NestiaAgent.ts | 8 + packages/agent/test/cli.ts | 22 ++- packages/chat/build/{deploy.js => deploy.mjs} | 9 +- packages/chat/index.html | 2 +- packages/chat/package.json | 26 +-- .../{rollup.config.js => rollup.config.cjs} | 0 packages/chat/shopping.html | 14 -- packages/chat/src/NestiaChatUploader.tsx | 158 ----------------- .../chat/src/components/MarkdownViewer.tsx | 17 +- packages/chat/src/index.ts | 1 - packages/chat/src/main.tsx | 104 ++++++++++- packages/chat/src/movies/NestiaChatMovie.tsx | 8 +- .../NestiaChatDescribeMessageMovie.tsx | 19 +- .../messages/NestiaChatSelectMessageMovie.tsx | 19 +- .../messages/NestiaChatTextMessageMovie.tsx | 2 - .../NestiaChatFunctionStackSideMovie.tsx | 3 +- .../src/movies/sides/NestiaChatSideMovie.tsx | 8 + .../uploader/NestiaChatFileUploadMovie.tsx | 77 -------- packages/chat/src/shopping.tsx | 81 --------- packages/chat/tsconfig.app.tsbuildinfo | 2 +- packages/chat/tsconfig.lib.json | 6 +- packages/chat/tsconfig.node.tsbuildinfo | 2 +- website/{next.config.mjs => next.config.js} | 6 - website/package.json | 22 ++- website/pages/_meta.js | 11 -- website/pages/chat/_meta.js | 12 ++ website/pages/chat/index.tsx | 164 ++++++++++++++++++ website/pages/editor/_meta.js | 12 ++ .../pages/{editor.tsx => editor/index.tsx} | 0 30 files changed, 368 insertions(+), 449 deletions(-) rename packages/chat/build/{deploy.js => deploy.mjs} (84%) rename packages/chat/{rollup.config.js => rollup.config.cjs} (100%) delete mode 100644 packages/chat/shopping.html delete mode 100644 packages/chat/src/NestiaChatUploader.tsx delete mode 100644 packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx delete mode 100644 packages/chat/src/shopping.tsx rename website/{next.config.mjs => next.config.js} (73%) create mode 100644 website/pages/chat/_meta.js create mode 100644 website/pages/chat/index.tsx create mode 100644 website/pages/editor/_meta.js rename website/pages/{editor.tsx => editor/index.tsx} (100%) diff --git a/packages/agent/package.json b/packages/agent/package.json index e6c295f3a..20a60f04c 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@nestia/agent", - "version": "0.3.6", + "version": "0.3.7", "main": "lib/index.js", "module": "lib/index.mjs", "typings": "lib/index.d.ts", diff --git a/packages/agent/src/NestiaAgent.ts b/packages/agent/src/NestiaAgent.ts index 28386ffb0..a09ebab2d 100644 --- a/packages/agent/src/NestiaAgent.ts +++ b/packages/agent/src/NestiaAgent.ts @@ -5,6 +5,7 @@ import { NestiaAgentCostAggregator } from "./internal/NestiaAgentCostAggregator" import { NestiaAgentOperationComposer } from "./internal/NestiaAgentOperationComposer"; import { NestiaAgentPromptTransformer } from "./internal/NestiaAgentPromptTransformer"; import { __map_take } from "./internal/__map_take"; +import { INestiaAgentConfig } from "./structures/INestiaAgentConfig"; import { INestiaAgentController } from "./structures/INestiaAgentController"; import { INestiaAgentEvent } from "./structures/INestiaAgentEvent"; import { INestiaAgentOperationCollection } from "./structures/INestiaAgentOperationCollection"; @@ -157,6 +158,13 @@ export class NestiaAgent { return [prompt, ...newbie]; } + /** + * Get configuration. + */ + public getConfig(): INestiaAgentConfig | undefined { + return this.props.config; + } + /** * Get LLM Provider. */ diff --git a/packages/agent/test/cli.ts b/packages/agent/test/cli.ts index 0a1f72046..75b7721e9 100644 --- a/packages/agent/test/cli.ts +++ b/packages/agent/test/cli.ts @@ -27,19 +27,17 @@ const main = async (): Promise => { if (!TestGlobal.env.CHATGPT_API_KEY?.length) return; // GET LLM APPLICATION SCHEMA - const swagger: - | SwaggerV2.IDocument - | OpenApiV3.IDocument - | OpenApiV3_1.IDocument = JSON.parse( - await fs.promises.readFile( - `${TestGlobal.ROOT}/../../../shopping-backend/packages/api/swagger.json`, - "utf8", - ), - ); - const document: OpenApi.IDocument = OpenApi.convert(typia.assert(swagger)); const application: IHttpLlmApplication<"chatgpt"> = HttpLlm.application({ model: "chatgpt", - document, + document: OpenApi.convert( + typia.json.assertParse< + SwaggerV2.IDocument | OpenApiV3.IDocument | OpenApiV3_1.IDocument + >( + await fetch(`http://127.0.0.1:37001/editor/swagger.json`).then((r) => + r.text(), + ), + ), + ), options: { reference: true, }, @@ -50,7 +48,7 @@ const main = async (): Promise => { // HANDSHAKE WITH SHOPPING BACKEND const connection: IHttpConnection = { - host: "http://localhost:37001", + host: "http://127.0.0.1:37001", }; await ShoppingApi.functional.shoppings.customers.authenticate.create( connection, diff --git a/packages/chat/build/deploy.js b/packages/chat/build/deploy.mjs similarity index 84% rename from packages/chat/build/deploy.js rename to packages/chat/build/deploy.mjs index 18fb18092..3028ac7e6 100644 --- a/packages/chat/build/deploy.js +++ b/packages/chat/build/deploy.mjs @@ -1,5 +1,10 @@ -const cp = require("child_process"); -const fs = require("fs"); +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 getAgentVersion = async () => { const packageJson = JSON.parse( diff --git a/packages/chat/index.html b/packages/chat/index.html index aa496dc21..db72a82a8 100644 --- a/packages/chat/index.html +++ b/packages/chat/index.html @@ -11,4 +11,4 @@
- + \ No newline at end of file diff --git a/packages/chat/package.json b/packages/chat/package.json index 23d620314..ff035c00d 100644 --- a/packages/chat/package.json +++ b/packages/chat/package.json @@ -1,18 +1,18 @@ { "name": "@nestia/chat", - "version": "0.2.1", - "main": "lib/index.js", - "module": "lib/index.mjs", - "typings": "lib/index.d.ts", + "version": "0.2.4", + "type": "module", + "main": "./lib/index.mjs", + "typings": "./lib/index.d.ts", "description": "Super A.I. Chatbot application by Swagger Document", "scripts": { "build": "npm run build:static && npm run build:lib", "build:static": "rimraf dist && tsc -b && vite build", - "build:lib": "rimraf lib && tsc --project tsconfig.lib.json && rollup -c", + "build:lib": "rimraf lib && tsc --project tsconfig.lib.json --emitDeclarationOnly && rollup -c", "dev": "vite", "lint": "eslint .", "preview": "vite preview", - "deploy": "node build/deploy.js" + "deploy": "node build/deploy.mjs" }, "repository": { "type": "git", @@ -35,20 +35,12 @@ }, "homepage": "https://nestia.io", "dependencies": { - "@mui/icons-material": "^6.3.1", - "@mui/material": "^5.15.6", - "@nestia/agent": "workspace:^", + "@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", - "prettier": "3.3.3", - "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": { @@ -64,7 +56,6 @@ "@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", @@ -73,6 +64,7 @@ "openai": "^4.77.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "rimraf": "^6.0.1", "rollup": "^4.24.2", "ts-node": "^10.9.2", "typescript": "~5.7.2", diff --git a/packages/chat/rollup.config.js b/packages/chat/rollup.config.cjs similarity index 100% rename from packages/chat/rollup.config.js rename to packages/chat/rollup.config.cjs diff --git a/packages/chat/shopping.html b/packages/chat/shopping.html deleted file mode 100644 index 1fdea304d..000000000 --- a/packages/chat/shopping.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Nestia A.I. Chatbot - - -
- - - diff --git a/packages/chat/src/NestiaChatUploader.tsx b/packages/chat/src/NestiaChatUploader.tsx deleted file mode 100644 index 49e3700ce..000000000 --- a/packages/chat/src/NestiaChatUploader.tsx +++ /dev/null @@ -1,158 +0,0 @@ -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"; - -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 d2a993b5b..94d39cbda 100644 --- a/packages/chat/src/components/MarkdownViewer.tsx +++ b/packages/chat/src/components/MarkdownViewer.tsx @@ -1,13 +1,20 @@ 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 ( ( + + ), + }} > {props.children} diff --git a/packages/chat/src/index.ts b/packages/chat/src/index.ts index ef64fc262..d8740b68e 100644 --- a/packages/chat/src/index.ts +++ b/packages/chat/src/index.ts @@ -1,2 +1 @@ export * from "./NestiaChatApplication"; -export * from "./NestiaChatUploader"; diff --git a/packages/chat/src/main.tsx b/packages/chat/src/main.tsx index 2025fe3ea..06092ccea 100644 --- a/packages/chat/src/main.tsx +++ b/packages/chat/src/main.tsx @@ -1,11 +1,99 @@ +import { NestiaAgent } from "@nestia/agent"; +import { + HttpLlm, + IHttpConnection, + IHttpLlmApplication, + OpenApi, + OpenApiV3, + OpenApiV3_1, + SwaggerV2, +} from "@samchon/openapi"; +import ShoppingApi from "@samchon/shopping-api"; +import OpenAI from "openai"; import { createRoot } from "react-dom/client"; -import { NestiaChatUploader } from "./NestiaChatUploader"; +import { NestiaChatApplication } from "./NestiaChatApplication"; -createRoot(window.document.getElementById("root")!).render( - { - createRoot(window.document.getElementById("root")!).render(element); - }} - />, -); +interface IQuery { + server?: "local" | "real"; +} + +const main = async (): Promise => { + 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); diff --git a/packages/chat/src/movies/NestiaChatMovie.tsx b/packages/chat/src/movies/NestiaChatMovie.tsx index ec3b66133..97c80a9f6 100644 --- a/packages/chat/src/movies/NestiaChatMovie.tsx +++ b/packages/chat/src/movies/NestiaChatMovie.tsx @@ -1,5 +1,3 @@ -import { AddAPhoto } from "@mui/icons-material"; -import SendIcon from "@mui/icons-material/Send"; import { AppBar, Button, @@ -27,6 +25,7 @@ export const NestiaChatMovie = ({ agent }: NestiaChatMovie.IProps) => { const middleDivRef = useRef(null); const bottomDivRef = useRef(null); const bodyContainerRef = useRef(null); + const scrollRef = useRef(null); const inputRef = useRef(null); const [text, setText] = useState(""); @@ -156,7 +155,7 @@ export const NestiaChatMovie = ({ agent }: NestiaChatMovie.IProps) => { Nestia A.I. Chatbot - @@ -190,6 +189,7 @@ export const NestiaChatMovie = ({ agent }: NestiaChatMovie.IProps) => {
{ @@ -228,7 +229,6 @@ 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 14a0c93de..1229bdd15 100644 --- a/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx +++ b/packages/chat/src/movies/messages/NestiaChatSelectMessageMovie.tsx @@ -1,4 +1,3 @@ -import { ExpandMore, Grading } from "@mui/icons-material"; import { Button, Card, @@ -26,12 +25,7 @@ export const NestiaChatSelectMessageMovie = ({ }} > - } - label="Function Selector" - variant="outlined" - color="warning" - /> +

Operation: @@ -48,16 +42,7 @@ export const NestiaChatSelectMessageMovie = ({ {selection.reason}
- diff --git a/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx b/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx index f40d0ccef..9258bb06b 100644 --- a/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx +++ b/packages/chat/src/movies/messages/NestiaChatTextMessageMovie.tsx @@ -1,4 +1,3 @@ -import { Face, SmartToy } from "@mui/icons-material"; import { Card, CardContent, Chip } from "@mui/material"; import { INestiaAgentPrompt } from "@nestia/agent"; @@ -27,7 +26,6 @@ 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 282818616..b9b314fc2 100644 --- a/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx +++ b/packages/chat/src/movies/sides/NestiaChatFunctionStackSideMovie.tsx @@ -1,4 +1,3 @@ -import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { Accordion, AccordionDetails, @@ -19,7 +18,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/sides/NestiaChatSideMovie.tsx b/packages/chat/src/movies/sides/NestiaChatSideMovie.tsx index 3f848aac3..4782dac22 100644 --- a/packages/chat/src/movies/sides/NestiaChatSideMovie.tsx +++ b/packages/chat/src/movies/sides/NestiaChatSideMovie.tsx @@ -1,5 +1,6 @@ import { Typography } from "@mui/material"; import { + INestiaAgentConfig, INestiaAgentOperationSelection, INestiaAgentProvider, INestiaAgentTokenUsage, @@ -20,6 +21,12 @@ export const NestiaChatSideMovie = (props: NestiaChatSideMovie.IProps) => {
  • Provider: {props.provider.type}
  • Model: {props.provider.model}
  • +
  • Locale: {props.config?.locale ?? navigator.language}
  • +
  • + Timezone:{" "} + {props.config?.timezone ?? + Intl.DateTimeFormat().resolvedOptions().timeZone} +


@@ -33,6 +40,7 @@ export const NestiaChatSideMovie = (props: NestiaChatSideMovie.IProps) => { export namespace NestiaChatSideMovie { export interface IProps { provider: INestiaAgentProvider; + config: INestiaAgentConfig | undefined; usage: INestiaAgentTokenUsage; selections: INestiaAgentOperationSelection[]; } diff --git a/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx b/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx deleted file mode 100644 index ca50d0b53..000000000 --- a/packages/chat/src/movies/uploader/NestiaChatFileUploadMovie.tsx +++ /dev/null @@ -1,77 +0,0 @@ -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 deleted file mode 100644 index 72a613386..000000000 --- a/packages/chat/src/shopping.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { NestiaAgent } from "@nestia/agent"; -import { - HttpLlm, - IHttpConnection, - IHttpLlmApplication, - OpenApi, - OpenApiV3, - OpenApiV3_1, - SwaggerV2, -} from "@samchon/openapi"; -import ShoppingApi from "@samchon/shopping-api"; -import OpenAI from "openai"; -import { createRoot } from "react-dom/client"; - -import { NestiaChatApplication } from "./NestiaChatApplication"; - -const main = async (): Promise => { - // COMPOSE LLM APPLICATION SCHEMA - const swagger: - | SwaggerV2.IDocument - | OpenApiV3.IDocument - | OpenApiV3_1.IDocument = await fetch( - "https://raw.githubusercontent.com/samchon/shopping-backend/refs/heads/master/packages/api/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((f) => - f.path.startsWith("/shoppings/customers"), - ); - - // HANDSHAKE 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: "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", - }, - controllers: [ - { - protocol: "http", - name: "shopping", - application, - connection, - }, - ], - config: { - locale: "en-US", - }, - }); - 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 796fccafa..1a2e293c8 100644 --- a/packages/chat/tsconfig.app.tsbuildinfo +++ b/packages/chat/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"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.2"} \ No newline at end of file +{"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 diff --git a/packages/chat/tsconfig.lib.json b/packages/chat/tsconfig.lib.json index 895d718ac..054a7b15c 100644 --- a/packages/chat/tsconfig.lib.json +++ b/packages/chat/tsconfig.lib.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "lib": [ "DOM", "ES2020" @@ -27,9 +27,9 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "ESNext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ diff --git a/packages/chat/tsconfig.node.tsbuildinfo b/packages/chat/tsconfig.node.tsbuildinfo index 1e7ed2791..0440098cb 100644 --- a/packages/chat/tsconfig.node.tsbuildinfo +++ b/packages/chat/tsconfig.node.tsbuildinfo @@ -1 +1 @@ -{"root":["./vite.config.ts"],"version":"5.7.2"} \ No newline at end of file +{"root":["./vite.config.ts"],"version":"5.7.3"} \ No newline at end of file diff --git a/website/next.config.mjs b/website/next.config.js similarity index 73% rename from website/next.config.mjs rename to website/next.config.js index 4878c25e6..4301fb651 100644 --- a/website/next.config.mjs +++ b/website/next.config.js @@ -12,11 +12,5 @@ const nextConfig = { unoptimized: true, }, output: "export", - rewrites: async () => [ - { - source: "/api", - destination: "/api/index.html", - }, - ], }; export default nextConfig; diff --git a/website/package.json b/website/package.json index 1043fda86..3ee679037 100644 --- a/website/package.json +++ b/website/package.json @@ -1,4 +1,5 @@ { + "type": "module", "name": "nestia.io", "version": "3.1.1", "description": "Nestia Guide Documents", @@ -18,17 +19,22 @@ "url": "https://github.com/samchon/nestia/issues" }, "dependencies": { - "@emotion/react": "11.10.6", - "@emotion/styled": "11.10.6", - "@mui/icons-material": "5.15.6", - "@mui/material": "5.15.6", - "@mui/system": "5.15.6", - "@nestia/editor": "latest", + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@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", - "react": "18.2.0", - "react-dom": "18.2.0" + "openai": "^4.79.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { "@types/node": "18.11.10", diff --git a/website/pages/_meta.js b/website/pages/_meta.js index 1a5d95eb6..77a3297c4 100644 --- a/website/pages/_meta.js +++ b/website/pages/_meta.js @@ -12,17 +12,6 @@ export default { title: "📖 Guide Documents", type: "page", }, - editor: { - title: "🛠️ Nestia Editor", - type: "page", - href: "/editor/", - hidden: true, - display: "hidden", - theme: { - layout: "raw", - footer: false, - }, - }, playground: { title: "💻 Playground", type: "page", diff --git a/website/pages/chat/_meta.js b/website/pages/chat/_meta.js new file mode 100644 index 000000000..b6722f827 --- /dev/null +++ b/website/pages/chat/_meta.js @@ -0,0 +1,12 @@ +export default { + index: { + title: "💬 Nestia Super A.I. Chatbot", + type: "page", + hidden: true, + display: "hidden", + theme: { + layout: "raw", + footer: false, + }, + }, +}; diff --git a/website/pages/chat/index.tsx b/website/pages/chat/index.tsx new file mode 100644 index 000000000..ca35f6b98 --- /dev/null +++ b/website/pages/chat/index.tsx @@ -0,0 +1,164 @@ +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 ShoppingChat() { + 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" + /> +
+
+ +
+ )} +
+ ); +} diff --git a/website/pages/editor/_meta.js b/website/pages/editor/_meta.js new file mode 100644 index 000000000..835a8d53b --- /dev/null +++ b/website/pages/editor/_meta.js @@ -0,0 +1,12 @@ +export default { + index: { + title: "🛠️ Nestia Editor", + type: "page", + hidden: true, + display: "hidden", + theme: { + layout: "raw", + footer: false, + }, + }, +}; diff --git a/website/pages/editor.tsx b/website/pages/editor/index.tsx similarity index 100% rename from website/pages/editor.tsx rename to website/pages/editor/index.tsx