代码实现(HTML+JavaScript整合版)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>职场会议无效沟通过滤工具</title>
<style>
body { font-family: "Microsoft YaHei", sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.container { display: flex; flex-direction: column; gap: 15px; }
button { padding: 10px 20px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:disabled { background: #90CAF9; }
textarea { width: 100%; height: 120px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
.result-box { border: 1px solid #eee; padding: 15px; border-radius: 4px; background: #f9f9f9; }
.section { margin: 10px 0; }
.keyword { color: #2196F3; font-weight: bold; }
</style>
</head>
<body>
<div class="container">
<h1>职场会议无效沟通过滤工具</h1>
<button id="startRecord">开始录音</button>
<button id="stopRecord" disabled>停止录音</button>
<textarea id="rawText" placeholder="录音转文字结果将显示在这里..." readonly></textarea>
<div class="result-box">
<h3>精简纪要</h3>
<div class="section"><strong>核心结论:</strong><div id="conclusions"></div></div>
<div class="section"><strong>行动项:</strong><div id="actionItems"></div></div>
<div class="section"><strong>过滤统计:</strong><div id="filterStats"></div></div>
</div>
</div>
<script>
// ==================== 核心模块 ====================
// 全局变量
let recognition = null;
let rawTranscript = '';
const irrelevantKeywords = ['天气', '午餐', '下班', '周末', '闲聊', '八卦']; // 无关话题关键词库
const actionItemRegex = /(负责人[::]?\s*(\w+).*?任务[::]?\s*(.+?)(?:截止[::]?\s*(\d{4}-\d{2}-\d{2}))?)/gi;
// 1. 录音控制模块
function initRecorder() {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) throw new Error("浏览器不支持语音识别(推荐Chrome)");
recognition = new SpeechRecognition();
recognition.continuous = true; // 持续录音
recognition.interimResults = true; // 实时返回临时结果
recognition.lang = 'zh-CN';
// 录音结果处理
recognition.onresult = (event) => {
let interimTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
const transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) rawTranscript += transcript;
else interimTranscript += transcript;
}
document.getElementById('rawText').value = rawTranscript + interimTranscript;
};
recognition.onerror = (event) => {
console.error("录音错误:", event.error);
alert("录音失败: " + event.error);
};
}
// 2. 文本预处理模块
function preprocessText(text) {
return text.replace(/\s+/g, '') // 去除空格
.replace(/[^\u4e00-\u9fa5a-zA-Z0-9,。;:]/g, '') // 保留中文、英文、数字及标点
.split(/[。;]/) // 按句号分号分句
.filter(sentence => sentence.length > 5); // 过滤短句
}
// 3. 重复表述识别模块(基于余弦相似度)
function findDuplicates(sentences) {
const duplicates = [];
for (let i = 0; i < sentences.length; i++) {
for (let j = i + 1; j < sentences.length; j++) {
if (calculateSimilarity(sentences[i], sentences[j]) > 0.8) {
duplicates.push(j); // 标记重复句索引
break;
}
}
}
return [...new Set(duplicates)]; // 去重
}
// 余弦相似度计算(简化版)
function calculateSimilarity(str1, str2) {
const words1 = str1.split(''), words2 = str2.split('');
const set = new Set([...words1, ...words2]);
const vec1 = [...set].map(char => str1.split(char).length - 1);
const vec2 = [...set].map(char => str2.split(char).length - 1);
const dot = vec1.reduce((sum, v, i) => sum + v * vec2[i], 0);
const norm1 = Math.sqrt(vec1.reduce((sum, v) => sum + v * v, 0));
const norm2 = Math.sqrt(vec2.reduce((sum, v) => sum + v * v, 0));
return dot / (norm1 * norm2) || 0;
}
// 4. 无关话题过滤模块
function filterIrrelevant(sentences) {
return sentences.filter(sentence =>
!irrelevantKeywords.some(keyword => sentence.includes(keyword))
);
}
// 5. 核心结论提取模块(关键词匹配)
function extractConclusions(sentences) {
const conclusionKeywords = ['结论', '决定', '共识', '总结', '因此'];
return sentences.filter(sentence =>
conclusionKeywords.some(kw => sentence.includes(kw))
).map(s => s.replace(/^.*?(结论|决定|共识|总结|因此)[::]?\s*/, '$1:'));
}
// 6. 行动项提取模块(正则匹配)
function extractActionItems(text) {
const items = [];
let match;
while ((match = actionItemRegex.exec(text)) !== null) {
items.push({
负责人: match[2] || '待明确',
任务: match[3],
截止时间: match[4] || '待明确'
});
}
return items;
}
// 7. 纪要生成模块
function generateMinutes(rawText) {
const sentences = preprocessText(rawText);
const duplicateIndices = findDuplicates(sentences);
const filteredSentences = sentences.filter((_, i) => !duplicateIndices.includes(i));
const relevantSentences = filterIrrelevant(filteredSentences);
const conclusions = extractConclusions(relevantSentences);
const actionItems = extractActionItems(rawText);
return {
conclusions,
actionItems,
stats: {
原始句数: sentences.length,
重复句数: duplicateIndices.length,
无关句数: sentences.length - relevantSentences.length,
有效句数: relevantSentences.length
}
};
}
// ==================== 交互逻辑 ====================
document.getElementById('startRecord').addEventListener('click', () => {
try {
initRecorder();
recognition.start();
document.getElementById('startRecord').disabled = true;
document.getElementById('stopRecord').disabled = false;
rawTranscript = '';
document.getElementById('rawText').value = '';
} catch (err) {
alert("初始化失败: " + err.message);
}
});
document.getElementById('stopRecord').addEventListener('click', () => {
recognition.stop();
document.getElementById('startRecord').disabled = false;
document.getElementById('stopRecord').disabled = true;
// 生成纪要
const minutes = generateMinutes(rawTranscript);
document.getElementById('conclusions').innerHTML = minutes.conclusions.map(c =>
`<div class="keyword">• ${c}</div>`
).join('');
document.getElementById('actionItems').innerHTML = minutes.actionItems.map(item =>
`<div>• 负责人: ${item.负责人}, 任务: ${item.任务}, 截止: ${item.截止时间}</div>`
).join('');
document.getElementById('filterStats').innerHTML = `
原始句数: ${minutes.stats.原始句数},
重复过滤: ${minutes.stats.重复句数},
无关过滤: ${minutes.stats.无关句数},
有效句数: ${minutes.stats.有效句数}
`;
});
</script>
</body>
</html>
README文件
# 职场会议无效沟通过滤工具
## 简介
通过录音转文字+NLP分析,自动过滤会议中的重复表述与无关话题,提取核心结论与行动项,生成精简纪要,提升复盘效率。
## 安装与使用
1. **环境要求**:Chrome浏览器(支持Web Speech API)、麦克风权限。
2. **启动方式**:直接打开`index.html`,点击「开始录音」授权麦克风。
3. **操作流程**:
- 点击「开始录音」→ 进行会议录音;
- 结束后点击「停止录音」→ 自动转文字并处理;
- 右侧显示精简纪要(核心结论+行动项+过滤统计)。
## 核心模块
| 模块名 | 功能 |
|----------------------|---------------------------------------|
| initRecorder | 初始化录音(Web Speech API) |
| preprocessText | 文本清洗与分句 |
| findDuplicates | 余弦相似度识别重复表述 |
| filterIrrelevant | 关键词库过滤无关话题 |
| extractConclusions | 关键词匹配提取核心结论 |
| extractActionItems | 正则提取行动项(负责人/任务/截止时间) |
| generateMinutes | 整合处理结果生成结构化纪要 |
## 依赖说明
- 浏览器内置API:Web Speech API(语音识别)、LocalStorage(可选存储)。
使用说明
1. 权限准备:首次使用需在浏览器地址栏允许麦克风权限(锁图标→网站设置→麦克风→允许)。
2. 录音操作:点击「开始录音」后正常开会,结束时点击「停止录音」。
3. 结果解读:
- 核心结论:含“结论/决定/共识”等关键词的总结性语句;
- 行动项:自动提取“负责人-任务-截止时间”三要素;
- 过滤统计:显示原始句数、重复/无关过滤数量。
4. 自定义调整:修改代码中
"irrelevantKeywords"数组(添加无关话题关键词)或
"actionItemRegex"正则(调整行动项格式)。
核心知识点卡片
1. 模块化架构设计
- 定义:将系统拆分为独立功能模块(录音、预处理、过滤、提取、生成),降低耦合度。
- 应用:本工具用7个函数拆分会议处理全流程,如
"findDuplicates"专注重复识别。
- 关联课程:战略管理中的分工协作理论(各模块专注单一目标,提升整体效能)。
2. 语音转文字技术赋能
- 定义:利用Web Speech API将音频流实时转为文本,突破人工记录效率瓶颈。
- 应用:通过
"recognition.onresult"回调实现边录边转,支持持续录音模式。
- 关联课程:创新思维中的技术驱动效率革新(用AI替代低价值转录工作)。
3. 重复表述过滤机制
- 定义:基于余弦相似度算法(字符向量点积)量化句子重复度,阈值>0.8标记为重复。
- 应用:
"findDuplicates"函数对比所有句子,过滤冗余信息(如多人重复强调同一观点)。
- 关联课程:创新思维中的精益沟通原则(消除浪费,保留核心价值)。
4. 目标导向的结论提取
- 定义:通过关键词匹配(“结论/决定/共识”)锁定会议核心产出,避免被过程讨论淹没。
- 应用:
"extractConclusions"函数用关键词过滤,聚焦决策层信息。
- 关联课程:战略管理中的目标聚焦理论(以终为始,优先关注关键成果)。
5. 行动项结构化沉淀
- 定义:用正则表达式提取“负责人-任务-截止时间”三要素,转化为可执行清单。
- 应用:
"actionItemRegex"匹配“负责人:张三 任务:完成报告 截止:2025-12-20”类语句。
- 关联课程:战略管理中的PDCA循环(通过结构化行动项推动计划落地与复盘)。
关注我,有更多编程干货等着你!