diff --git a/README.md b/README.md index 470fd6f6..5494db94 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ It's written in C# running on .Net Core that is full cross-platform framework, t * Support multiple LLM platforms (ChatGPT 3.5 / 4.0, PaLM 2, LLaMA 2, HuggingFace). * Allow multiple agents with different responsibilities cooperate to complete complex tasks. * Build, test, evaluate and audit your LLM agent in one place. -* Support different open source UI [Chatbot UI](src/Plugins/BotSharp.Plugin.ChatbotUI/Chatbot-UI.md), [HuggingChat UI](src/Plugins/BotSharp.Plugin.HuggingFace/HuggingChat-UI.md). +* Build-in Web Live Chat UI written in SvelteKit. * Abstract standard Rich Content data structure. Integrate with popular message channels like Facebook Messenger, Slack and Telegram. * Provide RESTful Open API and WebSocket real-time communication. @@ -38,7 +38,19 @@ It's written in C# running on .Net Core that is full cross-platform framework, t PS D:\> cd BotSharp PS D:\BotSharp\> dotnet run -p .\src\WebStarter ``` -2. Run UI project, reference to [Chatbot UI](src/Plugins/BotSharp.Plugin.ChatbotUI/Chatbot-UI.md). + +2. Run UI project, reference to [Web Live Chat](src/web-live-chat/README.md). +```sh +PS D:\> cd .\src\web-live-chat +PS D:\> npm install --force +PS D:\> npm run dev +``` + +Access http://localhost:5010/chat/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a + +![Alt text](./docs/static/screenshots/web-live-chat.png) + + ### Core Modules diff --git a/docs/static/screenshots/web-live-chat.png b/docs/static/screenshots/web-live-chat.png new file mode 100644 index 00000000..7a56b368 Binary files /dev/null and b/docs/static/screenshots/web-live-chat.png differ diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs index 87fdfd2c..3e84de6c 100644 --- a/src/WebStarter/Program.cs +++ b/src/WebStarter/Program.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Users; using BotSharp.Core; using BotSharp.Core.Users.Services; +using BotSharp.Plugin.ChatHub; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; @@ -50,14 +51,14 @@ builder.Services.AddBotSharp(builder.Configuration); builder.Services.AddCors(options => { options.AddPolicy("MyCorsPolicy", - builder => - { - builder.AllowAnyOrigin() + builder => builder.WithOrigins("http://localhost:5010") .AllowAnyMethod() - .AllowAnyHeader(); - }); + .AllowAnyHeader() + .AllowCredentials()); }); +builder.Services.AddSignalR(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -79,4 +80,6 @@ app.UseBotSharp(); app.UseCors("MyCorsPolicy"); #endif +app.MapHub("/chatHub"); + app.Run(); diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 7b4845f2..1309cde1 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -146,7 +146,7 @@ "BotSharp.Plugin.KnowledgeBase", "BotSharp.Plugin.Qdrant", "BotSharp.Plugin.PaddleSharp", - // "BotSharp.Plugin.ChatHub", + "BotSharp.Plugin.ChatHub", "BotSharp.Plugin.WeChat", // "BotSharp.Plugin.TelegramBots", // "BotSharp.Plugin.RoutingSpeeder", diff --git a/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json b/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json new file mode 100644 index 00000000..32960f8c --- /dev/null +++ b/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/agents.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file diff --git a/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/user.json b/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/user.json new file mode 100644 index 00000000..58873daf --- /dev/null +++ b/src/WebStarter/data/users/10d12798-08fb-4aa6-977b-5dd94d82dbfe/user.json @@ -0,0 +1,11 @@ +{ + "firstName": "Guest", + "lastName": "Anonymous", + "email": "guest@gmail.com", + "salt": "55f8fafcf829479ca97e635937440fee", + "password": "3b459ae9988628d41f0362c499a768dd", + "role": "client", + "updatedTime": "2023-11-13T18:00:00Z", + "createdTime": "2023-11-13T18:00:00Z", + "id": "10d12798-08fb-4aa6-977b-5dd94d82dbfe" +} \ No newline at end of file diff --git a/src/web-live-chat/README.md b/src/web-live-chat/README.md index 5c91169b..9db6fded 100644 --- a/src/web-live-chat/README.md +++ b/src/web-live-chat/README.md @@ -1,19 +1,3 @@ -# create-svelte - -Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). - -## Creating a project - -If you're seeing this, you've probably already done this step. Congrats! - -```bash -# create a new project in the current directory -npm create svelte@latest - -# create a new project in my-app -npm create svelte@latest my-app -``` - ## Developing Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: diff --git a/src/web-live-chat/src/lib/services/api-endpoints.js b/src/web-live-chat/src/lib/services/api-endpoints.js index 141b39ad..4948b1bd 100644 --- a/src/web-live-chat/src/lib/services/api-endpoints.js +++ b/src/web-live-chat/src/lib/services/api-endpoints.js @@ -2,6 +2,7 @@ const host = 'http://localhost:5500'; // user export const tokenUrl = `${host}/token`; +export const myInfoUrl = `${host}/user/my`; export const usrCreationUrl = `${host}/user`; // plugin diff --git a/src/web-live-chat/src/lib/services/auth-service.js b/src/web-live-chat/src/lib/services/auth-service.js index a2ee5445..738e5c0e 100644 --- a/src/web-live-chat/src/lib/services/auth-service.js +++ b/src/web-live-chat/src/lib/services/auth-service.js @@ -1,5 +1,5 @@ import { userStore, getUserStore } from '$lib/helpers/store.js'; -import { tokenUrl, usrCreationUrl } from './api-endpoints.js'; +import { tokenUrl, myInfoUrl, usrCreationUrl } from './api-endpoints.js'; /** * This callback type is called `requestCallback` and is displayed as a global symbol. @@ -36,6 +36,34 @@ export async function getToken(email, password, onSucceed) { .catch(error => alert(error.message)); } +/** + * @param {string} token + * @returns {Promise} + */ +export async function myInfo(token) { + const headers = { + Authorization: `Bearer ${token}`, + }; + + const info = await fetch(myInfoUrl, { + method: 'GET', + headers: headers, + }).then(response => { + if (response.ok) { + return response.json(); + } else { + alert(response.statusText); + } + }).then(result => { + let user = getUserStore(); + userStore.set({ ...user, init: false, id: result.id }); + return result; + }) + .catch(error => alert(error.message)); + + return info; +} + /** * @param {string} firstName * @param {string} lastName diff --git a/src/web-live-chat/src/routes/chat/[agentId]/+page.svelte b/src/web-live-chat/src/routes/chat/[agentId]/+page.svelte index 402e61ef..caab5640 100644 --- a/src/web-live-chat/src/routes/chat/[agentId]/+page.svelte +++ b/src/web-live-chat/src/routes/chat/[agentId]/+page.svelte @@ -22,7 +22,7 @@ userToken = token; }); } else { - userToken = $page.url.searchParams.get('token'); + userToken = $page.url.searchParams.get('token') ?? "unauthorized"; } setAuthorization(userToken); conversation = await newConversation(params.agentId); diff --git a/src/web-live-chat/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte b/src/web-live-chat/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte index 7d34282e..640e454b 100644 --- a/src/web-live-chat/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte +++ b/src/web-live-chat/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte @@ -13,6 +13,7 @@ import { page } from '$app/stores'; import { onMount } from 'svelte'; import Link from 'svelte-link'; + import { myInfo } from '$lib/services/auth-service.js'; import { signalr } from '$lib/services/signalr-service.js'; import { sendMessageToHub, GetDialogs } from '$lib/services/conversation-service.js'; import { setAuthorization } from '$lib/helpers/http'; @@ -31,7 +32,10 @@ const params = $page.params; let text = "Hi"; - + + /** @type {import('$typedefs').UserModel} */ + let currentUser; + // @ts-ignore let scrollbar; @@ -39,8 +43,11 @@ let dialogs = []; onMount(async () => { - const token = $page.url.searchParams.get('token'); + const token = $page.url.searchParams.get('token') ?? "unauthorized"; setAuthorization(token); + + currentUser = await myInfo(token); + dialogs = await GetDialogs(params.conversationId); signalr.onMessageReceivedFromClient = onMessageReceivedFromClient; signalr.onMessageReceivedFromCsr = onMessageReceivedFromCsr; @@ -86,11 +93,6 @@ viewport.scrollTo({ top: viewport.scrollHeight, behavior: 'smooth' }); // set scroll offset }, 200); } - - const currentUser = { - name: 'Annie Holder', - isActive: true - };
@@ -99,7 +101,7 @@
-
Steven Franklin
+
Guest

Active now

@@ -174,7 +176,7 @@ {#each dialogs as message}
  • + class={message.sender.id === currentUser.id ? 'right' : ''}>