flat: 暂存

This commit is contained in:
史典卓
2025-04-10 10:59:25 +08:00
parent b98e1d5405
commit 0d2b8ae65f
103 changed files with 461 additions and 189 deletions

View File

@@ -8,24 +8,7 @@ import {
onUnload
} from '@dcloudio/uni-app'
function formatTextForSpeech(rawText) {
return rawText
// 去除链接 markdown 格式 [xxx](url)
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
// 去除 Markdown 语法符号
.replace(/[*_`>#\-]/g, '')
// 将换行转换为句号
.replace(/\n+/g, '。')
// 多个标点统一转为句号(表示停顿)
.replace(/[。,,.、!?;:~~…··\-\/\\]{1,}/g, '。')
// 合并多个句号
.replace(/([。]{2,})/g, '。')
// 去除多余空格
.replace(/\s+/g, ' ')
// 去除开头结尾的句号
.replace(/^[。]+|[。]+$/g, '')
.trim()
}
export function useSpeechReader() {
const isSpeaking = ref(false)
@@ -41,14 +24,12 @@ export function useSpeechReader() {
rate: 0.9,
pitch: 1.2
}) => {
cancel() // 重置之前的
const voices = speechSynthesis.getVoices()
const chineseVoices = voices.filter(v => v.lang.includes('zh'))
// console.log(chineseVoices.map((item) => item.name))
const cleanText = cleanMarkdown(text)
utterance = new SpeechSynthesisUtterance(cleanText)
// utterance.voice = chineseVoices.find(v => v.name === 'Shelley')
utterance.lang = options.lang || 'zh-CN'
cancelAudio() // 重置之前的
// const voices = speechSynthesis.getVoices()
// const chineseVoices = voices.filter(v => v.lang.includes('zh'))
const speechText = extractSpeechText(text);
utterance = new SpeechSynthesisUtterance(speechText)
// utterance.lang = options.lang || 'zh'
utterance.rate = options.rate || 1
utterance.pitch = options.pitch || 1.1 // 音调0 - 2偏高比较柔和
@@ -76,7 +57,7 @@ export function useSpeechReader() {
}
}
const cancel = () => {
const cancelAudio = () => {
speechSynthesis.cancel()
isSpeaking.value = false
isPaused.value = false
@@ -84,26 +65,72 @@ export function useSpeechReader() {
// 页面刷新/关闭时
onMounted(() => {
if (typeof window !== 'undefined') {
window.addEventListener('beforeunload', cancel)
window.addEventListener('beforeunload', cancelAudio)
}
})
onBeforeUnmount(() => {
cancel()
cancelAudio()
if (typeof window !== 'undefined') {
window.removeEventListener('beforeunload', cancel)
window.removeEventListener('beforeunload', cancelAudio)
}
})
onHide(cancel)
onUnload(cancel)
onHide(cancelAudio)
onUnload(cancelAudio)
return {
speak,
pause,
resume,
cancel,
cancelAudio,
isSpeaking,
isPaused,
}
}
function extractSpeechText(markdown) {
const jobRegex = /``` job-json\s*({[\s\S]*?})\s*```/g;
const jobs = [];
let match;
let lastJobEndIndex = 0;
let firstJobStartIndex = -1;
// 提取岗位 json 数据及前后位置
while ((match = jobRegex.exec(markdown)) !== null) {
const jobStr = match[1];
try {
const job = JSON.parse(jobStr);
jobs.push(job);
if (firstJobStartIndex === -1) {
firstJobStartIndex = match.index;
}
lastJobEndIndex = jobRegex.lastIndex;
} catch (e) {
console.warn('JSON 解析失败', e);
}
}
// 提取引导语(第一个 job-json 之前的文字)
const guideText = firstJobStartIndex > 0 ?
markdown.slice(0, firstJobStartIndex).trim() :
'';
// 提取结束语(最后一个 job-json 之后的文字)
const endingText = lastJobEndIndex < markdown.length ?
markdown.slice(lastJobEndIndex).trim() :
'';
// 岗位信息格式化为语音文本
const jobTexts = jobs.map((job, index) => {
return `${index + 1} 个岗位,岗位名称是:${job.jobTitle},公司是:${job.companyName},薪资:${job.salary},地点:${job.location},学历要求:${job.education},经验要求:${job.experience}`;
});
// 拼接总语音内容
const finalTextParts = [];
if (guideText) finalTextParts.push(guideText);
finalTextParts.push(...jobTexts);
if (endingText) finalTextParts.push(endingText);
return finalTextParts.join('\n');
}