Skip to content

Commit 953d8f6

Browse files
committed
Add developing_bot.md
1 parent d92fdf8 commit 953d8f6

File tree

1 file changed

+310
-0
lines changed

1 file changed

+310
-0
lines changed

doc/developing_bot.md

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# Developing Bots for ChatALL
2+
3+
## Quick Start
4+
- [Basic bot setup](https://github.com/ai-shifu/ChatALL/blob/main/CONTRIBUTION.md#adding-a-new-ai-bot)
5+
6+
## Advanced Topics
7+
8+
### UI order configuration
9+
10+
In the `src/bots/index.js` file, you can find the `all` array like
11+
12+
```javascript
13+
// Add to the main bot list
14+
const all = [
15+
ChatGPT35Bot.getInstance(),
16+
ChatGPT4Bot.getInstance(),
17+
OpenAIAPI35Bot.getInstance(),
18+
OpenAIAPI4Bot.getInstance(),
19+
BingChatCreativeBot.getInstance(),
20+
BingChatBalancedBot.getInstance(),
21+
BingChatPreciseBot.getInstance(),
22+
WenxinQianfanBot.getInstance(),
23+
SparkBot.getInstance(),
24+
MOSSBot.getInstance(),
25+
BardBot.getInstance(),
26+
...existing_bots...
27+
];
28+
```
29+
30+
You can change the order of the bots in this array to control their display order in the UI.
31+
For example, if you want to move the `BardBot` between `MOSSBot` and `WenxinQianfanBot`, you can modify the array like this:
32+
33+
```javascript
34+
const all = [
35+
ChatGPT35Bot.getInstance(),
36+
ChatGPT4Bot.getInstance(),
37+
OpenAIAPI35Bot.getInstance(),
38+
OpenAIAPI4Bot.getInstance(),
39+
BingChatCreativeBot.getInstance(),
40+
BingChatBalancedBot.getInstance(),
41+
BingChatPreciseBot.getInstance(),
42+
MOSSBot.getInstance(),
43+
BardBot.getInstance(), // Moved BardBot here
44+
WenxinQianfanBot.getInstance(),
45+
SparkBot.getInstance(),
46+
...existing_bots...
47+
];
48+
```
49+
50+
### Setting component implementation
51+
52+
To fulfill other core functions, you need login functionality, API key configuration, etc. If your bot does not require login or you don't mind putting the key directly in the code (strongly not recommended), you can skip this section.
53+
54+
#### Create a settings component
55+
56+
57+
In the `src/components/BotSettings/` directory, create a new file named `KnowNothingBotSettings.vue`.
58+
\
59+
You can use existing settings components as templates:
60+
61+
1. If you only need login functionality, just copy `BardBotSettings.vue` and change import Bot from `@/bots/BardBot;` to import Bot from `@/bots/KnowNothingBot;`.
62+
- (Note: Some websites have implemented security measures to prevent ChatALL and similar clients from accessing them. If you encounter such situations, you will need to do a lot of hack work.)
63+
2. If you only need to configure the API key, copy `WenxinQianfanBotSettings.vue` and modify it, but this will require more work.
64+
3. For complex settings with multiple configurations, you will need to do even more work.
65+
66+
#### Add settings field
67+
68+
ChatALL's settings UI is built using [Vuetify 3](https://vuetifyjs.com/).
69+
Refer to the [Vuetify 3 official documentation](https://vuetifyjs.com/en/introduction/why-vuetify/) to see and test the rich components it supports.
70+
\
71+
By referring to the existing code, you can basically get everything workin. No need for further explanation here.
72+
73+
ChatALL's settings are stored in local storage using the [`vuex-persist`](https://github.com/championswimmer/vuex-persist). It's very handy, though the documentation is not readable enough.
74+
Here is a brief introduction on how to use it:
75+
76+
First, in `src/store/index.js`, add the following code:
77+
78+
```JavaScript
79+
export default createStore({
80+
state: {
81+
...
82+
knowNothing: {
83+
setting1: "",
84+
setting2: "",
85+
},
86+
...
87+
},
88+
mutations: {
89+
...
90+
setKnowNothing(state, { setting1, setting2 }) {
91+
state.knowNothing = { setting1, setting2 };
92+
},
93+
...
94+
},
95+
...
96+
});
97+
```
98+
99+
`setting1`, `setting2`, and sub-objects can be added, deleted, or modified as you like. Just make sure the top-level object is `knowNothing`, even if it only has one configuration.
100+
101+
Then, in `KnowNothingBotSettings.vue`, add the following code:
102+
103+
```JavaScript
104+
export default {
105+
...
106+
methods: {
107+
...mapMutations(["setKnowNothing"]),
108+
setSetting1(value){
109+
this.setKnowNothing({
110+
...this.knowNothing,
111+
setting1: value
112+
})
113+
},
114+
setSetting2(value){
115+
this.setKnowNothing({
116+
...this.knowNothing,
117+
setting2: value
118+
})
119+
},
120+
},
121+
computed: {
122+
...mapState(["knowNothing"])
123+
}
124+
}
125+
```
126+
127+
Finally, bind the `v-model` of the Vuetify component to the corresponding `knowNothing.xxx`, and point the action to the corresponding `setXxx()` function. For example:
128+
129+
```HTML
130+
<v-text-field
131+
v-model="knowNothing.setting1"
132+
@change="setSetting1($event.target.value)"
133+
></v-text-field>
134+
```
135+
136+
Done! Run the program and open DevTools to check if the values are correctly stored in the "Application" tab.
137+
138+
In `KnowNothingBot.js`, using the parameters you set is very simple:
139+
140+
```JavaScript
141+
...
142+
import store from "@/store";
143+
...
144+
store.state.knowNothing.setting1
145+
store.state.knowNothing.setting2
146+
const { setting1, setting2 } = store.state.knowNothing;
147+
...
148+
```
149+
150+
```JavaScript
151+
export default createStore({
152+
state: {
153+
...
154+
knowNothing: {
155+
setting1: "",
156+
setting2: "",
157+
},
158+
...
159+
},
160+
mutations: {
161+
...
162+
setKnowNothing(state, { setting1, setting2 }) {
163+
state.knowNothing = { setting1, setting2 };
164+
},
165+
...
166+
},
167+
...
168+
});
169+
```
170+
171+
`setting1`, `setting2`, and sub-objects can be added, deleted, or modified as you like. Just make sure the top-level object is `knowNothing`, even if it only has one configuration.
172+
173+
Then, in `KnowNothingBotSettings.vue`, add the following code:
174+
175+
```JavaScript
176+
export default {
177+
...
178+
methods: {
179+
...mapMutations(["setKnowNothing"]),
180+
setSetting1(value){
181+
this.setKnowNothing({
182+
...this.knowNothing,
183+
setting1: value
184+
})
185+
},
186+
setSetting2(value){
187+
this.setKnowNothing({
188+
...this.knowNothing,
189+
setting2: value
190+
})
191+
},
192+
},
193+
computed: {
194+
...mapState(["knowNothing"])
195+
}
196+
}
197+
```
198+
199+
Finally, bind the `v-model` of the Vuetify component to the corresponding `knowNothing.xxx`, and point the action to the corresponding `setXxx()` function. For example:
200+
201+
```HTML
202+
<v-text-field
203+
v-model="knowNothing.setting1"
204+
@change="setSetting1($event.target.value)"
205+
></v-text-field>
206+
```
207+
208+
Done! Run the program and open DevTools to check if the values are correctly stored in the "Application" tab.
209+
210+
In `KnowNothingBot.js`, using the parameters you set is very simple:
211+
212+
```JavaScript
213+
...
214+
import store from "@/store";
215+
...
216+
store.state.knowNothing.setting1
217+
store.state.knowNothing.setting2
218+
const { setting1, setting2 } = store.state.knowNothing;
219+
...
220+
```
221+
222+
### Detailed _sendPrompt() patterns
223+
224+
This is the core function, which sends and receives messages.
225+
226+
Reference existing bots depending on your interface type:
227+
228+
1. For standard HTTP APIs: see `BardBot.js`
229+
2. For SSE-based APIs: see `ChatGPTBot.js`
230+
3. For WebSocket APIs: see `BingChatBot.js`
231+
232+
How you send and parse messages depends on the specific chatbot. Once you receive a response or hit an error, do the following:
233+
234+
1. When receiving partial text, call `onUpdateResponse(callbackParam, {});`.
235+
2. If the response only contains new incremental text, and you need to assemble all the text yourself, then call `onUpdateResponse(callbackParam, {content: text, done: false)};`.
236+
3. After receiving all the text, call `onUpdateResponse(callbackParam, {content: text, done: true)};` to update all the data. If the text has already been `onUpdateResponse` before, you can just call `onUpdateResponse(callbackParam, {done: true)};`.
237+
4. When ending normally, call `resolve()`.
238+
5. If an error occurs, call `reject(error)`. The `error` can be an exception or an error message string. ChatALL will automatically handle it and display it to the user.
239+
240+
### checkAvailability() implementation
241+
242+
ChatALL calls the `checkAvailability()` function to check if the bot is available when it starts for the first time, refreshes the page (Command+R or Ctrl+R), and completes the settings.
243+
244+
In general, it performs these checks:
245+
246+
1. Is the login valid?
247+
2. Is the API key configured properly?
248+
3. Are all the other necessary conditions met?
249+
250+
If everything is good, it should execute:
251+
252+
```JavaScript
253+
this.constructor._isAvailable = true;
254+
```
255+
256+
Otherwise, it should execute:
257+
258+
```JavaScript
259+
this.constructor._isAvailable = false;
260+
```
261+
262+
Finally, always do:
263+
264+
```JavaScript
265+
return this.isAvailable();
266+
```
267+
268+
### Custom bot icons
269+
270+
Place the icon file in `src/assets/bots/knownothing-logo.png`, and modify `KnowNothingBot.js`:
271+
272+
```JavaScript
273+
static _logoFilename = "knownothing-logo.png";
274+
```
275+
276+
### Multi-language support in JS/HTML
277+
278+
Language files are located in `src/i18n/locales/`, named with language codes and in .json format.
279+
You need to add at least the following for your bot:
280+
281+
`en.json`
282+
```json
283+
"knowNothing": {
284+
"name": "Know Nothing"
285+
},
286+
```
287+
288+
`zh.json`
289+
```json
290+
"knowNothing": {
291+
"name": "啥都不懂"
292+
},
293+
```
294+
295+
Plus any other strings your bot need.
296+
297+
In JavaScript, you can use the following code to call the multi-language support:
298+
299+
```JavaScript
300+
import i18n from "@/i18n";
301+
...
302+
i18n.global.t("knowNothing.stringName")
303+
...
304+
```
305+
306+
In HTML, you can use the following code:
307+
308+
```HTML
309+
{{ $t("knowNothing.stringName") }}
310+
```

0 commit comments

Comments
 (0)