Skip to content

Commit 6db01d7

Browse files
authored
Merge pull request #1188 from samchon/feat/chat
Complete `@nestia/chat`
2 parents 47ddef6 + 845d345 commit 6db01d7

21 files changed

+584
-160
lines changed

packages/agent/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nestia/agent",
3-
"version": "0.3.3",
3+
"version": "0.3.5",
44
"main": "lib/index.js",
55
"module": "lib/index.mjs",
66
"typings": "lib/index.d.ts",

packages/agent/src/NestiaAgent.ts

+19
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import { NestiaAgentCostAggregator } from "./internal/NestiaAgentCostAggregator"
55
import { NestiaAgentOperationComposer } from "./internal/NestiaAgentOperationComposer";
66
import { NestiaAgentPromptTransformer } from "./internal/NestiaAgentPromptTransformer";
77
import { __map_take } from "./internal/__map_take";
8+
import { INestiaAgentController } from "./structures/INestiaAgentController";
89
import { INestiaAgentEvent } from "./structures/INestiaAgentEvent";
910
import { INestiaAgentOperationCollection } from "./structures/INestiaAgentOperationCollection";
1011
import { INestiaAgentOperationSelection } from "./structures/INestiaAgentOperationSelection";
1112
import { INestiaAgentPrompt } from "./structures/INestiaAgentPrompt";
1213
import { INestiaAgentProps } from "./structures/INestiaAgentProps";
14+
import { INestiaAgentProvider } from "./structures/INestiaAgentProvider";
1315
import { INestiaAgentTokenUsage } from "./structures/INestiaAgentTokenUsage";
1416

1517
/**
@@ -155,6 +157,23 @@ export class NestiaAgent {
155157
return [prompt, ...newbie];
156158
}
157159

160+
/**
161+
* Get LLM Provider.
162+
*/
163+
public getProvider(): INestiaAgentProvider {
164+
return this.props.provider;
165+
}
166+
167+
/**
168+
* Get controllers.
169+
*
170+
* Get list of controllers, which are the collection of functions that
171+
* the "Super A.I. Chatbot" can execute.
172+
*/
173+
public getControllers(): ReadonlyArray<INestiaAgentController> {
174+
return this.props.controllers;
175+
}
176+
158177
/**
159178
* Get the chatbot's prompt histories.
160179
*

packages/agent/src/functional/createHttpLlmApplication.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const createHttpLlmApplication = (props: {
1515
| OpenApiV3.IDocument
1616
| OpenApiV3_1.IDocument
1717
| OpenApi.IDocument;
18-
options?: IHttpLlmApplication.IOptions<"chatgpt">;
18+
options?: Partial<IHttpLlmApplication.IOptions<"chatgpt">>;
1919
}): IValidation<IHttpLlmApplication<"chatgpt">> => {
2020
const inspect: IValidation<
2121
| SwaggerV2.IDocument

packages/chat/build/publish.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const cp = require("child_process");
2+
const fs = require("fs");
3+
4+
const getAgentVersion = async () => {
5+
const packageJson = JSON.parse(
6+
await fs.promises.readFile(
7+
`${__dirname}/../../agent/package.json`,
8+
"utf-8",
9+
),
10+
);
11+
return packageJson.version;
12+
};
13+
14+
const main = async () => {
15+
const agent = await getAgentVersion();
16+
const packageJson = JSON.parse(
17+
await fs.promises.readFile(`${__dirname}/../package.json`, "utf8"),
18+
);
19+
const tag = packageJson.version.includes("dev") ? "next" : "latest";
20+
21+
await fs.promises.writeFile(
22+
`${__dirname}/../package.json`,
23+
JSON.stringify(
24+
{
25+
...packageJson,
26+
dependencies: {
27+
...packageJson.dependencies,
28+
"@nestia/agent": `^${agent}`,
29+
},
30+
},
31+
null,
32+
2,
33+
),
34+
"utf8",
35+
);
36+
37+
const execute = (str) =>
38+
cp.execSync(str, {
39+
cwd: `${__dirname}/..`,
40+
stdio: "inherit",
41+
});
42+
execute("npm run build");
43+
execute(`npm publish --tag ${tag}`);
44+
45+
await fs.promises.writeFile(
46+
`${__dirname}/../package.json`,
47+
JSON.stringify(packageJson, null, 2),
48+
"utf8",
49+
);
50+
};
51+
main().catch((error) => {
52+
console.log(error);
53+
process.exit(-1);
54+
});

packages/chat/package.json

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nestia/chat",
3-
"version": "0.2.1",
3+
"version": "0.1.0",
44
"main": "lib/index.js",
55
"module": "lib/index.mjs",
66
"typings": "lib/index.d.ts",
@@ -36,12 +36,18 @@
3636
"dependencies": {
3737
"@mui/icons-material": "^6.3.1",
3838
"@mui/material": "^5.15.6",
39-
"@nestia/agent": "workspace:^",
40-
"@samchon/openapi": "^2.3.2",
39+
"@nestia/agent": "^0.3.4",
40+
"@samchon/openapi": "^2.3.4",
41+
"html2canvas": "^1.4.1",
42+
"js-file-download": "^0.4.12",
4143
"js-yaml": "^4.1.0",
4244
"prettier": "3.3.3",
45+
"react-json-editor-ajrm": "^2.5.14",
4346
"react-markdown": "^9.0.3",
4447
"react-mui-fileuploader": "^0.5.2",
48+
"rehype-raw": "^7.0.0",
49+
"rehype-stringify": "^10.0.1",
50+
"remark-mermaid-plugin": "^1.0.2",
4551
"typia": "^7.5.1"
4652
},
4753
"devDependencies": {
@@ -54,15 +60,16 @@
5460
"@rollup/plugin-typescript": "^12.1.1",
5561
"@samchon/shopping-api": "^0.11.0",
5662
"@types/js-yaml": "^4.0.9",
57-
"@types/node": "^22.8.6",
63+
"@types/node": "^22.10.5",
5864
"@types/react": "^18.3.11",
5965
"@types/react-dom": "^18.3.1",
66+
"@types/react-json-editor-ajrm": "^2.5.6",
6067
"@vitejs/plugin-react": "^4.3.3",
6168
"eslint": "^9.13.0",
6269
"eslint-plugin-react-hooks": "^5.0.0",
6370
"eslint-plugin-react-refresh": "^0.4.13",
6471
"globals": "^15.11.0",
65-
"openai": "^4.77.0",
72+
"openai": "^4.77.3",
6673
"react": "^18.3.1",
6774
"react-dom": "^18.3.1",
6875
"rollup": "^4.24.2",
@@ -77,6 +84,7 @@
7784
"package.json",
7885
"dist",
7986
"lib",
80-
"src"
87+
"src",
88+
"!src/test.ts"
8189
]
8290
}
+153-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,158 @@
1-
import { IChatGptService } from "@nestia/agent";
2-
import { IHttpConnection } from "@samchon/openapi";
1+
import {
2+
Button,
3+
FormControl,
4+
FormControlLabel,
5+
FormLabel,
6+
Radio,
7+
RadioGroup,
8+
TextField,
9+
Typography,
10+
} from "@mui/material";
11+
import { INestiaAgentProvider, NestiaAgent } from "@nestia/agent";
12+
import { IHttpLlmApplication } from "@samchon/openapi";
13+
import OpenAI from "openai";
14+
import React, { useState } from "react";
15+
import JsonInput from "react-json-editor-ajrm";
16+
// @ts-ignore
17+
import locale from "react-json-editor-ajrm/locale/en";
318

4-
export const NestiaChatUploader = () => {};
19+
import { NestiaChatApplication } from "./NestiaChatApplication";
20+
import { NestiaChatFileUploadMovie } from "./movies/uploader/NestiaChatFileUploadMovie";
21+
22+
export const NestiaChatUploader = (props: NestiaChatUploader.IProps) => {
23+
// PARAMETERS
24+
const [host, setHost] = useState("http://localhost:37001");
25+
const [headers, setHeaders] = useState<Record<string, string>>({
26+
Authorization: "YOUR_SERVER_API_KEY",
27+
});
28+
const [model, setModel] = useState("gpt-4o");
29+
const [apiKey, setApiKey] = useState("YOUR-OPENAI-API-KEY");
30+
31+
// RESULT
32+
const [application, setApplication] =
33+
useState<IHttpLlmApplication<"chatgpt"> | null>(null);
34+
const [progress, setProgress] = useState(false);
35+
36+
// HANDLERS
37+
const handleApplication = (
38+
application: IHttpLlmApplication<"chatgpt"> | null,
39+
error: string | null,
40+
) => {
41+
setApplication(application);
42+
if (error !== null) handleError(error);
43+
};
44+
const handleError = (error: string) => {
45+
if (props.onError) props.onError(error);
46+
else alert(error);
47+
};
48+
49+
const open = async () => {
50+
if (application === null) return;
51+
setProgress(true);
52+
try {
53+
const provider: INestiaAgentProvider = {
54+
type: "chatgpt",
55+
api: new OpenAI({
56+
apiKey,
57+
dangerouslyAllowBrowser: true,
58+
}),
59+
model: model as "gpt-4o",
60+
};
61+
const agent: NestiaAgent = new NestiaAgent({
62+
provider,
63+
controllers: [
64+
{
65+
protocol: "http",
66+
name: "main",
67+
application,
68+
connection: {
69+
host,
70+
headers,
71+
},
72+
},
73+
],
74+
});
75+
props.onSuccess(<NestiaChatApplication agent={agent} />);
76+
} catch (error) {
77+
handleError(error instanceof Error ? error.message : "unknown error");
78+
setProgress(false);
79+
}
80+
};
81+
82+
return (
83+
<React.Fragment>
84+
<NestiaChatFileUploadMovie onChange={handleApplication} />
85+
<br />
86+
<FormControl fullWidth style={{ paddingLeft: 15 }}>
87+
<Typography variant="h6">HTTP Connection</Typography>
88+
<br />
89+
<TextField
90+
onChange={(e) => setHost(e.target.value)}
91+
defaultValue={host}
92+
label="Host URL"
93+
variant="outlined"
94+
/>
95+
<br />
96+
<FormLabel> Headers </FormLabel>
97+
<JsonInput
98+
locale={locale}
99+
theme="dark_vscode_tribute"
100+
placeholder={headers}
101+
onChange={setHeaders}
102+
height="100px"
103+
/>
104+
<br />
105+
<br />
106+
<Typography variant="h6">LLM Arguments</Typography>
107+
<br />
108+
<FormLabel> LLM Provider </FormLabel>
109+
<RadioGroup defaultValue={"chatgpt"} style={{ paddingLeft: 15 }}>
110+
<FormControlLabel
111+
value="chatgpt"
112+
control={<Radio />}
113+
label="OpenAI (ChatGPT)"
114+
/>
115+
</RadioGroup>
116+
<FormLabel style={{ paddingTop: 20 }}> OpenAI Model </FormLabel>
117+
<RadioGroup
118+
defaultValue={model}
119+
onChange={(_e, value) => setModel(value)}
120+
style={{ paddingLeft: 15 }}
121+
>
122+
<FormControlLabel value="gpt-4o" control={<Radio />} label="GPT-4o" />
123+
<FormControlLabel
124+
value="gpt-4o-mini"
125+
control={<Radio />}
126+
label="GPT-4o Mini"
127+
/>
128+
</RadioGroup>
129+
<br />
130+
<TextField
131+
onChange={(e) => setApiKey(e.target.value)}
132+
defaultValue={apiKey}
133+
label="OpenAI API Key"
134+
variant="outlined"
135+
/>
136+
</FormControl>
137+
<br />
138+
<br />
139+
<Button
140+
component="a"
141+
fullWidth
142+
variant="contained"
143+
color={"info"}
144+
size="large"
145+
disabled={progress === true || document === null}
146+
onClick={() => open()}
147+
>
148+
{progress ? "Generating..." : "Generate Editor"}
149+
</Button>
150+
</React.Fragment>
151+
);
152+
};
5153
export namespace NestiaChatUploader {
6154
export interface IProps {
7-
connection?: IHttpConnection;
8-
service?: IChatGptService;
155+
onError?: (error: string) => void;
156+
onSuccess: (element: JSX.Element) => void;
9157
}
10158
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Markdown from "react-markdown";
2+
import rehypeRaw from "rehype-raw";
3+
import rehypeStringify from "rehype-stringify";
4+
import remarkMermaidPlugin from "remark-mermaid-plugin";
5+
6+
export const MarkdownViewer = (props: MarkdownViewer.IProps) => {
7+
return (
8+
<Markdown
9+
remarkPlugins={[remarkMermaidPlugin as any]}
10+
rehypePlugins={[rehypeRaw, rehypeStringify]}
11+
>
12+
{props.children}
13+
</Markdown>
14+
);
15+
};
16+
export namespace MarkdownViewer {
17+
export interface IProps {
18+
children: string | null | undefined;
19+
}
20+
}

packages/chat/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./NestiaChatApplication";
2+
export * from "./NestiaChatUploader";

0 commit comments

Comments
 (0)