@syfei49/mini-dynamic-renderer 1.0.7 → 1.2.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.
package/index.js CHANGED
@@ -1,16 +1,16 @@
1
- var initModule = require('./src/init');
2
- var interceptor = require('./src/interceptor');
3
- var handler = require('./src/handler');
4
- var chatService = require('./src/chat/service');
5
- var configModule = require('./src/config');
6
-
7
- module.exports = {
8
- version: '1.0.7',
9
- init: initModule.init,
10
- getConfig: configModule.getConfig,
11
- isInitialized: initModule.isInitialized,
12
- uninstall: interceptor.uninstallInterceptor,
13
- parseRenderConfig: handler.parseRenderConfig,
14
- openChat: chatService.openConversation,
15
- closeChat: chatService.closeConversation
16
- };
1
+ var initModule = require('./src/init');
2
+ var interceptor = require('./src/interceptor');
3
+ var handler = require('./src/handler');
4
+ var chatService = require('./src/chat/service');
5
+ var configModule = require('./src/config');
6
+
7
+ module.exports = {
8
+ version: '1.1.1',
9
+ init: initModule.init,
10
+ getConfig: configModule.getConfig,
11
+ isInitialized: initModule.isInitialized,
12
+ uninstall: interceptor.uninstallInterceptor,
13
+ parseRenderConfig: handler.parseRenderConfig,
14
+ openChat: chatService.openConversation,
15
+ closeChat: chatService.closeConversation
16
+ };
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
- {
2
- "name": "@syfei49/mini-dynamic-renderer",
3
- "version": "1.0.7",
4
- "description": "uni-app 浮层 AI 客服插件",
5
- "main": "index.js",
6
- "files": [
7
- "index.js",
8
- "src/**/*.js",
9
- "components/**/*.vue",
10
- "README.md"
11
- ],
12
- "scripts": {
13
- "test": "echo \"Error: no test specified\" && exit 1"
14
- },
15
- "keywords": [
16
- "uni-app",
17
- "mini-program",
18
- "ai",
19
- "chat",
20
- "float"
21
- ],
22
- "author": "syfei49",
23
- "license": "MIT",
24
- "publishConfig": {
25
- "access": "public"
26
- }
27
- }
1
+ {
2
+ "name": "@syfei49/mini-dynamic-renderer",
3
+ "version": "1.2.0",
4
+ "description": "uni-app 浮层 AI 客服插件",
5
+ "main": "index.js",
6
+ "files": [
7
+ "index.js",
8
+ "src/**/*.js",
9
+ "components/**/*.vue",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": [
16
+ "uni-app",
17
+ "mini-program",
18
+ "ai",
19
+ "chat",
20
+ "float"
21
+ ],
22
+ "author": "syfei49",
23
+ "license": "MIT",
24
+ "publishConfig": {
25
+ "access": "public"
26
+ }
27
+ }
@@ -1,106 +1,148 @@
1
- var configModule = require('../config');
2
-
3
- function getFullUrl(path) {
4
- var config = configModule.getConfig();
5
- var baseUrl = config.baseUrl || '';
6
- var normalizedPath = (path || '').replace(/^\/+/, '/');
7
- if (baseUrl.slice(-1) === '/' && normalizedPath.indexOf('/') === 0) {
8
- return baseUrl + normalizedPath.slice(1);
9
- }
10
- if (baseUrl && normalizedPath.indexOf('/') !== 0) {
11
- normalizedPath = '/' + normalizedPath;
12
- }
13
- return baseUrl + normalizedPath;
14
- }
15
-
16
- function getHeaders(extraHeaders) {
17
- var config = configModule.getConfig();
18
- var headers = Object.assign({}, config.getHeaders() || {});
19
- var token = typeof config.getToken === 'function' ? config.getToken() : '';
20
- if (token) {
21
- headers.Authorization = token;
22
- }
23
- if (extraHeaders) {
24
- Object.assign(headers, extraHeaders);
25
- }
26
- return headers;
27
- }
28
-
29
- function sendChat(payload) {
30
- var config = configModule.getConfig();
31
- var url = getFullUrl(config.chatApiPath);
32
- var headers = getHeaders({
33
- 'Content-Type': 'application/json'
34
- });
35
-
36
- if (config.debug) {
37
- console.log('[mini-dynamic-renderer] sendChat', url, payload);
38
- }
39
-
40
- return new Promise(function (resolve, reject) {
41
- uni.request({
42
- url: url,
43
- method: 'POST',
44
- data: payload,
45
- header: headers,
46
- timeout: 120000,
47
- success: function (res) {
48
- var data = res.data || {};
49
- if (res.statusCode >= 200 && res.statusCode < 300 && data.code !== 500) {
50
- resolve(data);
51
- } else {
52
- reject(new Error(data.msg || data.message || ('请求失败 ' + res.statusCode)));
53
- }
54
- },
55
- fail: function (err) {
56
- reject(err || new Error('网络请求失败'));
57
- }
58
- });
59
- });
60
- }
61
-
62
- function uploadImage(filePath) {
63
- var config = configModule.getConfig();
64
- var url = getFullUrl(config.uploadApiPath);
65
- var headers = getHeaders();
66
-
67
- if (config.debug) {
68
- console.log('[mini-dynamic-renderer] uploadImage', url, filePath);
69
- }
70
-
71
- return new Promise(function (resolve, reject) {
72
- uni.uploadFile({
73
- url: url,
74
- filePath: filePath,
75
- name: 'file',
76
- header: headers,
77
- success: function (res) {
78
- var data = res.data || '{}';
79
- try {
80
- data = typeof data === 'string' ? JSON.parse(data) : data;
81
- } catch (e) {
82
- reject(new Error('上传响应解析失败'));
83
- return;
84
- }
85
- var dataObj = data.data || {};
86
- var urlValue = data.url || dataObj.url || dataObj.fileName || dataObj || '';
87
- if (urlValue && typeof urlValue === 'object' && urlValue.url) {
88
- urlValue = urlValue.url;
89
- }
90
- if (urlValue) {
91
- resolve(urlValue);
92
- } else {
93
- reject(new Error(data.msg || data.message || '上传失败'));
94
- }
95
- },
96
- fail: function (err) {
97
- reject(err || new Error('图片上传失败'));
98
- }
99
- });
100
- });
101
- }
102
-
103
- module.exports = {
104
- sendChat: sendChat,
105
- uploadImage: uploadImage
106
- };
1
+ var configModule = require('../config');
2
+
3
+ function getFullUrl(path, useUploadBase) {
4
+ var config = configModule.getConfig();
5
+ var baseUrl = (useUploadBase && config.uploadBaseUrl) ? config.uploadBaseUrl : config.baseUrl;
6
+ baseUrl = baseUrl || '';
7
+ var normalizedPath = (path || '').replace(/^\/+/, '/');
8
+ if (baseUrl.slice(-1) === '/' && normalizedPath.indexOf('/') === 0) {
9
+ return baseUrl + normalizedPath.slice(1);
10
+ }
11
+ if (baseUrl && normalizedPath.indexOf('/') !== 0) {
12
+ normalizedPath = '/' + normalizedPath;
13
+ }
14
+ return baseUrl + normalizedPath;
15
+ }
16
+
17
+ function getHeaders(extraHeaders) {
18
+ var config = configModule.getConfig();
19
+ var headers = Object.assign({}, config.getHeaders() || {});
20
+ var token = typeof config.getToken === 'function' ? config.getToken() : '';
21
+ if (token) {
22
+ headers.Authorization = token;
23
+ }
24
+ if (config.appId) {
25
+ headers['X-App-Id'] = config.appId;
26
+ }
27
+ if (extraHeaders) {
28
+ Object.assign(headers, extraHeaders);
29
+ }
30
+ return headers;
31
+ }
32
+
33
+ function sendChat(payload) {
34
+ var config = configModule.getConfig();
35
+ var url = getFullUrl(config.chatApiPath);
36
+ var headers = getHeaders({
37
+ 'Content-Type': 'application/json'
38
+ });
39
+ var data = Object.assign({}, payload || {});
40
+ if (!data.inputs) {
41
+ delete data.inputs;
42
+ }
43
+
44
+ if (config.debug) {
45
+ console.log('[mini-dynamic-renderer] sendChat', url, data);
46
+ }
47
+
48
+ return new Promise(function (resolve, reject) {
49
+ uni.request({
50
+ url: url,
51
+ method: 'POST',
52
+ data: data,
53
+ header: headers,
54
+ timeout: 120000,
55
+ success: function (res) {
56
+ var data = res.data || {};
57
+ if (res.statusCode >= 200 && res.statusCode < 300 && data.code !== 500) {
58
+ resolve(data);
59
+ } else {
60
+ reject(new Error(data.msg || data.message || ('请求失败 ' + res.statusCode)));
61
+ }
62
+ },
63
+ fail: function (err) {
64
+ reject(err || new Error('网络请求失败'));
65
+ }
66
+ });
67
+ });
68
+ }
69
+
70
+ function uploadImage(filePath) {
71
+ var config = configModule.getConfig();
72
+ var url = getFullUrl(config.uploadApiPath, true);
73
+ var headers = getHeaders();
74
+
75
+ if (config.debug) {
76
+ console.log('[mini-dynamic-renderer] uploadImage', url, filePath);
77
+ }
78
+
79
+ return new Promise(function (resolve, reject) {
80
+ uni.uploadFile({
81
+ url: url,
82
+ filePath: filePath,
83
+ name: 'file',
84
+ header: headers,
85
+ success: function (res) {
86
+ var data = res.data || '{}';
87
+ try {
88
+ data = typeof data === 'string' ? JSON.parse(data) : data;
89
+ } catch (e) {
90
+ reject(new Error('上传响应解析失败'));
91
+ return;
92
+ }
93
+ var dataObj = data.data || {};
94
+ var urlValue = data.url || dataObj.url || dataObj.fileName || dataObj || '';
95
+ if (urlValue && typeof urlValue === 'object' && urlValue.url) {
96
+ urlValue = urlValue.url;
97
+ }
98
+ if (urlValue) {
99
+ resolve(urlValue);
100
+ } else {
101
+ reject(new Error(data.msg || data.message || '上传失败'));
102
+ }
103
+ },
104
+ fail: function (err) {
105
+ reject(err || new Error('图片上传失败'));
106
+ }
107
+ });
108
+ });
109
+ }
110
+
111
+ function sendAction(payload) {
112
+ var config = configModule.getConfig();
113
+ var url = getFullUrl(config.actionApiPath || '/openapi/mini/ai/action');
114
+ var headers = getHeaders({
115
+ 'Content-Type': 'application/json'
116
+ });
117
+
118
+ if (config.debug) {
119
+ console.log('[mini-dynamic-renderer] sendAction', url, payload);
120
+ }
121
+
122
+ return new Promise(function (resolve, reject) {
123
+ uni.request({
124
+ url: url,
125
+ method: 'POST',
126
+ data: payload || {},
127
+ header: headers,
128
+ timeout: 120000,
129
+ success: function (res) {
130
+ var data = res.data || {};
131
+ if (res.statusCode >= 200 && res.statusCode < 300 && data.code !== 500) {
132
+ resolve(data);
133
+ } else {
134
+ reject(new Error(data.msg || data.message || ('请求失败 ' + res.statusCode)));
135
+ }
136
+ },
137
+ fail: function (err) {
138
+ reject(err || new Error('网络请求失败'));
139
+ }
140
+ });
141
+ });
142
+ }
143
+
144
+ module.exports = {
145
+ sendChat: sendChat,
146
+ uploadImage: uploadImage,
147
+ sendAction: sendAction
148
+ };
@@ -1,55 +1,152 @@
1
- function cleanImageUrl(url) {
2
- return String(url || '').replace(/[)\]}>.,;,。]+$/g, '');
3
- }
4
-
5
- function parseAssistantMessage(answer) {
6
- if (!answer) {
7
- return {
8
- content: '',
9
- imageUrls: []
10
- };
11
- }
12
- var imageUrls = [];
13
- var iconLineRegex = /[--•]\s*图标[::]\s*(https?:\/\/\S+)/gi;
14
- var match;
15
- while ((match = iconLineRegex.exec(answer)) !== null) {
16
- var url = cleanImageUrl(match[1]);
17
- if (url && imageUrls.indexOf(url) === -1) {
18
- imageUrls.push(url);
19
- }
20
- }
21
- var content = answer;
22
- if (imageUrls.length) {
23
- content = answer.replace(/[--•]\s*图标[::]\s*https?:\/\/\S+/gi, '- 图标:');
24
- }
25
- return {
26
- content: content.trim(),
27
- imageUrls: imageUrls
28
- };
29
- }
30
-
31
- function parseNeedIcon(answer) {
32
- if (!answer || answer.indexOf('[NEED_ICON]') === -1) {
33
- return null;
34
- }
35
- var jsonPart = answer.replace('[NEED_ICON]', '').trim();
36
- try {
37
- var data = JSON.parse(jsonPart);
38
- if (!data || !data.name) {
39
- return null;
40
- }
41
- return {
42
- name: data.name,
43
- sort: Number(data.sort != null ? data.sort : 0),
44
- msg: data.msg || ('请上传一张图片作为「' + data.name + '」的分类图标')
45
- };
46
- } catch (error) {
47
- return null;
48
- }
49
- }
50
-
51
- module.exports = {
52
- cleanImageUrl: cleanImageUrl,
53
- parseAssistantMessage: parseAssistantMessage,
54
- parseNeedIcon: parseNeedIcon
55
- };
1
+ function cleanImageUrl(url) {
2
+ return String(url || '').replace(/[)\]}>.,;,。]+$/g, '');
3
+ }
4
+
5
+ function parseAssistantMessage(answer) {
6
+ if (!answer) {
7
+ return {
8
+ content: '',
9
+ imageUrls: []
10
+ };
11
+ }
12
+ var imageUrls = [];
13
+ var iconLineRegex = /[--•]\s*图标[::]\s*(https?:\/\/\S+)/gi;
14
+ var match;
15
+ while ((match = iconLineRegex.exec(answer)) !== null) {
16
+ var url = cleanImageUrl(match[1]);
17
+ if (url && imageUrls.indexOf(url) === -1) {
18
+ imageUrls.push(url);
19
+ }
20
+ }
21
+ var content = answer;
22
+ if (imageUrls.length) {
23
+ content = answer.replace(/[--•]\s*图标[::]\s*https?:\/\/\S+/gi, '- 图标:');
24
+ }
25
+ return {
26
+ content: content.trim(),
27
+ imageUrls: imageUrls
28
+ };
29
+ }
30
+
31
+ function parseNeedIcon(answer) {
32
+ if (!answer || answer.indexOf('[NEED_ICON]') === -1) {
33
+ return null;
34
+ }
35
+ var jsonPart = answer.replace('[NEED_ICON]', '').trim();
36
+ try {
37
+ var data = JSON.parse(jsonPart);
38
+ if (!data || !data.name) {
39
+ return null;
40
+ }
41
+ return {
42
+ name: data.name,
43
+ sort: Number(data.sort != null ? data.sort : 0),
44
+ msg: data.msg || ('请上传一张图片作为「' + data.name + '」的分类图标')
45
+ };
46
+ } catch (error) {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ function parseRenderConfig(answer) {
52
+ if (!answer || typeof answer !== 'string') {
53
+ return null;
54
+ }
55
+ var renderIdx = answer.indexOf('[RENDER_CONFIG]');
56
+ if (renderIdx !== -1) {
57
+ var jsonPart = answer.substring(renderIdx + '[RENDER_CONFIG]'.length);
58
+ var start = jsonPart.indexOf('{');
59
+ var end = jsonPart.lastIndexOf('}');
60
+ if (start === -1 || end === -1 || end < start) {
61
+ return null;
62
+ }
63
+ try {
64
+ return JSON.parse(jsonPart.substring(start, end + 1));
65
+ } catch (e) {
66
+ return null;
67
+ }
68
+ }
69
+ if (answer.indexOf('[NEED_ICON]') !== -1) {
70
+ return {
71
+ type: 'iconPicker',
72
+ fields: [{ name: 'imageUrl', label: '分类图标', type: 'image' }]
73
+ };
74
+ }
75
+ return null;
76
+ }
77
+
78
+ function parseApiRenderConfig(renderConfig) {
79
+ if (!renderConfig) {
80
+ return null;
81
+ }
82
+ if (typeof renderConfig === 'object') {
83
+ return renderConfig;
84
+ }
85
+ if (typeof renderConfig === 'string') {
86
+ try {
87
+ return JSON.parse(renderConfig);
88
+ } catch (e) {
89
+ return null;
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+
95
+ function extractJsonAfterMarker(answer, marker) {
96
+ if (!answer || typeof answer !== 'string') {
97
+ return null;
98
+ }
99
+ var idx = answer.indexOf(marker);
100
+ if (idx === -1) {
101
+ return null;
102
+ }
103
+ var jsonPart = answer.substring(idx + marker.length);
104
+ var start = jsonPart.indexOf('{');
105
+ if (start === -1) {
106
+ return null;
107
+ }
108
+ var depth = 0;
109
+ for (var i = start; i < jsonPart.length; i++) {
110
+ var ch = jsonPart.charAt(i);
111
+ if (ch === '{') {
112
+ depth++;
113
+ } else if (ch === '}') {
114
+ depth--;
115
+ if (depth === 0) {
116
+ return {
117
+ json: jsonPart.substring(start, i + 1),
118
+ end: idx + marker.length + i + 1
119
+ };
120
+ }
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+
126
+ function stripMarkerBlock(answer, marker) {
127
+ var extracted = extractJsonAfterMarker(answer, marker);
128
+ if (!extracted) {
129
+ return answer;
130
+ }
131
+ return (answer.substring(0, answer.indexOf(marker)) + answer.substring(extracted.end)).trim();
132
+ }
133
+
134
+ function stripMarkers(answer) {
135
+ if (!answer || typeof answer !== 'string') {
136
+ return '';
137
+ }
138
+ var result = answer;
139
+ result = stripMarkerBlock(result, '[RENDER_CONFIG]');
140
+ result = stripMarkerBlock(result, '[AI_ACTION]');
141
+ result = stripMarkerBlock(result, '[NEED_ICON]');
142
+ return result.trim();
143
+ }
144
+
145
+ module.exports = {
146
+ cleanImageUrl: cleanImageUrl,
147
+ parseAssistantMessage: parseAssistantMessage,
148
+ parseNeedIcon: parseNeedIcon,
149
+ parseRenderConfig: parseRenderConfig,
150
+ parseApiRenderConfig: parseApiRenderConfig,
151
+ stripMarkers: stripMarkers
152
+ };