mirror of
https://github.com/wassname/chatGPTBox.git
synced 2026-06-27 18:04:15 +08:00
improve 48817006
This commit is contained in:
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Immer das schwebende Fenster anzeigen, die Seitenleiste für alle Website-Adapter deaktivieren",
|
||||
"Allow ESC to close all floating windows": "ESC-Taste zum Schließen aller schwebenden Fenster zulassen",
|
||||
"Export All Data": "Alle Daten exportieren",
|
||||
"Import All Data": "Alle Daten importieren"
|
||||
"Import All Data": "Alle Daten importieren",
|
||||
"Keep-Alive Time": "Keep-Alive-Zeit",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Für immer"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Always display floating window, disable sidebar for all site adapters",
|
||||
"Allow ESC to close all floating windows": "Allow ESC to close all floating windows",
|
||||
"Export All Data": "Export All Data",
|
||||
"Import All Data": "Import All Data"
|
||||
"Import All Data": "Import All Data",
|
||||
"Keep-Alive Time": "Keep-Alive Time",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Forever"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Mostrar siempre la ventana flotante, desactivar la barra lateral para todos los adaptadores de sitios",
|
||||
"Allow ESC to close all floating windows": "Permitir que ESC cierre todas las ventanas flotantes",
|
||||
"Export All Data": "Exportar todos los datos",
|
||||
"Import All Data": "Importar todos los datos"
|
||||
"Import All Data": "Importar todos los datos",
|
||||
"Keep-Alive Time": "Tiempo de mantenimiento de la conexión",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Siempre"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Toujours afficher la fenêtre flottante, désactiver la barre latérale pour tous les adaptateurs de site",
|
||||
"Allow ESC to close all floating windows": "Autoriser la touche ESC pour fermer toutes les fenêtres flottantes",
|
||||
"Export All Data": "Exporter toutes les données",
|
||||
"Import All Data": "Importer toutes les données"
|
||||
"Import All Data": "Importer toutes les données",
|
||||
"Keep-Alive Time": "Temps de maintien de la connexion",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Toujours"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Selalu tampilkan jendela mengambang, nonaktifkan sidebar untuk semua adapter situs",
|
||||
"Allow ESC to close all floating windows": "Izinkan ESC untuk menutup semua jendela mengambang",
|
||||
"Export All Data": "Ekspor Semua Data",
|
||||
"Import All Data": "Impor Semua Data"
|
||||
"Import All Data": "Impor Semua Data",
|
||||
"Keep-Alive Time": "Waktu Tetap Hidup",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Selamanya"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Mostra sempre la finestra flottante, disabilita la barra laterale per tutti gli adattatori del sito",
|
||||
"Allow ESC to close all floating windows": "Consenti ESC per chiudere tutte le finestre flottanti",
|
||||
"Export All Data": "Esporta tutti i dati",
|
||||
"Import All Data": "Importa tutti i dati"
|
||||
"Import All Data": "Importa tutti i dati",
|
||||
"Keep-Alive Time": "Tempo di mantenimento",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Per sempre"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "常にフローティングウィンドウを表示し、すべてのサイトアダプターでサイドバーを無効にします",
|
||||
"Allow ESC to close all floating windows": "ESCキーですべてのフローティングウィンドウを閉じる",
|
||||
"Export All Data": "すべてのデータをエクスポート",
|
||||
"Import All Data": "すべてのデータをインポート"
|
||||
"Import All Data": "すべてのデータをインポート",
|
||||
"Keep-Alive Time": "Keep-Alive時間",
|
||||
"5m": "5分",
|
||||
"30m": "30分",
|
||||
"Forever": "永久"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "항상 떠다니는 창을 표시하고 모든 사이트 어댑터의 사이드바를 비활성화합니다",
|
||||
"Allow ESC to close all floating windows": "ESC를 눌러 모든 떠다니는 창을 닫도록 허용",
|
||||
"Export All Data": "모든 데이터 내보내기",
|
||||
"Import All Data": "모든 데이터 가져오기"
|
||||
"Import All Data": "모든 데이터 가져오기",
|
||||
"Keep-Alive Time": "Keep-Alive 시간",
|
||||
"5m": "5분",
|
||||
"30m": "30분",
|
||||
"Forever": "영원히"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Sempre exibir janela flutuante, desativar barra lateral para todos os adaptadores de site",
|
||||
"Allow ESC to close all floating windows": "Permitir ESC para fechar todas as janelas flutuantes",
|
||||
"Export All Data": "Exportar Todos os Dados",
|
||||
"Import All Data": "Importar Todos os Dados"
|
||||
"Import All Data": "Importar Todos os Dados",
|
||||
"Keep-Alive Time": "Tempo de Manutenção de Conexão",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Para sempre"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Всегда отображать плавающее окно, отключить боковую панель для всех адаптеров сайтов",
|
||||
"Allow ESC to close all floating windows": "Разрешить ESC для закрытия всех плавающих окон",
|
||||
"Export All Data": "Экспорт всех данных",
|
||||
"Import All Data": "Импорт всех данных"
|
||||
"Import All Data": "Импорт всех данных",
|
||||
"Keep-Alive Time": "Время поддержания активности",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Вечно"
|
||||
}
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "Her zaman kayan pencereyi görüntüle, tüm site adaptörleri için kenar çubuğunu devre dışı bırak",
|
||||
"Allow ESC to close all floating windows": "ESC tuşuyla tüm kayan pencereleri kapatmaya izin ver",
|
||||
"Export All Data": "Tüm Verileri Dışa Aktar",
|
||||
"Import All Data": "Tüm Verileri İçe Aktar"
|
||||
"Import All Data": "Tüm Verileri İçe Aktar",
|
||||
"Keep-Alive Time": "Canlı Tutma Süresi",
|
||||
"5m": "5m",
|
||||
"30m": "30m",
|
||||
"Forever": "Sonsuza dek"
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
"ChatGPT (GPT-4-8k)": "ChatGPT (GPT-4-8k)",
|
||||
"ChatGPT (GPT-4-32k)": "ChatGPT (GPT-4-32k)",
|
||||
"GPT-3.5": "GPT-3.5",
|
||||
"Ollama API": "Ollama API",
|
||||
"Custom Model": "自定义模型",
|
||||
"Balanced": "平衡",
|
||||
"Creative": "有创造力",
|
||||
@@ -148,8 +147,7 @@
|
||||
"Allow ESC to close all floating windows": "允许按ESC关闭所有浮动窗口",
|
||||
"Export All Data": "导出所有数据",
|
||||
"Import All Data": "导入所有数据",
|
||||
"Temperature": "温度",
|
||||
"keep-alive Time": "保活时间",
|
||||
"Keep-Alive Time": "保活时间",
|
||||
"5m": "5分钟",
|
||||
"30m": "半小时",
|
||||
"Forever": "永久"
|
||||
|
||||
@@ -146,5 +146,9 @@
|
||||
"Always display floating window, disable sidebar for all site adapters": "總是顯示浮動視窗,停用所有網站適配器的側邊欄",
|
||||
"Allow ESC to close all floating windows": "允許按 ESC 關閉所有浮動視窗",
|
||||
"Export All Data": "匯出所有資料",
|
||||
"Import All Data": "匯入所有資料"
|
||||
"Import All Data": "匯入所有資料",
|
||||
"Keep-Alive Time": "保持連線時間",
|
||||
"5m": "5 分鐘",
|
||||
"30m": "30 分鐘",
|
||||
"Forever": "永遠"
|
||||
}
|
||||
|
||||
@@ -127,13 +127,7 @@ async function executeApi(session, port, config) {
|
||||
config.customModelName,
|
||||
)
|
||||
} else if (ollamaApiModelKeys.includes(session.modelName)) {
|
||||
await generateAnswersWithOllamaApi(
|
||||
port,
|
||||
session.question,
|
||||
session,
|
||||
config.ollamaApiKey,
|
||||
config.ollamaModelName,
|
||||
)
|
||||
await generateAnswersWithOllamaApi(port, session.question, session)
|
||||
} else if (azureOpenAiApiModelKeys.includes(session.modelName)) {
|
||||
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
|
||||
} else if (claudeApiModelKeys.includes(session.modelName)) {
|
||||
|
||||
@@ -251,7 +251,8 @@ export const defaultConfig = {
|
||||
|
||||
ollamaEndpoint: 'http://127.0.0.1:11434',
|
||||
ollamaModelName: 'llama3.1',
|
||||
keepAliveTime: '5m',
|
||||
ollamaApiKey: '',
|
||||
ollamaKeepAliveTime: '5m',
|
||||
|
||||
// advanced
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import '../styles.scss'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { parseFloatWithClamp, parseIntWithClamp } from '../../utils/index.mjs'
|
||||
import { isUsingOllamaModel } from '../../config/index.mjs'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'
|
||||
import Browser from 'webextension-polyfill'
|
||||
@@ -58,49 +56,6 @@ function ApiParams({ config, updateConfig }) {
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
{isUsingOllamaModel(config) && (
|
||||
<label>
|
||||
{`${t('keep-alive Time')}: `}
|
||||
<div className="label-group">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="keepAliveTime"
|
||||
value="5m"
|
||||
checked={config.keepAliveTime === '5m'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ keepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('5m')}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="keepAliveTime"
|
||||
value="30m"
|
||||
checked={config.keepAliveTime === '30m'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ keepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('30m')}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="keepAliveTime"
|
||||
value="-1"
|
||||
checked={config.keepAliveTime === '-1'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ keepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('Forever')}
|
||||
</label>
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -350,6 +350,47 @@ export function GeneralPart({ config, updateConfig }) {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isUsingOllamaModel(config) && (
|
||||
<div style={{ display: 'flex', gap: '10px' }}>
|
||||
{t('Keep-Alive Time') + ':'}
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="ollamaKeepAliveTime"
|
||||
value="5m"
|
||||
checked={config.ollamaKeepAliveTime === '5m'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ ollamaKeepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('5m')}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="ollamaKeepAliveTime"
|
||||
value="30m"
|
||||
checked={config.ollamaKeepAliveTime === '30m'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ ollamaKeepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('30m')}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="ollamaKeepAliveTime"
|
||||
value="-1"
|
||||
checked={config.ollamaKeepAliveTime === '-1'}
|
||||
onChange={(e) => {
|
||||
updateConfig({ ollamaKeepAliveTime: e.target.value })
|
||||
}}
|
||||
/>
|
||||
{t('Forever')}
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isUsingOllamaModel(config) && (
|
||||
<input
|
||||
type="text"
|
||||
|
||||
@@ -23,11 +23,6 @@
|
||||
--active-color: #eaecf0;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.container-page-mode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -63,7 +58,6 @@
|
||||
}
|
||||
|
||||
.footer {
|
||||
max-width: 580px;
|
||||
width: 90%;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
@@ -94,12 +88,3 @@
|
||||
background: var(--active-color);
|
||||
}
|
||||
}
|
||||
|
||||
.label-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label-group label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@@ -1,84 +1,38 @@
|
||||
// ollama api version
|
||||
|
||||
// There is a lot of duplicated code here, but it is very easy to refactor.
|
||||
// The current state is mainly convenient for making targeted changes at any time,
|
||||
// and it has not yet had a negative impact on maintenance.
|
||||
// If necessary, I will refactor.
|
||||
|
||||
import { getUserConfig } from '../../config/index.mjs'
|
||||
import { fetchSSE } from '../../utils/fetch-ollama.mjs'
|
||||
import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs'
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { pushRecord, setAbortController } from './shared.mjs'
|
||||
import { generateAnswersWithChatgptApiCompat } from './openai-api.mjs'
|
||||
|
||||
/**
|
||||
* @param {Browser.Runtime.Port} port
|
||||
* @param {string} question
|
||||
* @param {Session} session
|
||||
* @param {string} apiKey
|
||||
* @param {string} modelName
|
||||
*/
|
||||
export async function generateAnswersWithOllamaApi(port, question, session, apiKey, modelName) {
|
||||
const { controller, messageListener, disconnectListener } = setAbortController(port)
|
||||
|
||||
export async function generateAnswersWithOllamaApi(port, question, session) {
|
||||
const config = await getUserConfig()
|
||||
const prompt = getConversationPairs(
|
||||
session.conversationRecords.slice(-config.maxConversationContextLength),
|
||||
false,
|
||||
)
|
||||
// prompt.unshift({ role: 'system', content: await getOllamaApiPromptBase() })
|
||||
prompt.push({ role: 'user', content: question })
|
||||
const apiUrl = config.ollamaEndpoint
|
||||
|
||||
let answer = ''
|
||||
let finished = false
|
||||
const finish = () => {
|
||||
finished = true
|
||||
pushRecord(session, question, answer)
|
||||
console.debug('conversation history', { content: session.conversationRecords })
|
||||
port.postMessage({ answer: null, done: true, session: session })
|
||||
}
|
||||
await fetchSSE(`${apiUrl}/api/chat`, {
|
||||
method: 'POST',
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
return generateAnswersWithChatgptApiCompat(
|
||||
config.ollamaEndpoint + '/v1',
|
||||
port,
|
||||
question,
|
||||
session,
|
||||
config.ollamaApiKey,
|
||||
'ollamaModel',
|
||||
{
|
||||
model: config.ollamaModelName,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: prompt,
|
||||
model: modelName,
|
||||
stream: true,
|
||||
max_tokens: config.maxResponseTokenLength,
|
||||
temperature: config.temperature,
|
||||
keep_alive: config.keepAliveTime === '-1' ? -1 : config.keepAliveTime,
|
||||
).then(() =>
|
||||
fetch(config.ollamaEndpoint + '/api/generate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${config.ollamaApiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: config.ollamaModelName,
|
||||
prompt: 't',
|
||||
options: {
|
||||
num_predict: 1,
|
||||
},
|
||||
keep_alive: config.ollamaKeepAliveTime === '-1' ? -1 : config.ollamaKeepAliveTime,
|
||||
}),
|
||||
}),
|
||||
onMessage(message) {
|
||||
console.debug('sse message', message)
|
||||
if (finished) return
|
||||
let data = message
|
||||
const delta = data.message?.content
|
||||
if (delta) {
|
||||
answer += delta
|
||||
port.postMessage({ answer: answer, done: false, session: null })
|
||||
}
|
||||
if (data.done_reason) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
},
|
||||
async onStart() {},
|
||||
async onEnd() {
|
||||
port.postMessage({ done: true })
|
||||
port.onMessage.removeListener(messageListener)
|
||||
port.onDisconnect.removeListener(disconnectListener)
|
||||
},
|
||||
async onError(resp) {
|
||||
port.onMessage.removeListener(messageListener)
|
||||
port.onDisconnect.removeListener(disconnectListener)
|
||||
if (resp instanceof Error) throw resp
|
||||
const error = await resp.json().catch(() => ({}))
|
||||
throw new Error(!isEmpty(error) ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`)
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ export async function generateAnswersWithChatgptApiCompat(
|
||||
session,
|
||||
apiKey,
|
||||
modelName,
|
||||
extraBody = {},
|
||||
) {
|
||||
const { controller, messageListener, disconnectListener } = setAbortController(port)
|
||||
|
||||
@@ -157,6 +158,7 @@ export async function generateAnswersWithChatgptApiCompat(
|
||||
stream: true,
|
||||
max_tokens: config.maxResponseTokenLength,
|
||||
temperature: config.temperature,
|
||||
...extraBody,
|
||||
}),
|
||||
onMessage(message) {
|
||||
console.debug('sse message', message)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
export async function fetchSSE(resource, options) {
|
||||
const { onMessage, onStart, onEnd, onError, ...fetchOptions } = options
|
||||
const resp = await fetch(resource, fetchOptions).catch(async (err) => {
|
||||
await onError(err)
|
||||
})
|
||||
if (!resp) return
|
||||
if (!resp.ok) {
|
||||
await onError(resp)
|
||||
return
|
||||
}
|
||||
let hasStarted = false
|
||||
const reader = resp.body.getReader()
|
||||
let result
|
||||
while (!(result = await reader.read()).done) {
|
||||
const chunk = result.value
|
||||
const str = new TextDecoder().decode(chunk)
|
||||
if (!hasStarted) {
|
||||
const str = new TextDecoder().decode(chunk)
|
||||
hasStarted = true
|
||||
await onStart(str)
|
||||
}
|
||||
let data = JSON.parse(str)
|
||||
onMessage(data)
|
||||
if (data.done) break
|
||||
}
|
||||
await onEnd()
|
||||
}
|
||||
@@ -33,7 +33,6 @@ export async function fetchSSE(resource, options) {
|
||||
console.debug('not common response', error)
|
||||
}
|
||||
if (fakeSseData) {
|
||||
console.log('FAKE')
|
||||
parser.feed(new TextEncoder().encode(fakeSseData))
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user