12 Commits

Author SHA1 Message Date
IndieKKY
cccf7e6149 chore: release 1.11.10 2024-10-16 09:08:09 +08:00
IndieKKY
30dc724ebb 断开连接提示 2024-10-16 09:07:49 +08:00
IndieKKY
51a7e998b9 chore: release 1.11.9 2024-10-13 21:14:44 +08:00
IndieKKY
556ccef4b2 代理推荐 2024-10-13 21:12:10 +08:00
IndieKKY
42b719fb98 语言文件 2024-10-13 21:12:04 +08:00
IndieKKY
fa66445466 chore: release 1.11.8 2024-10-12 14:01:32 +08:00
IndieKKY
d711b2abf8 bibigpt 2024-10-12 14:01:16 +08:00
IndieKKY
47fcb1de11 bibigpt 2024-10-12 14:01:07 +08:00
IndieKKY
be3d3624bc chore: release 1.11.7 2024-10-10 11:24:18 +08:00
IndieKKY
910b1ce6d9 优化描述 2024-10-10 11:23:23 +08:00
IndieKKY
0a6bda667e chore: release 1.11.6 2024-10-10 11:21:23 +08:00
IndieKKY
5a0a123af9 优化导出 2024-10-10 09:23:42 +08:00
15 changed files with 132 additions and 43 deletions

View File

@@ -12,9 +12,10 @@ const [major, minor, patch, label = '0'] = version
.split(/[.-]/) .split(/[.-]/)
export default defineManifest(async (env) => ({ export default defineManifest(async (env) => ({
"name": "哔哔君 - 哔哩哔哩字幕列表", "name": '__MSG_appName__',
"description": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!", "description": '__MSG_appDescription__',
"version": `${major}.${minor}.${patch}`, "version": `${major}.${minor}.${patch}`,
"default_locale": "zh_CN",
"manifest_version": 3, "manifest_version": 3,
"permissions": [ "permissions": [
"sidePanel", "sidePanel",

View File

@@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"name": "bilibili-subtitle", "name": "bilibili-subtitle",
"version": "1.11.5", "version": "1.11.10",
"type": "module", "type": "module",
"description": "哔哩哔哩字幕列表", "description": "哔哩哔哩字幕列表",
"main": "index.js", "main": "index.js",
@@ -24,6 +24,7 @@
"ahooks": "^3.7.1", "ahooks": "^3.7.1",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"daisyui": "^2.42.1", "daisyui": "^2.42.1",
"dayjs": "^1.11.13",
"js-search": "^2.0.0", "js-search": "^2.0.0",
"less": "^4.1.3", "less": "^4.1.3",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",

13
pnpm-lock.yaml generated
View File

@@ -41,6 +41,9 @@ importers:
daisyui: daisyui:
specifier: ^2.42.1 specifier: ^2.42.1
version: 2.42.1(autoprefixer@10.4.13(postcss@8.4.19))(postcss@8.4.19) version: 2.42.1(autoprefixer@10.4.13(postcss@8.4.19))(postcss@8.4.19)
dayjs:
specifier: ^1.11.13
version: 1.11.13
js-search: js-search:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
@@ -856,8 +859,8 @@ packages:
autoprefixer: ^10.0.2 autoprefixer: ^10.0.2
postcss: ^8.1.6 postcss: ^8.1.6
dayjs@1.11.5: dayjs@1.11.13:
resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==} resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
debug@2.6.9: debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
@@ -3114,7 +3117,7 @@ snapshots:
dependencies: dependencies:
'@types/js-cookie': 2.2.7 '@types/js-cookie': 2.2.7
ahooks-v3-count: 1.0.0 ahooks-v3-count: 1.0.0
dayjs: 1.11.5 dayjs: 1.11.13
intersection-observer: 0.12.2 intersection-observer: 0.12.2
js-cookie: 2.2.1 js-cookie: 2.2.1
lodash: 4.17.21 lodash: 4.17.21
@@ -3126,7 +3129,7 @@ snapshots:
dependencies: dependencies:
'@types/js-cookie': 2.2.7 '@types/js-cookie': 2.2.7
ahooks-v3-count: 1.0.0 ahooks-v3-count: 1.0.0
dayjs: 1.11.5 dayjs: 1.11.13
intersection-observer: 0.12.2 intersection-observer: 0.12.2
js-cookie: 2.2.1 js-cookie: 2.2.1
lodash: 4.17.21 lodash: 4.17.21
@@ -3385,7 +3388,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- ts-node - ts-node
dayjs@1.11.5: {} dayjs@1.11.13: {}
debug@2.6.9: debug@2.6.9:
dependencies: dependencies:

View File

@@ -0,0 +1,8 @@
{
"appName": {
"message": "哔哔君 - bilibili哔哩哔哩字幕列表"
},
"appDescription": {
"message": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!"
}
}

BIN
public/bibigpt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -39,6 +39,7 @@ import Ask from './Ask'
import { v4 } from 'uuid' import { v4 } from 'uuid'
import RateExtension from '../components/RateExtension' import RateExtension from '../components/RateExtension'
import ApiKeyReminder from './ApiKeyReminder' import ApiKeyReminder from './ApiKeyReminder'
import useMessaging from '@/messaging/layer2/useMessaging'
const Body = () => { const Body = () => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@@ -65,6 +66,7 @@ const Body = () => {
// const fontSize = useAppSelector(state => state.env.envData.fontSize) // const fontSize = useAppSelector(state => state.env.envData.fontSize)
const searchText = useAppSelector(state => state.env.searchText) const searchText = useAppSelector(state => state.env.searchText)
const asks = useAppSelector(state => state.env.asks) const asks = useAppSelector(state => state.env.asks)
const {disconnected} = useMessaging()
// const recommendIdx = useMemo(() => random(0, 3), []) // const recommendIdx = useMemo(() => random(0, 3), [])
const showSearchInput = useMemo(() => { const showSearchInput = useMemo(() => {
return (segments != null && segments.length > 0) && (envData.searchEnabled ? envData.searchEnabled : (envData.askEnabled ?? ASK_ENABLED_DEFAULT)) return (segments != null && segments.length > 0) && (envData.searchEnabled ? envData.searchEnabled : (envData.askEnabled ?? ASK_ENABLED_DEFAULT))
@@ -262,6 +264,10 @@ const Body = () => {
{searchText && <button className='absolute top-1 right-2 btn btn-ghost btn-xs btn-circle text-base-content/75' onClick={onClearSearchText}><AiOutlineCloseCircle /></button>} {searchText && <button className='absolute top-1 right-2 btn btn-ghost btn-xs btn-circle text-base-content/75' onClick={onClearSearchText}><AiOutlineCloseCircle /></button>}
</div>} </div>}
{disconnected && <div className='flex flex-col justify-center items-center gap-2 text-sm bg-red-400 rounded mx-2'>
<span className='flex items-center gap-1 text-white'><AiOutlineCloseCircle className='text-white' /></span>
</div>}
{/* auto scroll btn */} {/* auto scroll btn */}
{!autoScroll && <div {!autoScroll && <div
className='absolute z-[999] top-[96px] right-6 tooltip tooltip-left cursor-pointer rounded-full bg-primary/25 hover:bg-primary/75 text-primary-content p-1.5 text-xl' className='absolute z-[999] top-[96px] right-6 tooltip tooltip-left cursor-pointer rounded-full bg-primary/25 hover:bg-primary/75 text-primary-content p-1.5 text-xl'
@@ -304,22 +310,22 @@ const Body = () => {
{/* </button>} */} {/* </button>} */}
{/* </div> */} {/* </div> */}
<div className='flex flex-col'> <div className='flex flex-col'>
{/* <div className='flex flex-col items-center text-center py-2 mx-4 border-t border-t-base-300'> */} <div className='flex flex-col items-center text-center py-2 mx-4 border-t border-t-base-300'>
{/* <div className='font-semibold text-accent flex items-center gap-1'><img src='/bibigpt.png' */} <div className='font-semibold text-accent flex items-center gap-1'><img src='/bibigpt.png'
{/* alt='BibiGPT logo' */} alt='BibiGPT logo'
{/* className='w-8 h-8'/>BibiGPT */} className='w-8 h-8'/>BibiGPT
{/* </div> */} </div>
{/* <div className='text-sm px-2 desc'>这是<span className='text-amber-600 font-semibold text-base'>网页</span>版的字幕列表,支持<span */} <div className='text-sm px-2 desc'><span className='text-amber-600 font-semibold text-base'></span><span
{/* className='font-semibold'>任意</span>视频提取字幕总结(包括没有字幕的视频) */} className='font-semibold'></span>
{/* </div> */} </div>
{/* <div className='flex gap-2'> */} <div className='flex gap-2'>
{/* <a title='BibiGPT' href='https://bibigpt.co/r/bilibili' */} <a title='BibiGPT' href='https://bibigpt.co/r/bilibili'
{/* onClick={(e) => { */} onClick={(e) => {
{/* e.preventDefault() */} e.preventDefault()
{/* openUrl('https://bibigpt.co/r/bilibili') */} openUrl('https://bibigpt.co/r/bilibili')
{/* }} className='link text-sm text-accent'>✨ BibiGPT ✨</a> */} }} className='link text-sm text-accent'> BibiGPT </a>
{/* </div> */} </div>
{/* </div> */} </div>
<div className='flex flex-col items-center text-center py-2 mx-4 border-t border-t-base-300'> <div className='flex flex-col items-center text-center py-2 mx-4 border-t border-t-base-300'>
<div className='font-semibold text-accent flex items-center gap-1'><img src='/youtube-caption.png' <div className='font-semibold text-accent flex items-center gap-1'><img src='/youtube-caption.png'
alt='youtube caption logo' alt='youtube caption logo'

View File

@@ -19,6 +19,8 @@ import {downloadText, openUrl} from '@kky002/kky-util'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import {getSummarize} from '../utils/bizUtil' import {getSummarize} from '../utils/bizUtil'
import { useMessage } from '@/hooks/message' import { useMessage } from '@/hooks/message'
import dayjs from 'dayjs';
interface Props { interface Props {
placement: Placement placement: Placement
} }
@@ -68,6 +70,8 @@ const MoreBtn = (props: Props) => {
const segments = useAppSelector(state => state.env.segments) const segments = useAppSelector(state => state.env.segments)
const url = useAppSelector(state => state.env.url) const url = useAppSelector(state => state.env.url)
const title = useAppSelector(state => state.env.title) const title = useAppSelector(state => state.env.title)
const ctime = useAppSelector(state => state.env.ctime) //时间戳单位s
const author = useAppSelector(state => state.env.author)
const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType) const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType)
const {sendInject} = useMessage() const {sendInject} = useMessage()
@@ -79,20 +83,21 @@ const MoreBtn = (props: Props) => {
let fileName = title let fileName = title
let s, suffix let s, suffix
let time = ctime ? dayjs(ctime * 1000).format('YYYY-MM-DD HH:mm:ss') : '' // 2024-05-01 12:00:00
if (!downloadType || downloadType === 'text') { if (!downloadType || downloadType === 'text') {
s = `${title??'无标题'}\n${url??'无链接'}\n\n` s = `${title??'无标题'}\n${url??'无链接'}\n${author??'无作者'} ${time}\n\n`
for (const item of data.body) { for (const item of data.body) {
s += item.content + '\n' s += item.content + '\n'
} }
suffix = 'txt' suffix = 'txt'
} else if (downloadType === 'textWithTime') { } else if (downloadType === 'textWithTime') {
s = `${title??'无标题'}\n${url??'无链接'}\n\n` s = `${title??'无标题'}\n${url??'无链接'}\n${author??'无作者'} ${time}\n\n`
for (const item of data.body) { for (const item of data.body) {
s += formatTime(item.from) + ' ' + item.content + '\n' s += formatTime(item.from) + ' ' + item.content + '\n'
} }
suffix = 'txt' suffix = 'txt'
} else if (downloadType === 'article') { } else if (downloadType === 'article') {
s = `${title??'无标题'}\n${url??'无链接'}\n\n` s = `${title??'无标题'}\n${url??'无链接'}\n${author??'无作者'} ${time}\n\n`
for (const item of data.body) { for (const item of data.body) {
s += item.content + ', ' s += item.content + ', '
} }
@@ -142,7 +147,7 @@ const MoreBtn = (props: Props) => {
s = JSON.stringify(data) s = JSON.stringify(data)
suffix = 'json' suffix = 'json'
} else if (downloadType === 'summarize') { } else if (downloadType === 'summarize') {
s = `${title??'无标题'}\n${url??'无链接'}\n\n` s = `${title??'无标题'}\n${url??'无链接'}\n${author??'无作者'} ${time}\n\n`
const [success, content] = getSummarize(title, segments, curSummaryType) const [success, content] = getSummarize(title, segments, curSummaryType)
if (!success) return if (!success) return
s += content s += content

View File

@@ -291,6 +291,9 @@ for (const model of MODELS) {
export const LANGUAGES = [{ export const LANGUAGES = [{
code: 'en', code: 'en',
name: 'English', name: 'English',
}, {
code: 'ja',
name: '日本語',
}, { }, {
code: 'ena', code: 'ena',
name: 'American English', name: 'American English',
@@ -324,6 +327,39 @@ export const LANGUAGES = [{
}, { }, {
code: 'Italian', code: 'Italian',
name: 'Italiano', name: 'Italiano',
}, {
code: 'ko',
name: '한국어',
}, {
code: 'hi',
name: 'हिन्दी',
}, {
code: 'tr',
name: 'Türkçe',
}, {
code: 'nl',
name: 'Nederlands',
}, {
code: 'pl',
name: 'Polski',
}, {
code: 'sv',
name: 'Svenska',
}, {
code: 'vi',
name: 'Tiếng Việt',
}, {
code: 'th',
name: 'ไทย',
}, {
code: 'id',
name: 'Bahasa Indonesia',
}, {
code: 'el',
name: 'Ελληνικά',
}, {
code: 'he',
name: 'עברית',
}] }]
export const LANGUAGES_MAP: {[key: string]: typeof LANGUAGES[number]} = {} export const LANGUAGES_MAP: {[key: string]: typeof LANGUAGES[number]} = {}
for (const language of LANGUAGES) { for (const language of LANGUAGES) {

View File

@@ -1,4 +1,4 @@
import { setCurFetched, setCurInfo, setData, setInfos, setTitle, setUrl } from '@/redux/envReducer' import { setAuthor, setCtime, setCurFetched, setCurInfo, setData, setInfos, setTitle, setUrl } from '@/redux/envReducer'
import { useMemo } from 'react' import { useMemo } from 'react'
import { useAppDispatch } from './redux' import { useAppDispatch } from './redux'
import useMessagingService from '@/messaging/layer2/useMessagingService' import useMessagingService from '@/messaging/layer2/useMessagingService'
@@ -20,6 +20,8 @@ const useMessageService = () => {
dispatch(setInfos(params.infos)) dispatch(setInfos(params.infos))
dispatch(setUrl(params.url)) dispatch(setUrl(params.url))
dispatch(setTitle(params.title)) dispatch(setTitle(params.title))
dispatch(setCtime(params.ctime))
dispatch(setAuthor(params.author))
console.debug('video title: ', params.title) console.debug('video title: ', params.title)
}, },
}), [dispatch]) }), [dispatch])

View File

@@ -120,6 +120,8 @@ const debug = (...args: any[]) => {
} }
let aid: number | null = null let aid: number | null = null
let ctime: number | null = null
let author: string | undefined
let title = '' let title = ''
let pages: any[] = [] let pages: any[] = []
let pagesMap: Record<string, any> = {} let pagesMap: Record<string, any> = {}
@@ -162,6 +164,8 @@ const debug = (...args: any[]) => {
aid = parseInt(aidOrBvid.slice(2)) aid = parseInt(aidOrBvid.slice(2))
pages = await fetch(`https://api.bilibili.com/x/player/pagelist?aid=${aid}`, { credentials: 'include' }).then(res => res.json()).then(res => res.data) pages = await fetch(`https://api.bilibili.com/x/player/pagelist?aid=${aid}`, { credentials: 'include' }).then(res => res.json()).then(res => res.data)
cid = pages[0].cid cid = pages[0].cid
ctime = pages[0].ctime
author = pages[0].owner?.name
title = pages[0].part title = pages[0].part
await fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, { credentials: 'include' }).then(res => res.json()).then(res => { await fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, { credentials: 'include' }).then(res => res.json()).then(res => {
subtitles = res.data.subtitle.subtitles subtitles = res.data.subtitle.subtitles
@@ -171,6 +175,8 @@ const debug = (...args: any[]) => {
title = res.data.title title = res.data.title
aid = res.data.aid aid = res.data.aid
cid = res.data.cid cid = res.data.cid
ctime = res.data.ctime
author = res.data.owner?.name
pages = res.data.pages pages = res.data.pages
}) })
await fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, { credentials: 'include' }).then(res => res.json()).then(res => { await fetch(`https://api.bilibili.com/x/player/v2?aid=${aid}&cid=${cid}`, { credentials: 'include' }).then(res => res.json()).then(res => {
@@ -191,6 +197,8 @@ const debug = (...args: any[]) => {
url: location.origin + location.pathname, url: location.origin + location.pathname,
title, title,
aid, aid,
ctime,
author,
pages, pages,
infos: subtitles, infos: subtitles,
}) })

View File

@@ -80,7 +80,7 @@ interface ExtensionCloseSidePanelMessage extends ExtensionMessage {
method: 'SET_INFOS'; method: 'SET_INFOS';
} }
interface AppSetVideoInfoMessage extends AppMessage<{ url: string, title: string, aid: number | null, pages: any, infos: any }> { interface AppSetVideoInfoMessage extends AppMessage<{ url: string, title: string, aid: number | null, ctime: number | null, author?: string, pages: any, infos: any }> {
method: 'SET_VIDEO_INFO'; method: 'SET_VIDEO_INFO';
} }

View File

@@ -25,6 +25,7 @@ class Layer1Protocol<L1Req = any, L1Res = any> {
private timeout: number private timeout: number
private requests: Map<string, { resolve: (value: L1Res) => void, reject: (reason?: any) => void, timer: number }> private requests: Map<string, { resolve: (value: L1Res) => void, reject: (reason?: any) => void, timer: number }>
private handler: Handler<L1Req, L1Res> private handler: Handler<L1Req, L1Res>
public disconnected: boolean = false
constructor(handler: Handler<L1Req, L1Res>, port: chrome.runtime.Port, autoDispose = true, timeout = 30000) { // 默认超时 30 秒 constructor(handler: Handler<L1Req, L1Res>, port: chrome.runtime.Port, autoDispose = true, timeout = 30000) { // 默认超时 30 秒
this.port = port; this.port = port;
@@ -82,6 +83,7 @@ class Layer1Protocol<L1Req = any, L1Res = any> {
} }
dispose() { dispose() {
this.disconnected = true
this.port.onMessage.removeListener(this._messageListener); this.port.onMessage.removeListener(this._messageListener);
if (this.port.onDisconnect) { if (this.port.onDisconnect) {
this.port.onDisconnect.removeListener(this.dispose); this.port.onDisconnect.removeListener(this.dispose);

View File

@@ -1,12 +1,18 @@
import { msgWaiter } from './useMessagingService' import { msgWaiter } from './useMessagingService'
import { useCallback } from 'react' import { useCallback, useState } from 'react'
import Layer1Protocol from '../layer1/Layer1Protocol' import Layer1Protocol from '../layer1/Layer1Protocol'
import { L2ReqMsg, L2ResMsg, TAG_TARGET_INJECT } from '../const' import { L2ReqMsg, L2ResMsg, TAG_TARGET_INJECT } from '../const'
const useMessaging = <AllExtensionMessagesType extends ExtensionMessage, AllInjectMessagesType extends InjectMessage>() => { const useMessaging = <AllExtensionMessagesType extends ExtensionMessage, AllInjectMessagesType extends InjectMessage>() => {
const [disconnected, setDisconnected] = useState(false)
const sendExtension = useCallback(async <M extends AllExtensionMessagesType | MessagingExtensionMessages, K extends M['method']>(method: K, params?: Extract<M, { method: K }>['params']): Promise<Extract<M, { method: K }>['return']> => { const sendExtension = useCallback(async <M extends AllExtensionMessagesType | MessagingExtensionMessages, K extends M['method']>(method: K, params?: Extract<M, { method: K }>['params']): Promise<Extract<M, { method: K }>['return']> => {
// wait // wait
const pmh = await msgWaiter.wait() as Layer1Protocol<L2ReqMsg, L2ResMsg> const pmh = await msgWaiter.wait() as Layer1Protocol<L2ReqMsg, L2ResMsg>
if (pmh.disconnected) {
setDisconnected(true)
throw new Error('disconnected')
}
// send message // send message
const res = await pmh.sendMessage({ const res = await pmh.sendMessage({
from: 'app', from: 'app',
@@ -30,7 +36,8 @@ const useMessaging = <AllExtensionMessagesType extends ExtensionMessage, AllInje
return { return {
sendExtension, sendExtension,
sendInject sendInject,
disconnected
} }
} }

View File

@@ -27,7 +27,7 @@ import toast from 'react-hot-toast'
import {useBoolean, useEventTarget} from 'ahooks' import {useBoolean, useEventTarget} from 'ahooks'
import {useEventChecked} from '@kky002/kky-hooks' import {useEventChecked} from '@kky002/kky-hooks'
import { useMessage } from '@/hooks/message' import { useMessage } from '@/hooks/message'
import { FaChevronDown, FaChevronUp } from 'react-icons/fa' import { FaChevronDown, FaChevronUp, FaGripfire } from 'react-icons/fa'
const OptionCard = ({ title, children, defaultExpanded = true }: { title: React.ReactNode; children: React.ReactNode; defaultExpanded?: boolean }) => { const OptionCard = ({ title, children, defaultExpanded = true }: { title: React.ReactNode; children: React.ReactNode; defaultExpanded?: boolean }) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded); const [isExpanded, setIsExpanded] = useState(defaultExpanded);
@@ -261,14 +261,15 @@ const OptionsPage = () => {
<div><a className='link link-primary' <div><a className='link link-primary'
onClick={() => setServerUrlValue(DEFAULT_SERVER_URL_OPENAI)} onClick={() => setServerUrlValue(DEFAULT_SERVER_URL_OPENAI)}
rel='noreferrer'></a></div> rel='noreferrer'></a></div>
{/* <div className='flex justify-center font-semibold'>【第三方代理】</div> */} <div className='flex justify-center font-semibold'></div>
{/* <div>代理网址:<a className='link link-primary' href='https://api.openai-up.com/register?aff=varM' */} <div><a className='link link-primary' href='https://api.kksj.org/register?aff=ucVc'
{/* target='_blank' */} target='_blank'
{/* rel="noreferrer">点击访问</a></div> */} rel="noreferrer">访</a></div>
{/* <div>服务器地址:<a className='link link-primary' */} <div><a className='link link-primary'
{/* onClick={() => setServerUrlValue('https://api.openai-up.com')} */} onClick={() => setServerUrlValue('https://api.kksj.org')}
{/* rel='noreferrer'>点击设置</a></div> */} rel='noreferrer'></a></div>
{/* <div className='text-amber-600 flex justify-center items-center'><FaGripfire/>目前价格不到官方价格的6折<FaGripfire/></div> */} <div className='text-amber-600 flex justify-center items-center'><FaGripfire/>0.91(1/8)<FaGripfire/></div>
<div className='text-amber-600 flex justify-center items-center'><FaGripfire/>访🪜<FaGripfire/></div>
</div> </div>
</div>} </div>}
{(!aiTypeValue || aiTypeValue === 'openai') && <FormItem title='模型选择' htmlFor='modelSel' tip='注意不同模型有不同价格与token限制'> {(!aiTypeValue || aiTypeValue === 'openai') && <FormItem title='模型选择' htmlFor='modelSel' tip='注意不同模型有不同价格与token限制'>

View File

@@ -32,7 +32,8 @@ interface EnvState {
segments?: Segment[] segments?: Segment[]
url?: string url?: string
title?: string title?: string
ctime?: number | null
author?: string
taskIds?: string[] taskIds?: string[]
transResults: { [key: number]: TransResult } transResults: { [key: number]: TransResult }
lastTransTime?: number lastTransTime?: number
@@ -271,6 +272,12 @@ export const slice = createSlice({
setTitle: (state, action: PayloadAction<string | undefined>) => { setTitle: (state, action: PayloadAction<string | undefined>) => {
state.title = action.payload state.title = action.payload
}, },
setCtime: (state, action: PayloadAction<number | null | undefined>) => {
state.ctime = action.payload
},
setAuthor: (state, action: PayloadAction<string | undefined>) => {
state.author = action.payload
},
setInfos: (state, action: PayloadAction<any[]>) => { setInfos: (state, action: PayloadAction<any[]>) => {
state.infos = action.payload state.infos = action.payload
}, },
@@ -342,6 +349,8 @@ export const {
addAskInfo, addAskInfo,
delAskInfo, delAskInfo,
mergeAskInfo, mergeAskInfo,
setCtime,
setAuthor,
} = slice.actions } = slice.actions
export default slice.reducer export default slice.reducer