yt-chat-components 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.idea/langflow-embedded-chat.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/sonarlint/issuestore/0/f/0f8c0c92cf798431ebb931ff6e997b1af86ecee5 +0 -0
  4. package/.idea/sonarlint/issuestore/3/9/39129446b425a1d640160c068e4194e96639eedf +0 -0
  5. package/.idea/sonarlint/issuestore/4/a/4a2f33951ce07c1ff7184f91877aa13db05d3785 +0 -0
  6. package/.idea/sonarlint/issuestore/4/a/4a7b99bdbee5792679d347b6474463bf5e14b66d +0 -0
  7. package/.idea/sonarlint/issuestore/4/b/4b6989b8ccae808ebc45d02230d336ea53800365 +0 -0
  8. package/.idea/sonarlint/issuestore/6/c/6c024c1d0ad64656b9d4b0695ec3c49c0454addf +0 -0
  9. package/.idea/sonarlint/issuestore/8/d/8d6123af13a140f93e06299fff7ea23c547e9ec8 +0 -0
  10. package/.idea/sonarlint/issuestore/8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d +0 -0
  11. package/.idea/sonarlint/issuestore/d/9/d938938695d447dadda115e28781c6541f53fc4f +0 -0
  12. package/.idea/sonarlint/issuestore/index.pb +19 -0
  13. package/.idea/vcs.xml +6 -0
  14. package/README.md +274 -0
  15. package/build/asset-manifest.json +16 -0
  16. package/build/index.html +1 -0
  17. package/build/static/css/main.6f7c593d.css +2 -0
  18. package/build/static/css/main.6f7c593d.css.map +1 -0
  19. package/build/static/js/bundle.min.js +2 -0
  20. package/build/static/js/bundle.min.js.LICENSE.txt +124 -0
  21. package/build/static/js/main.cb252095.js +3 -0
  22. package/build/static/js/main.cb252095.js.LICENSE.txt +134 -0
  23. package/build/static/js/main.cb252095.js.map +1 -0
  24. package/build/static/media/aiavatar.74bafa995cce4c01b804.png +0 -0
  25. package/build/static/media/history-list-empty.1eb65b1550aef4e8c8a4.png +0 -0
  26. package/build/static/media/moreBg.9fc998472925cecd89f2.png +0 -0
  27. package/package.json +75 -0
  28. package/public/index.html +47 -0
  29. package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.module.css +86 -0
  30. package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.tsx +211 -0
  31. package/src/YtChatView/chatWidget/chatWindow/chatPlaceholder/index.module.css +9 -0
  32. package/src/YtChatView/chatWidget/chatWindow/chatPlaceholder/index.tsx +23 -0
  33. package/src/YtChatView/chatWidget/chatWindow/controllers/index.ts +236 -0
  34. package/src/YtChatView/chatWidget/chatWindow/index.module.css +197 -0
  35. package/src/YtChatView/chatWidget/chatWindow/index.tsx +791 -0
  36. package/src/YtChatView/chatWidget/chatWindow/types/chatWidget/index.ts +37 -0
  37. package/src/YtChatView/chatWidget/chatWindow/utils.ts +75 -0
  38. package/src/YtChatView/chatWidget/index.tsx +2289 -0
  39. package/src/YtChatView/logoBtn/index.css +4 -0
  40. package/src/YtChatView/logoBtn/index.jsx +65 -0
  41. package/src/YtChatView/logoSplitBtn/index.css +4 -0
  42. package/src/YtChatView/logoSplitBtn/index.jsx +67 -0
  43. package/src/YtChatView/previewDialog/index.jsx +431 -0
  44. package/src/YtChatView/previewDialog/index.module.css +144 -0
  45. package/src/assets/aicenter/add.png +0 -0
  46. package/src/assets/aicenter/aiavatar.png +0 -0
  47. package/src/assets/aicenter/aicenterbg.png +0 -0
  48. package/src/assets/aicenter/aicenterbgdark.png +0 -0
  49. package/src/assets/aicenter/close.png +0 -0
  50. package/src/assets/aicenter/closex.png +0 -0
  51. package/src/assets/aicenter/copy.png +0 -0
  52. package/src/assets/aicenter/file.png +0 -0
  53. package/src/assets/aicenter/fileupload.png +0 -0
  54. package/src/assets/aicenter/history-list-empty.png +0 -0
  55. package/src/assets/aicenter/history.png +0 -0
  56. package/src/assets/aicenter/luyin.png +0 -0
  57. package/src/assets/aicenter/moreAi.png +0 -0
  58. package/src/assets/aicenter/moreBg.png +0 -0
  59. package/src/assets/aicenter/play-run.gif +0 -0
  60. package/src/assets/aicenter/play.png +0 -0
  61. package/src/assets/aicenter/send-img.png +0 -0
  62. package/src/assets/aicenter/send-question-black.png +0 -0
  63. package/src/assets/aicenter/send-question.png +0 -0
  64. package/src/assets/aicenter/sendmessage.png +0 -0
  65. package/src/assets/aicenter/sound-wave.gif +0 -0
  66. package/src/assets/aicenter/toLeft.png +0 -0
  67. package/src/assets/aicenter/toRight.png +0 -0
  68. package/src/assets/aicenter/type-excel.png +0 -0
  69. package/src/assets/aicenter/type-markdown.png +0 -0
  70. package/src/assets/aicenter/type-mobi.png +0 -0
  71. package/src/assets/aicenter/type-pdf.png +0 -0
  72. package/src/assets/aicenter/type-rpub.png +0 -0
  73. package/src/assets/aicenter/type-text.png +0 -0
  74. package/src/assets/aicenter/type-word.png +0 -0
  75. package/src/assets/aicenter/upfile.png +0 -0
  76. package/src/chatPlaceholder/index.tsx +18 -0
  77. package/src/chatWidget/chatTrigger/index.tsx +15 -0
  78. package/src/chatWidget/chatWindow/chatMessage/index.tsx +42 -0
  79. package/src/chatWidget/chatWindow/index.tsx +426 -0
  80. package/src/chatWidget/index.tsx +2195 -0
  81. package/src/chatWidget/utils.ts +76 -0
  82. package/src/controllers/index.ts +205 -0
  83. package/src/index.tsx +60 -0
  84. package/src/react-app-env.d.ts +1 -0
  85. package/src/reportWebVitals.ts +15 -0
  86. package/src/setupTests.ts +5 -0
  87. package/src/types/chatWidget/index.ts +13 -0
  88. package/tsconfig.json +26 -0
  89. package/webpack.config.js +51 -0
@@ -0,0 +1,76 @@
1
+ export function getChatPosition(
2
+ triggerPosition: DOMRect,
3
+ Cwidth:number,
4
+ Cheight:number,
5
+ position?: string,
6
+ ): { top: string; left: string;
7
+ position?: string, } {
8
+ if (!triggerPosition) {
9
+ return { top: "0px", left: "0px" }; // Return empty string if trigger position is not available
10
+ }
11
+
12
+ const { top, left, width, height } = triggerPosition;
13
+
14
+ const distance = 5; // Adjust this value to set the desired distance from the trigger
15
+ if(!position) return { top: distance + height+ "px", left: width + "px" };
16
+
17
+ switch (position) {
18
+ case "top-left":
19
+ return { top: - distance - Cheight + "px", left: -Cwidth + "px" };
20
+ case "top-center":
21
+ return { top: - distance - Cheight + "px", left: width/2-Cwidth / 2 + "px" };
22
+ case "top-right":
23
+ return { top: - distance - Cheight + "px", left: width+ "px" };
24
+ case "center-left":
25
+ return { top: width/2-Cheight/2 + "px", left: -Cwidth - distance + "px" };
26
+ case "center-right":
27
+ return {
28
+ top: width/2-Cheight/2 + "px",
29
+ left: width + distance + "px",
30
+ };
31
+ case "bottom-right":
32
+ return { top: distance + height+ "px", left: width + "px" };
33
+ case "bottom-center":
34
+ return {
35
+ top: distance + height+ "px",
36
+ left: width/2-Cwidth / 2 + "px",
37
+ };
38
+ case "bottom-left":
39
+ return { top: distance + height+ "px", left: -Cwidth + "px"};
40
+ default:
41
+ return { top: distance + height+ "px", left: width + "px" };
42
+ }
43
+ }
44
+
45
+ export function getAnimationOrigin(position?:string) {
46
+ if(!position) return "origin-top-left";
47
+ switch (position) {
48
+ case "top-left":
49
+ return 'origin-bottom-right'
50
+ case "top-center":
51
+ return "origin-bottom";
52
+ case "top-right":
53
+ return "origin-bottom-left";
54
+ case "center-left":
55
+ return "origin-center";
56
+ case "center-right":
57
+ return "origin-center";
58
+ case "bottom-right":
59
+ return "origin-top-left";
60
+ case "bottom-center":
61
+ return "origin-top";
62
+ case "bottom-left":
63
+ return "origin-top-right"
64
+ default:
65
+ return "origin-top-left"
66
+ }
67
+ }
68
+
69
+ export function extractMessageFromOutput(output:{type:string, message:any}){
70
+ console.log(output)
71
+ const {type, message} = output;
72
+ if(type === "text") return message;
73
+ if (type ==="message") return message.text;
74
+ if(type==="object") return message.text;
75
+ return "Unknown message structure"
76
+ }
@@ -0,0 +1,205 @@
1
+ // @ts-nocheck
2
+ import axios from "axios";
3
+
4
+ export async function sendMessage(baseUrl: string, flowId: string, message: string,input_type:string,output_type:string,sessionId:React.MutableRefObject<string>,output_component?:string, tweaks?: Object,api_key?:string,additional_headers?:{[key:string]:string}) {
5
+ let data:any;
6
+ data = {input_type,input_value:message,output_type}
7
+ if (tweaks) {
8
+ data["tweaks"]= tweaks
9
+ }
10
+ if(output_component){
11
+ data["output_component"]=output_component;
12
+ }
13
+ let headers:{[key:string]:string}= {"Content-Type": "application/json"}
14
+ if( api_key){
15
+ headers["x-api-key"]=api_key;
16
+ }
17
+ if (additional_headers){
18
+ headers = Object.assign(headers, additional_headers);
19
+ // headers = {...headers, ...additional_headers};
20
+ }
21
+ if(sessionId.current && sessionId.current!=""){
22
+ data.session_id=sessionId.current;
23
+ }
24
+ data.embed_app_extend = {
25
+ http_extend:{
26
+ bd:{code:"2301431205"},
27
+ // header:{appId:"a", metaId:"b", menuId:"c"},
28
+ // params:{},
29
+ body:{code:"2301431205"}
30
+ },
31
+ operator_id:"operator_id_123",
32
+ // /upload_file_path_list :["7bfb7cae-e434-42cc-9b33-9ec482665963\\2025-02-13_16-36-26_wallhaven-0qdq1q_2560x1600.png"]
33
+ }
34
+ let response = axios.post(`${baseUrl}/api/v1/run/${flowId}`, data,{headers});
35
+ return response;
36
+ }
37
+
38
+ export async function sendMessageStream(
39
+ embed_app_extend: object,
40
+ isStream: boolean,
41
+ handleMessageContent: Function,
42
+ signal,
43
+ baseUrl: string,
44
+ flowId: string,
45
+ message: string,
46
+ input_type: string,
47
+ output_type: string,
48
+ sessionId: React.MutableRefObject<string>,
49
+ output_component?: string,
50
+ tweaks?: Object,
51
+ api_key?: string,
52
+ additional_headers?: {
53
+ [key: string]: string;
54
+ },
55
+ ) {
56
+ let data: any;
57
+ data = {input_type, input_value: message, output_type};
58
+ if (tweaks) {
59
+ data['tweaks'] = tweaks;
60
+ }
61
+ if (output_component) {
62
+ data['output_component'] = output_component;
63
+ }
64
+ if (embed_app_extend) {
65
+ data['embed_app_extend'] = embed_app_extend;
66
+ }
67
+ let headers: { [key: string]: string } = {'Content-Type': 'application/json'};
68
+ if (api_key) {
69
+ headers['x-api-key'] = api_key;
70
+ }
71
+ if (additional_headers) {
72
+ headers = Object.assign(headers, additional_headers);
73
+ // headers = {...headers, ...additional_headers};
74
+ }
75
+ // @ts-ignore
76
+ if (sessionId && sessionId != '') {
77
+ data.session_id = sessionId;
78
+ }
79
+
80
+ if (isStream) {
81
+ return await fetchCustomStream(
82
+ `${baseUrl}/api/v1/run/${flowId}?stream=true`,
83
+ data,
84
+ headers,
85
+ handleMessageContent,
86
+ signal,
87
+ );
88
+ } else {
89
+ let response = axios.post(`${baseUrl}/api/v1/run/${flowId}`, data,{headers});
90
+ return response;
91
+ // const response = await fetch(`${baseUrl}/api/v1/run/${flowId}`, {
92
+ // method: 'POST',
93
+ // headers: headers,
94
+ // body: JSON.stringify(data),
95
+ // });
96
+ // const data = await response.json(); // 处理响应数据
97
+ // return {data, status: response.status};
98
+
99
+ }
100
+ }
101
+
102
+ // 缓冲区用于累积未完成的 JSON 数据
103
+ let buffer = '';
104
+
105
+ async function fetchCustomStream(url, body, headers, handleMessageContent, signal) {
106
+ const response = await fetch(url, {
107
+ method: 'POST',
108
+ headers: headers,
109
+ body: JSON.stringify(body),
110
+ signal: signal,
111
+ });
112
+
113
+ if (!response.ok) {
114
+ throw new Error('请求失败');
115
+ }
116
+
117
+ // 手动读取响应体作为可读流
118
+ const reader = response.body.getReader();
119
+ const decoder = new TextDecoder();
120
+
121
+ while (true) {
122
+ const {done, value} = await reader.read();
123
+ if (done) break;
124
+
125
+ // 将二进制数据解码为字符串,并累积到缓冲区
126
+ const chunk = decoder.decode(value, {stream: true});
127
+ buffer += chunk;
128
+
129
+ // 提取并解析 JSON
130
+ const {parsedData, remainingBuffer} = extractAndParseJSON(buffer, handleMessageContent);
131
+
132
+ console.log("----------------------- 1")
133
+ console.log(buffer)
134
+ console.log(parsedData)
135
+ console.log(remainingBuffer)
136
+ console.log("----------------------- 2")
137
+
138
+ // 更新缓冲区为剩余未处理的数据
139
+ buffer = remainingBuffer;
140
+ }
141
+
142
+ // 如果缓冲区中还有剩余数据,可能是不完整的 JSON
143
+ if (buffer.trim() !== '') {
144
+ console.warn('缓冲区中存在未完成的 JSON 数据:', buffer);
145
+ }
146
+ }
147
+
148
+ // 辅助函数:从缓冲区中提取并解析所有完整的 JSON 对象
149
+ function extractAndParseJSON(buffer, handleMessageContent) {
150
+ let remainingBuffer = buffer; // 剩余未处理的数据
151
+ const parsedData = []; // 存储解析成功的 JSON 对象
152
+ let bracketCount = 0; // 记录大括号的嵌套层次
153
+ let jsonStartIndex = -1; // 当前 JSON 对象的起始索引
154
+ let inString = false; // 是否处于字符串内部
155
+ let escapeChar = false; // 是否遇到转义字符
156
+
157
+ for (let i = 0; i < remainingBuffer.length; i++) {
158
+ const char = remainingBuffer[i];
159
+
160
+ if (escapeChar) {
161
+ escapeChar = false; // 跳过转义字符后的下一个字符
162
+ continue;
163
+ }
164
+
165
+ if (char === '\\') {
166
+ escapeChar = true; // 标记转义字符
167
+ continue;
168
+ }
169
+
170
+ if (char === '"' && !escapeChar) {
171
+ inString = !inString; // 切换字符串状态
172
+ continue;
173
+ }
174
+
175
+ if (!inString) {
176
+ if (char === '{') {
177
+ if (bracketCount === 0) {
178
+ jsonStartIndex = i; // 标记 JSON 开始位置
179
+ }
180
+ bracketCount++;
181
+ } else if (char === '}') {
182
+ bracketCount--;
183
+ if (bracketCount === 0 && jsonStartIndex !== -1) {
184
+ // 找到一个完整的 JSON 对象
185
+ const jsonString = remainingBuffer.slice(jsonStartIndex, i + 1);
186
+
187
+ try {
188
+ const parsedJson = JSON.parse(jsonString); // 解析 JSON
189
+ handleMessageContent(parsedJson['event'], parsedJson['data']);
190
+ parsedData.push(parsedJson); // 添加到解析结果中
191
+ } catch (error) {
192
+ console.warn('无法解析 JSON 数据:', error);
193
+ }
194
+
195
+ // 更新剩余缓冲区的起始位置
196
+ remainingBuffer = remainingBuffer.slice(i + 1);
197
+ i = -1; // 重置索引以重新开始扫描
198
+ jsonStartIndex = -1; // 重置 JSON 起始索引
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ return {parsedData, remainingBuffer}; // 返回解析结果和剩余缓冲区
205
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import r2wc from '@r2wc/react-to-web-component';
4
+ import LogoBtn from './YtChatView/logoBtn/index';
5
+ import ToolDialog from "./YtChatView/previewDialog/index";
6
+ import LogoSplitBtn from "./YtChatView/logoSplitBtn/index";
7
+
8
+ // 手动注入 React 和 ReactDOM 到全局
9
+ window.React = React;
10
+ window.ReactDOM = ReactDOM;
11
+
12
+ customElements.define('yt-chat', r2wc(LogoBtn, {
13
+ shadow: "closed",
14
+ props: {
15
+ left: "number",
16
+ right: "number",
17
+ top: "number",
18
+ bottom: "number",
19
+ width: "number",
20
+ height: "number",
21
+ iconUrl: "string",
22
+ title: "string",
23
+ flowId: "string",
24
+ hostUrl: "string",
25
+ userInfo: "json",
26
+ tags: "json"
27
+ },
28
+ }));
29
+
30
+ customElements.define('yt-page-chat', r2wc(ToolDialog, {
31
+ shadow: "closed",
32
+ props: {
33
+ title: "string",
34
+ flowId: "string",
35
+ hostUrl: "string",
36
+ setDialogVisible: "function",
37
+ userInfo: "json",
38
+ tags: "json",
39
+ boxStyle: "json"
40
+ },
41
+ }));
42
+
43
+ customElements.define('yt-split-modal-chat', r2wc(LogoSplitBtn, {
44
+ shadow: "closed",
45
+ props: {
46
+ left: "number",
47
+ right: "number",
48
+ top: "number",
49
+ bottom: "number",
50
+ width: "number",
51
+ height: "number",
52
+ iconUrl: "string",
53
+ title: "string",
54
+ flowId: "string",
55
+ hostUrl: "string",
56
+ userInfo: "json",
57
+ tags: "json",
58
+ sceneId: "string"
59
+ },
60
+ }));
@@ -0,0 +1 @@
1
+ /// <reference types="react-scripts" />
@@ -0,0 +1,15 @@
1
+ import { ReportHandler } from 'web-vitals';
2
+
3
+ const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4
+ if (onPerfEntry && onPerfEntry instanceof Function) {
5
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6
+ getCLS(onPerfEntry);
7
+ getFID(onPerfEntry);
8
+ getFCP(onPerfEntry);
9
+ getLCP(onPerfEntry);
10
+ getTTFB(onPerfEntry);
11
+ });
12
+ }
13
+ };
14
+
15
+ export default reportWebVitals;
@@ -0,0 +1,5 @@
1
+ // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
+ // allows you to do things like:
3
+ // expect(element).toHaveTextContent(/react/i)
4
+ // learn more: https://github.com/testing-library/jest-dom
5
+ import '@testing-library/jest-dom';
@@ -0,0 +1,13 @@
1
+ export type ChatMessageType = {
2
+ message: string;
3
+ isSend: boolean;
4
+ error?: boolean;
5
+ bot_message_style?: React.CSSProperties;
6
+ user_message_style?: React.CSSProperties;
7
+ error_message_style?: React.CSSProperties;
8
+ };
9
+
10
+
11
+ export type ChatMessagePlaceholderType = {
12
+ bot_message_style?: React.CSSProperties;
13
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es5",
4
+ "lib": [
5
+ "dom",
6
+ "dom.iterable",
7
+ "esnext"
8
+ ],
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "esModuleInterop": true,
12
+ "allowSyntheticDefaultImports": true,
13
+ "strict": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "module": "esnext",
17
+ "moduleResolution": "node",
18
+ "resolveJsonModule": true,
19
+ "isolatedModules": true,
20
+ "noEmit": true,
21
+ "jsx": "react-jsx"
22
+ },
23
+ "include": [
24
+ "src"
25
+ ]
26
+ }
@@ -0,0 +1,51 @@
1
+ const path = require("path");
2
+
3
+ module.exports = {
4
+ mode: "production",
5
+ entry: "./src/index.tsx",
6
+ output: {
7
+ filename: "bundle.min.js",
8
+ path: path.resolve(__dirname, "build/static/js"),
9
+ libraryTarget: "umd",
10
+ globalObject: "this",
11
+ library: "YtChatComponents", // 可选,定义全局命名空间
12
+ },
13
+ module: {
14
+ rules: [
15
+ {
16
+ test: /\.(jsx|js|tsx|ts)$/,
17
+ exclude: /node_modules/,
18
+ use: {
19
+ loader: "babel-loader",
20
+ options: {
21
+ presets: [
22
+ "@babel/preset-env",
23
+ "@babel/preset-react",
24
+ "@babel/preset-typescript",
25
+ ],
26
+ },
27
+ },
28
+ },
29
+ {
30
+ test: /\.css$/,
31
+ use: ["style-loader", "css-loader"],
32
+ },
33
+ {
34
+ test: /\.(png|jpg|jpeg|gif|svg)$/,
35
+ use: {
36
+ loader: "url-loader",
37
+ options: {
38
+ limit: 1000000,
39
+ },
40
+ },
41
+ },
42
+ ],
43
+ },
44
+ resolve: {
45
+ extensions: [".jsx", ".js", ".tsx", ".ts"],
46
+ },
47
+ optimization: {
48
+ minimize: true,
49
+ usedExports: false, // 禁用 tree-shaking,避免移除 React
50
+ },
51
+ };