Skip to content

Commit ffafd95

Browse files
committed
Merge branch 'trunk'
2 parents c5594d7 + 1f7e7af commit ffafd95

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1002
-383
lines changed

manifest.config.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default defineManifest(async (env) => {
66
name: '__MSG_appName__',
77
description: '__MSG_appDesc__',
88
default_locale: 'en',
9-
version: '1.35.5',
9+
version: '1.38.1',
1010
icons: {
1111
'16': 'src/assets/icon.png',
1212
'32': 'src/assets/icon.png',
@@ -23,8 +23,12 @@ export default defineManifest(async (env) => {
2323
'https://*.openai.com/',
2424
'https://bard.google.com/',
2525
'https://*.chathub.gg/',
26+
'https://*.duckduckgo.com/',
27+
'https://*.poe.com/',
28+
'https://*.anthropic.com/',
29+
'https://*.claude.ai/',
2630
],
27-
optional_host_permissions: ['https://*/*'],
31+
optional_host_permissions: ['https://*/*', 'wss://*/*'],
2832
permissions: ['storage', 'unlimitedStorage', 'sidePanel', 'declarativeNetRequestWithHostAccess'],
2933
content_scripts: [
3034
{
@@ -58,6 +62,16 @@ export default defineManifest(async (env) => {
5862
enabled: true,
5963
path: 'src/rules/ddg.json',
6064
},
65+
{
66+
id: 'ruleset_qianwen',
67+
enabled: true,
68+
path: 'src/rules/qianwen.json',
69+
},
70+
{
71+
id: 'ruleset_baichuan',
72+
enabled: true,
73+
path: 'src/rules/baichuan.json',
74+
},
6175
],
6276
},
6377
}

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"devDependencies": {
1111
"@crxjs/vite-plugin": "^2.0.0-beta.18",
1212
"@headlessui/tailwindcss": "^0.2.0",
13-
"@types/chrome": "^0.0.241",
13+
"@types/humanize-duration": "^3.27.1",
1414
"@types/lodash-es": "^4.17.8",
1515
"@types/md5": "^2.3.2",
1616
"@types/react": "^18.2.18",
@@ -20,11 +20,12 @@
2020
"@types/react-scroll-to-bottom": "^4.2.1",
2121
"@types/turndown": "^5.0.1",
2222
"@types/uuid": "^9.0.2",
23-
"@types/webextension-polyfill": "^0.10.1",
23+
"@types/webextension-polyfill": "^0.10.2",
2424
"@typescript-eslint/eslint-plugin": "^5.60.1",
2525
"@typescript-eslint/parser": "^5.60.1",
2626
"@vitejs/plugin-react": "^4.0.4",
2727
"autoprefixer": "^10.4.14",
28+
"chrome-types": "^0.1.231",
2829
"eslint": "^8.46.0",
2930
"eslint-config-prettier": "^8.8.0",
3031
"eslint-plugin-react": "^7.33.1",
@@ -54,12 +55,14 @@
5455
"cachified": "^3.5.4",
5556
"clsx": "^2.0.0",
5657
"cmdk": "^0.2.0",
58+
"dayjs": "^1.11.9",
5759
"eventsource-parser": "^1.0.0",
5860
"framer-motion": "^10.16.0",
5961
"fuse.js": "^6.6.2",
6062
"github-markdown-css": "^5.2.0",
6163
"gpt3-tokenizer": "^1.1.5",
6264
"highlight.js": "^11.8.0",
65+
"humanize-duration": "^3.29.0",
6366
"i18next": "^23.4.2",
6467
"i18next-browser-languagedetector": "^7.1.0",
6568
"immer": "^9.0.19",
@@ -70,6 +73,7 @@
7073
"lodash-es": "^4.17.21",
7174
"lucide-react": "^0.264.0",
7275
"md5": "^2.3.0",
76+
"nanoid": "^4.0.2",
7377
"ofetch": "^1.1.1",
7478
"plausible-tracker": "^0.3.8",
7579
"react": "^18.2.0",

src/app/bots/baichuan/api.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ofetch } from 'ofetch'
2+
import { customAlphabet } from 'nanoid'
3+
import { ChatError, ErrorCode } from '~utils/errors'
4+
5+
interface UserInfo {
6+
id: number
7+
}
8+
9+
export async function getUserInfo(): Promise<UserInfo> {
10+
const resp = await ofetch<{ data?: UserInfo; code: number; msg: string }>(
11+
'https://www.baichuan-ai.com/api/user/user-info',
12+
{ method: 'POST' },
13+
)
14+
if (resp.code === 401) {
15+
throw new ChatError('请先登录百川账号', ErrorCode.BAICHUAN_WEB_UNAUTHORIZED)
16+
}
17+
if (resp.code !== 200) {
18+
throw new Error(`Error: ${resp.code} ${resp.msg}`)
19+
}
20+
return resp.data!
21+
}
22+
23+
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789')
24+
25+
function randomString(length: number) {
26+
return nanoid(length)
27+
}
28+
29+
export function generateSessionId() {
30+
return 'p' + randomString(10)
31+
}
32+
33+
export function generateMessageId() {
34+
return 'U' + randomString(14)
35+
}

src/app/bots/baichuan/index.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { AbstractBot, SendMessageParams } from '../abstract-bot'
2+
import { requestHostPermission } from '~app/utils/permissions'
3+
import { ChatError, ErrorCode } from '~utils/errors'
4+
import { uuid } from '~utils'
5+
import { generateMessageId, generateSessionId, getUserInfo } from './api'
6+
import { streamAsyncIterable } from '~utils/stream-async-iterable'
7+
8+
interface Message {
9+
id: string
10+
createdAt: number
11+
data: string
12+
from: 0 | 1 // human | bot
13+
}
14+
15+
interface ConversationContext {
16+
conversationId: string
17+
historyMessages: Message[]
18+
userId: number
19+
lastMessageId?: string
20+
}
21+
22+
export class BaichuanWebBot extends AbstractBot {
23+
private conversationContext?: ConversationContext
24+
25+
async doSendMessage(params: SendMessageParams) {
26+
if (!(await requestHostPermission('https://*.baichuan-ai.com/'))) {
27+
throw new ChatError('Missing baichuan-ai.com permission', ErrorCode.MISSING_HOST_PERMISSION)
28+
}
29+
30+
if (!this.conversationContext) {
31+
const conversationId = generateSessionId()
32+
const userInfo = await getUserInfo()
33+
this.conversationContext = { conversationId, historyMessages: [], userId: userInfo.id }
34+
}
35+
36+
const { conversationId, lastMessageId, historyMessages, userId } = this.conversationContext
37+
38+
const message: Message = {
39+
id: generateMessageId(),
40+
createdAt: Date.now(),
41+
data: params.prompt,
42+
from: 0,
43+
}
44+
45+
const resp = await fetch('https://www.baichuan-ai.com/api/chat/v1/chat', {
46+
method: 'POST',
47+
signal: params.signal,
48+
headers: {
49+
'Content-Type': 'application/json',
50+
},
51+
body: JSON.stringify({
52+
stream: true,
53+
request_id: uuid(),
54+
app_info: { id: 10001, name: 'baichuan_web' },
55+
user_info: { id: userId, status: 1 },
56+
prompt: {
57+
id: message.id,
58+
data: message.data,
59+
from: message.from,
60+
parent_id: lastMessageId || 0,
61+
created_at: message.createdAt,
62+
},
63+
session_info: { id: conversationId, name: '新的对话', created_at: Date.now() },
64+
parameters: {
65+
repetition_penalty: -1,
66+
temperature: -1,
67+
top_k: -1,
68+
top_p: -1,
69+
max_new_tokens: -1,
70+
do_sample: -1,
71+
regenerate: 0,
72+
},
73+
history: historyMessages,
74+
}),
75+
})
76+
77+
const decoder = new TextDecoder()
78+
let result = ''
79+
let answerMessageId: string | undefined
80+
81+
for await (const uint8Array of streamAsyncIterable(resp.body!)) {
82+
const str = decoder.decode(uint8Array)
83+
console.debug('baichuan stream', str)
84+
const lines = str.split('\n')
85+
for (const line of lines) {
86+
if (!line) {
87+
continue
88+
}
89+
const data = JSON.parse(line)
90+
if (!data.answer) {
91+
continue
92+
}
93+
answerMessageId = data.answer.id
94+
const text = data.answer.data
95+
if (text) {
96+
result += text
97+
params.onEvent({ type: 'UPDATE_ANSWER', data: { text: result } })
98+
}
99+
}
100+
}
101+
102+
this.conversationContext.historyMessages.push(message)
103+
if (answerMessageId) {
104+
this.conversationContext.lastMessageId = answerMessageId
105+
if (result) {
106+
this.conversationContext.historyMessages.push({
107+
id: answerMessageId,
108+
data: result,
109+
createdAt: Date.now(),
110+
from: 1,
111+
})
112+
}
113+
}
114+
115+
params.onEvent({ type: 'DONE' })
116+
}
117+
118+
resetConversation() {
119+
this.conversationContext = undefined
120+
}
121+
122+
get name() {
123+
return '百川大模型'
124+
}
125+
}

src/app/bots/bing/api.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { random } from 'lodash-es'
2-
import { FetchError, ofetch } from 'ofetch'
2+
import { FetchError, FetchResponse, ofetch } from 'ofetch'
33
import { uuid } from '~utils'
44
import { ChatError, ErrorCode } from '~utils/errors'
55
import { ConversationResponse } from './types'
@@ -14,32 +14,41 @@ const API_ENDPOINT = 'https://www.bing.com/turing/conversation/create'
1414
export async function createConversation(): Promise<ConversationResponse> {
1515
const headers = {
1616
'x-ms-client-request-id': uuid(),
17-
'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.0 OS/Win32',
17+
'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.3 OS/macOS',
1818
}
1919

20-
let resp: ConversationResponse
20+
let rawResponse: FetchResponse<ConversationResponse>
2121
try {
22-
resp = await ofetch(API_ENDPOINT, { headers, redirect: 'error' })
23-
if (!resp.result) {
22+
rawResponse = await ofetch.raw<ConversationResponse>(API_ENDPOINT, { headers, redirect: 'error' })
23+
if (!rawResponse._data?.result) {
2424
throw new Error('Invalid response')
2525
}
2626
} catch (err) {
2727
console.error('retry bing create', err)
28-
resp = await ofetch(API_ENDPOINT, {
28+
rawResponse = await ofetch.raw<ConversationResponse>(API_ENDPOINT, {
2929
headers: { ...headers, 'x-forwarded-for': randomIP() },
3030
redirect: 'error',
3131
})
32-
if (!resp) {
32+
if (!rawResponse._data) {
3333
throw new FetchError(`Failed to fetch (${API_ENDPOINT})`)
3434
}
3535
}
3636

37-
if (resp.result.value !== 'Success') {
38-
const message = `${resp.result.value}: ${resp.result.message}`
39-
if (resp.result.value === 'UnauthorizedRequest') {
37+
const data = rawResponse._data
38+
39+
if (data.result.value !== 'Success') {
40+
const message = `${data.result.value}: ${data.result.message}`
41+
if (data.result.value === 'UnauthorizedRequest') {
4042
throw new ChatError(message, ErrorCode.BING_UNAUTHORIZED)
4143
}
4244
throw new Error(message)
4345
}
44-
return resp
46+
47+
const conversationSignature = rawResponse.headers.get('x-sydney-conversationsignature')!
48+
const encryptedConversationSignature = rawResponse.headers.get('x-sydney-encryptedconversationsignature') || undefined
49+
50+
data.conversationSignature = data.conversationSignature || conversationSignature
51+
data.encryptedConversationSignature = encryptedConversationSignature
52+
53+
return data
4554
}

0 commit comments

Comments
 (0)