复制总结内容优化

This commit is contained in:
IndieKKY
2023-06-02 09:23:08 +08:00
parent aa6088e04e
commit 098506be33
7 changed files with 52 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
{ {
"name": "哔哩哔哩字幕列表", "name": "哔哩哔哩字幕列表",
"description": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!", "description": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!",
"version": "1.6.8", "version": "1.7.0",
"manifest_version": 3, "manifest_version": 3,
"permissions": [ "permissions": [
"storage" "storage"

View File

@@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"name": "bilibili-subtitle", "name": "bilibili-subtitle",
"version": "1.6.5", "version": "1.7.0",
"type": "module", "type": "module",
"description": "哔哩哔哩字幕列表", "description": "哔哩哔哩字幕列表",
"main": "index.js", "main": "index.js",

View File

@@ -10,13 +10,14 @@ import {
setSegmentFold setSegmentFold
} from '../redux/envReducer' } from '../redux/envReducer'
import {useAppDispatch, useAppSelector} from '../hooks/redux' import {useAppDispatch, useAppSelector} from '../hooks/redux'
import {AiOutlineAim, FaRegArrowAltCircleDown, IoWarning, MdExpand, RiTranslate} from 'react-icons/all' import {AiOutlineAim, FaRegArrowAltCircleDown, IoWarning, MdExpand, RiFileCopy2Line, RiTranslate} from 'react-icons/all'
import classNames from 'classnames' import classNames from 'classnames'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import SegmentCard from './SegmentCard' import SegmentCard from './SegmentCard'
import {HEADER_HEIGHT, PAGE_SETTINGS, SUMMARIZE_ALL_THRESHOLD, TITLE_HEIGHT} from '../const' import {HEADER_HEIGHT, PAGE_SETTINGS, SUMMARIZE_ALL_THRESHOLD, SUMMARIZE_TYPES, TITLE_HEIGHT} from '../const'
import {FaClipboardList} from 'react-icons/fa' import {FaClipboardList} from 'react-icons/fa'
import useTranslate from '../hooks/useTranslate' import useTranslate from '../hooks/useTranslate'
import {getSummarize} from '../util/biz_util'
const Body = () => { const Body = () => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@@ -38,6 +39,7 @@ const Body = () => {
const needScroll = useAppSelector(state => state.env.needScroll) const needScroll = useAppSelector(state => state.env.needScroll)
const totalHeight = useAppSelector(state => state.env.totalHeight) const totalHeight = useAppSelector(state => state.env.totalHeight)
const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType) const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType)
const title = useAppSelector(state => state.env.title)
const normalCallback = useCallback(() => { const normalCallback = useCallback(() => {
dispatch(setCompact(false)) dispatch(setCompact(false))
@@ -106,6 +108,15 @@ const Body = () => {
} }
}, [autoScroll, dispatch]) }, [autoScroll, dispatch])
const onCopy = useCallback(() => {
const [success, content] = getSummarize(title, segments, curSummaryType)
if (success) {
navigator.clipboard.writeText(content).then(() => {
toast.success('复制成功')
}).catch(console.error)
}
}, [curSummaryType, segments, title])
// 自动滚动 // 自动滚动
useEffect(() => { useEffect(() => {
if (checkAutoScroll && curOffsetTop && autoScroll && !needScroll) { if (checkAutoScroll && curOffsetTop && autoScroll && !needScroll) {
@@ -160,6 +171,11 @@ const Body = () => {
}} }}
> >
{segments?.map((segment, segmentIdx) => <SegmentCard key={segment.startIdx} segment={segment} segmentIdx={segmentIdx} bodyRef={bodyRef}/>)} {segments?.map((segment, segmentIdx) => <SegmentCard key={segment.startIdx} segment={segment} segmentIdx={segmentIdx} bodyRef={bodyRef}/>)}
<div className='flex flex-col items-center text-center pt-1 pb-2'>
<div className='font-semibold text-accent'>💡<span className='underline underline-offset-4'></span>💡</div>
<div className='text-sm desc px-2'><span className='text-amber-600 font-semibold'></span><span className='text-secondary/75 font-semibold'></span>🥳</div>
{(segments?.length??0) > 0 && <button className='mt-1.5 btn btn-xs btn-info' onClick={onCopy}>{SUMMARIZE_TYPES[curSummaryType].name}<RiFileCopy2Line/></button>}
</div>
</div> </div>
</div> </div>
} }

View File

@@ -3,7 +3,7 @@ import {useAppDispatch, useAppSelector} from '../hooks/redux'
import {setFloatKeyPointsSegIdx, setPage, setSegmentFold, setTempData} from '../redux/envReducer' import {setFloatKeyPointsSegIdx, setPage, setSegmentFold, setTempData} from '../redux/envReducer'
import classNames from 'classnames' import classNames from 'classnames'
import {FaClipboardList} from 'react-icons/fa' import {FaClipboardList} from 'react-icons/fa'
import {PAGE_MAIN, PAGE_SETTINGS, SUMMARIZE_THRESHOLD} from '../const' import {PAGE_MAIN, PAGE_SETTINGS, SUMMARIZE_THRESHOLD, SUMMARIZE_TYPES} from '../const'
import useTranslate from '../hooks/useTranslate' import useTranslate from '../hooks/useTranslate'
import {BsDashSquare, BsPlusSquare, CgFileDocument, GrOverview, RiFileCopy2Line} from 'react-icons/all' import {BsDashSquare, BsPlusSquare, CgFileDocument, GrOverview, RiFileCopy2Line} from 'react-icons/all'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
@@ -112,6 +112,7 @@ const Summarize = (props: {
{segment.text.length >= SUMMARIZE_THRESHOLD && ((summary == null) || summary.status !== 'done' || summary.error) && <button disabled={summary?.status === 'pending'} {segment.text.length >= SUMMARIZE_THRESHOLD && ((summary == null) || summary.status !== 'done' || summary.error) && <button disabled={summary?.status === 'pending'}
className={classNames('btn btn-link btn-xs', summary?.status === 'pending' && 'loading')} className={classNames('btn btn-link btn-xs', summary?.status === 'pending' && 'loading')}
onClick={onGenerate}>{(summary == null) || summary.status === 'init' ? '点击生成' : (summary.status === 'pending' ? '生成中' : '重新生成')}</button>} onClick={onGenerate}>{(summary == null) || summary.status === 'init' ? '点击生成' : (summary.status === 'pending' ? '生成中' : '重新生成')}</button>}
{((summary == null) || summary.status === 'init') && <div className='desc-lighter text-xs'>{SUMMARIZE_TYPES[curSummaryType].desc}</div>}
{summary?.error && <div className='text-xs text-error'>{summary?.error}</div>} {summary?.error && <div className='text-xs text-error'>{summary?.error}</div>}
</div> </div>
{!float && <div className='mx-2 my-1 h-[1px] bg-base-300'></div>} {!float && <div className='mx-2 my-1 h-[1px] bg-base-300'></div>}

View File

@@ -23,10 +23,25 @@ export const PROMPT_TYPES = [{
type: PROMPT_TYPE_SUMMARIZE_BRIEF, type: PROMPT_TYPE_SUMMARIZE_BRIEF,
}] }]
export const SUMMARIZE_TYPE_TO_PROMPT_TYPE = { export const SUMMARIZE_TYPES = {
overview: PROMPT_TYPE_SUMMARIZE_OVERVIEW, brief: {
keypoint: PROMPT_TYPE_SUMMARIZE_KEYPOINT, name: '总结',
brief: PROMPT_TYPE_SUMMARIZE_BRIEF, desc: '一句话总结',
downloadName: '💡视频总结💡',
promptType: PROMPT_TYPE_SUMMARIZE_BRIEF,
},
overview: {
name: '概览',
desc: '可定位到视频位置',
downloadName: '💡视频概览💡',
promptType: PROMPT_TYPE_SUMMARIZE_OVERVIEW,
},
keypoint: {
name: '要点',
desc: '完整的要点提取',
downloadName: '💡视频要点💡',
promptType: PROMPT_TYPE_SUMMARIZE_KEYPOINT,
},
} }
export const PROMPT_DEFAULTS = { export const PROMPT_DEFAULTS = {

View File

@@ -17,7 +17,7 @@ import {
PROMPT_TYPE_TRANSLATE, PROMPT_TYPE_TRANSLATE,
SUMMARIZE_LANGUAGE_DEFAULT, SUMMARIZE_LANGUAGE_DEFAULT,
SUMMARIZE_THRESHOLD, SUMMARIZE_THRESHOLD,
SUMMARIZE_TYPE_TO_PROMPT_TYPE, SUMMARIZE_TYPES,
TRANSLATE_COOLDOWN, TRANSLATE_COOLDOWN,
TRANSLATE_FETCH_DEFAULT, TRANSLATE_FETCH_DEFAULT,
} from '../const' } from '../const'
@@ -125,7 +125,7 @@ const useTranslate = () => {
subtitles += formatTime(item.from) + ' ' + item.content + '\n' subtitles += formatTime(item.from) + ' ' + item.content + '\n'
} }
// @ts-expect-error // @ts-expect-error
const promptType: keyof typeof PROMPT_DEFAULTS = SUMMARIZE_TYPE_TO_PROMPT_TYPE[type] const promptType: keyof typeof PROMPT_DEFAULTS = SUMMARIZE_TYPES[type].promptType
let prompt: string = envData.prompts?.[promptType]??PROMPT_DEFAULTS[promptType] let prompt: string = envData.prompts?.[promptType]??PROMPT_DEFAULTS[promptType]
// replace params // replace params
prompt = prompt.replaceAll('{{language}}', summarizeLanguage.name) prompt = prompt.replaceAll('{{language}}', summarizeLanguage.name)

View File

@@ -1,5 +1,5 @@
import devData from '../data/data.json' import devData from '../data/data.json'
import {APP_DOM_ID} from '../const' import {APP_DOM_ID, SUMMARIZE_TYPES} from '../const'
import {isDarkMode} from '@kky002/kky-util' import {isDarkMode} from '@kky002/kky-util'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import {findIndex} from 'lodash-es' import {findIndex} from 'lodash-es'
@@ -108,7 +108,7 @@ export const getSummaryStr = (summary: Summary) => {
const content: { summary: string } = summary.content ?? { const content: { summary: string } = summary.content ?? {
summary: '' summary: ''
} }
s += content.summary s += content.summary + '\n'
} }
return s return s
} }
@@ -148,23 +148,23 @@ export const getSummarize = (title: string | undefined, segments: Segment[] | un
return [false, ''] return [false, '']
} }
let content = `${title ?? ''}\n\n` let content = `${SUMMARIZE_TYPES[type]?.downloadName ?? ''}\n\n`
let success = false let success = false
for (const segment of segments) { for (const segment of segments) {
if (segment.items.length > 0) {
content += `${getTimeDisplay(segment.items[0].from)}\n`
}
const summary = segment.summaries[type] const summary = segment.summaries[type]
if (summary && !isSummaryEmpty(summary)) { if (summary && !isSummaryEmpty(summary)) {
success = true success = true
content += getSummaryStr(summary) content += getSummaryStr(summary)
} else { } else {
content += '无总结\n' if (segment.items.length > 0) {
content += `${getTimeDisplay(segment.items[0].from)} `
}
content += '未总结\n'
} }
content += '\n'
} }
content += '\n--- 哔哩哔哩字幕列表'
if (!success) { if (!success) {
toast.error('未找到总结') toast.error('未找到总结')
} }