import React, {MutableRefObject, useCallback, useEffect, useMemo, useRef} from 'react'
import {useAppDispatch, useAppSelector} from '../hooks/redux'
import {setFloatKeyPointsSegIdx, setPage, setSegmentFold, setTempData} from '../redux/envReducer'
import classNames from 'classnames'
import {FaClipboardList} from 'react-icons/fa'
import {PAGE_MAIN, PAGE_SETTINGS, SUMMARIZE_THRESHOLD, SUMMARIZE_TYPES} from '../const'
import useTranslate from '../hooks/useTranslate'
import {BsDashSquare, BsPlusSquare, CgFileDocument, FaQuestion, GrOverview, RiFileCopy2Line} from 'react-icons/all'
import toast from 'react-hot-toast'
import {getLastTime, getSummaryStr, isSummaryEmpty, parseStrTimeToSeconds} from '../util/biz_util'
import {useInViewport} from 'ahooks'
import SegmentItem from './SegmentItem'
import {stopPopFunc} from '../util/util'
import useSubtitle from '../hooks/useSubtitle'
const SummarizeItemOverview = (props: {
segment: Segment
summary: OverviewSummary
segmentIdx: number
overviewItem: OverviewItem
idx: number
}) => {
const { segment, summary, segmentIdx, overviewItem, idx} = props
const {move} = useSubtitle()
const time = parseStrTimeToSeconds(overviewItem.time)
const currentTime = useAppSelector(state => state.env.currentTime)
const isIn = useMemo(() => {
if (currentTime != null) {
// check in current segment
if (segment.items?.length > 0) {
const startTime = segment.items[0].from
const lastTime = segment.items[segment.items.length - 1].to
if (currentTime >= startTime && currentTime < lastTime) {
// check in current overview item
const nextOverviewItem = summary.content?.[idx + 1]
const nextTime = (nextOverviewItem != null)?parseStrTimeToSeconds(nextOverviewItem.time):null
return currentTime >= time && (nextTime == null || currentTime < nextTime)
}
}
}
return false
}, [currentTime, idx, segment.items, summary.content, time])
const moveCallback = useCallback((event: any) => {
if (event.altKey) { // 复制
navigator.clipboard.writeText(overviewItem.key).catch(console.error)
} else {
move(time, false)
}
}, [overviewItem.key, move, time])
return
{overviewItem.emoji}
{overviewItem.time}
{overviewItem.key}
}
const Summarize = (props: {
segment: Segment
segmentIdx: number
summary?: Summary
float?: boolean
}) => {
const {segment, segmentIdx, summary, float} = props
const dispatch = useAppDispatch()
const envData = useAppSelector(state => state.env.envData)
const fontSize = useAppSelector(state => state.env.envData.fontSize)
const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType)
const {addSummarizeTask} = useTranslate()
const onGenerate = useCallback(() => {
const apiKey = envData.aiType === 'gemini'?envData.geminiApiKey:envData.apiKey
if (apiKey) {
addSummarizeTask(curSummaryType, segment).catch(console.error)
} else {
dispatch(setPage(PAGE_SETTINGS))
toast.error('需要先设置ApiKey!')
}
}, [addSummarizeTask, curSummaryType, dispatch, envData.aiType, envData.apiKey, envData.geminiApiKey, segment])
const onCopy = useCallback(() => {
if (summary != null) {
navigator.clipboard.writeText(getSummaryStr(summary)).then(() => {
toast.success('已复制到剪贴板!')
}).catch(console.error)
}
}, [summary])
return
{(summary != null) && !isSummaryEmpty(summary) &&
}
{summary?.type === 'overview' && (summary.content != null) &&
{(summary.content).map((overviewItem: OverviewItem, idx: number) =>
)}
}
{summary?.type === 'keypoint' && (summary.content != null) &&
{summary.content?.map((keyPoint: string, idx: number) => - {keyPoint}
)}
}
{summary?.type === 'brief' && (summary.content != null) &&
{summary.content.summary}
}
{summary?.type === 'question' && (summary.content != null) &&
{summary.content.map((question: any, idx: number) =>
{question.q}
{question.a}
)}
}
{segment.text.length < SUMMARIZE_THRESHOLD &&
文字过短,无法总结.
}
{segment.text.length >= SUMMARIZE_THRESHOLD && ((summary == null) || summary.status !== 'done' || summary.error) &&
}
{((summary == null) || summary.status === 'init') &&
{SUMMARIZE_TYPES[curSummaryType].desc}
}
{summary?.error &&
{summary?.error}
}
{!float &&
}
}
const SegmentCard = (props: {
bodyRef: MutableRefObject
segment: Segment
segmentIdx: number
}) => {
const {bodyRef, segment, segmentIdx} = props
const dispatch = useAppDispatch()
const summarizeRef = useRef(null)
const [inViewport] = useInViewport(summarizeRef, {
root: bodyRef.current,
})
const segments = useAppSelector(state => state.env.segments)
const needScroll = useAppSelector(state => state.env.needScroll)
const curIdx = useAppSelector(state => state.env.curIdx)
const summarizeEnable = useAppSelector(state => state.env.envData.summarizeEnable)
const summarizeFloat = useAppSelector(state => state.env.envData.summarizeFloat)
const fold = useAppSelector(state => state.env.fold)
const page = useAppSelector(state => state.env.page)
const compact = useAppSelector(state => state.env.tempData.compact)
const floatKeyPointsSegIdx = useAppSelector(state => state.env.floatKeyPointsSegIdx)
const showCurrent = useMemo(() => curIdx != null && segment.startIdx <= curIdx && curIdx <= segment.endIdx, [curIdx, segment.endIdx, segment.startIdx])
const curSummaryType = useAppSelector(state => state.env.tempData.curSummaryType)
const summary = useMemo(() => {
const result = segment.summaries[curSummaryType]
if (result) {
return result
}
return undefined
}, [curSummaryType, segment.summaries])
const onFold = useCallback(() => {
dispatch(setSegmentFold({
segmentStartIdx: segment.startIdx,
fold: !segment.fold
}))
}, [dispatch, segment.fold, segment.startIdx])
// 检测设置floatKeyPointsSegIdx
useEffect(() => {
if (summarizeFloat) { // 已启用
if (!fold && page === PAGE_MAIN && showCurrent) { // 当前Card有控制权
if (!inViewport && (summary != null) && !isSummaryEmpty(summary)) {
dispatch(setFloatKeyPointsSegIdx(segment.startIdx))
} else {
dispatch(setFloatKeyPointsSegIdx())
}
}
}
}, [dispatch, fold, inViewport, page, segment.startIdx, showCurrent, summarizeFloat, summary])
const onSelBrief = useCallback(() => {
dispatch(setTempData({
curSummaryType: 'brief'
}))
}, [dispatch])
const onSelOverview = useCallback(() => {
dispatch(setTempData({
curSummaryType: 'overview'
}))
}, [dispatch])
const onSelKeypoint = useCallback(() => {
dispatch(setTempData({
curSummaryType: 'keypoint'
}))
}, [dispatch])
const onSelQuestion = useCallback(() => {
dispatch(setTempData({
curSummaryType: 'question'
}))
}, [dispatch])
return
{segments != null && segments.length > 0 &&
{segment.fold
? :
}
}
{summarizeEnable &&
}
{getLastTime(segment.items[segment.items.length - 1].to - segment.items[0].from)}
{summarizeEnable &&
}
{!segment.fold
?
{!compact &&
}
{segment.items.map((item: TranscriptItem, idx: number) =>
)}
{segments != null && segments.length > 0 &&
}
:
}
{floatKeyPointsSegIdx === segment.startIdx &&
}
}
export default SegmentCard