Skip to content

Commit d1c9115

Browse files
committed
feat(ollama): add ollama #40
1 parent 9c1a4de commit d1c9115

File tree

4 files changed

+71
-5
lines changed

4 files changed

+71
-5
lines changed

src/app/bots/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { PiBot } from './pi'
88
import { QianwenWebBot } from './qianwen'
99
import { XunfeiBot } from './xunfei'
1010
import {LlaMa2Bot} from "~app/bots/llama2";
11+
import {OllamaBot} from "~app/bots/ollama";
1112

1213
export type BotId =
1314
| 'chatgpt'
@@ -23,6 +24,7 @@ export type BotId =
2324
| 'gemma'
2425
| 'qianwen'
2526
| 'baichuan'
27+
| 'ollama'
2628

2729
export type ChatPage =
2830
| 'side'
@@ -31,6 +33,8 @@ export type ChatPage =
3133

3234
export function createBotInstance(botId: BotId) {
3335
switch (botId) {
36+
case 'ollama':
37+
return new OllamaBot()
3438
case 'chatgpt':
3539
return new ChatGPTBot()
3640
case 'bing':

src/app/bots/ollama/index.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { parseSSEResponse } from '~utils/sse'
2+
import { AbstractBot, SendMessageParams } from '../abstract-bot'
3+
import {requestHostPermission} from "~app/utils/permissions";
4+
import {ChatError, ErrorCode} from "~utils/errors";
5+
import {getUserConfig, OllamaAPIModel} from "~services/user-config";
6+
import {streamAsyncIterable} from "~utils/stream-async-iterable";
7+
8+
interface ConversationContext {
9+
initialized: boolean
10+
}
11+
12+
export class OllamaBot extends AbstractBot {
13+
private conversationContext?: ConversationContext
14+
15+
async doSendMessage(params: SendMessageParams) {
16+
const {ollamaApi, ollamaModel} = await getUserConfig()
17+
18+
const urlObj = new URL(ollamaApi);
19+
if (!(await requestHostPermission(urlObj.protocol + '//*.' + urlObj.hostname + "/"))) {
20+
throw new ChatError('Missing ollama api url permission', ErrorCode.MISSING_HOST_PERMISSION)
21+
}
22+
23+
const resp = await fetch(ollamaApi, {
24+
method: 'POST',
25+
signal: params.signal,
26+
body: JSON.stringify({
27+
"model": ollamaModel,
28+
"messages": [
29+
{ "role": "user", "content": params.prompt }
30+
]
31+
})
32+
})
33+
34+
const decoder = new TextDecoder()
35+
let result = ''
36+
37+
for await (const uint8Array of streamAsyncIterable(resp.body!)) {
38+
const str = decoder.decode(uint8Array)
39+
console.debug('ollama stream', str)
40+
const lines = str.split('\n')
41+
for (const line of lines) {
42+
if (!line) {
43+
continue
44+
}
45+
const data = JSON.parse(line)
46+
const text = data.message.content
47+
if (text) {
48+
result += text
49+
params.onEvent({ type: 'UPDATE_ANSWER', data: { text: result } })
50+
}
51+
}
52+
}
53+
params.onEvent({ type: 'DONE' })
54+
}
55+
56+
resetConversation() {
57+
this.conversationContext = undefined
58+
}
59+
}

src/app/consts.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import bardLogo from '~/assets/bard-logo.svg'
44
import bingLogo from '~/assets/bing-logo.svg'
55
import yiLogo from '~/assets/yi-logo.svg'
66
import chatgptLogo from '~/assets/chatgpt-logo.svg'
7-
import falconLogo from '~/assets/falcon-logo.jpeg'
7+
import ollamaLogo from '~/assets/ollama-logo.png'
88
import llamaLogo from '~/assets/llama-logo.png'
99
import mistralLogo from '~/assets/mistral-logo.png'
1010
import piLogo from '~/assets/pi-logo.png'
@@ -31,14 +31,14 @@ export const CHATBOTS: Record<BotId, { name: string; avatar: string }> = {
3131
name: 'Llama 3 70B',
3232
avatar: llamaLogo,
3333
},
34+
ollama: {
35+
name: 'Ollama',
36+
avatar: ollamaLogo,
37+
},
3438
vicuna: {
3539
name: 'Vicuna',
3640
avatar: vicunaLogo,
3741
},
38-
/* falcon: {
39-
name: 'Falcon',
40-
avatar: falconLogo,
41-
},*/
4242
mistral: {
4343
name: 'Mixtral',
4444
avatar: mistralLogo,

src/app/pages/SettingPage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
setStore, getBotId
4040
} from "~services/storage/memory-store";
4141
import store from "store2";
42+
import OllamaAPISettings from "~app/components/Settings/OllamaAPISettings";
4243

4344
const BING_STYLE_OPTIONS = [
4445
{ name: 'Precise', value: BingConversationStyle.Precise },
@@ -153,6 +154,8 @@ const SettingPage = () => {
153154
</div>
154155
</div>
155156
</div>)}
157+
{getBotId() == "ollama" && (
158+
<OllamaAPISettings userConfig={userConfig} updateConfigValue={updateConfigValue} />)}
156159
</div>
157160
<Button color={dirty ? 'primary' : 'flat'} text={t('Save')} className="w-fit my-8" onClick={save} />
158161
<Toaster position="top-right" />

0 commit comments

Comments
 (0)