智能洞察 Cordova 与 OpenHarmony 混合开发实战
智能洞察功能通过AI算法分析笔记数据,提供更新建议和内容优化提示。实现流程包括数据收集、分析处理和结果展示,支持Web(JavaScript)和OpenHarmony(TypeScript)两种开发方式。Web端可检测长时间未更新或内容过少的笔记,原生端则提供笔记创建引导。该功能展示了混合开发中智能分析模块的实现方案,帮助用户优化笔记管理效率。
📌 模块概述
智能洞察功能基于多维度 AI 算法分析笔记全量数据,在基础更新提醒和字数分析的基础上,新增内容主题识别、创作行为分析、笔记关联推荐、关键词提取、创作趋势预测等深度洞察能力,为用户提供个性化的笔记管理建议和创作指引,帮助提升笔记质量和创作效率。
🔗 完整流程
第一步:多维度数据采集与分析
采集笔记内容、更新频率、分类分布、字数变化、关键词等全维度数据;
通过 AI 算法识别笔记主题、情感倾向、内容完整性、关联度等特征。
第二步:分层级洞察生成
基础洞察:更新提醒、字数分析、分类分布等;
进阶洞察:主题标签推荐、相似笔记关联、创作高峰时段分析;
个性化建议:内容完善指引、分类优化方案、创作效率提升建议。
第三步:可视化展示与交互
按洞察类型分类展示,支持洞察详情展开 / 收起;
提供一键优化操作(如添加标签、合并相似笔记);
展示创作趋势图表,直观呈现笔记创作规律。
🔧 Web代码实现
// 智能洞察页面(扩展版)
async renderInsights() {
const allNotes = await noteDB.getAllNotes();
// 调用增强版洞察生成方法
const insights = this.generateEnhancedInsights(allNotes);
// 分类整理洞察(基础/进阶/建议)
const basicInsights = insights.filter(ins => ins.type === 'basic');
const advancedInsights = insights.filter(ins => ins.type === 'advanced');
const suggestionInsights = insights.filter(ins => ins.type === 'suggestion');
return `
<div class="page active">
<div class="page-header">
<h1 class="page-title">💡 智能洞察</h1>
<button class="btn btn-outline" onclick="app.refreshInsights()" style="margin-left: 8px;">
刷新洞察
</button>
</div>
<!-- 创作概览卡片 -->
<div class="insights-overview" style="margin: 16px 0; display: flex; gap: 12px; flex-wrap: wrap;">
<div class="overview-card">
<p class="card-label">总笔记数</p>
<p class="card-value">${allNotes.length}</p>
</div>
<div class="overview-card">
<p class="card-label">总字数</p>
<p class="card-value">${allNotes.reduce((sum, n) => sum + (n.wordCount || 0), 0).toLocaleString()}</p>
</div>
<div class="overview-card">
<p class="card-label">活跃分类数</p>
<p class="card-value">${new Set(allNotes.map(n => n.category)).size}</p>
</div>
<div class="overview-card">
<p class="card-label">平均更新周期</p>
<p class="card-value">${this.calculateAvgUpdateCycle(allNotes)} 天</p>
</div>
</div>
<!-- 基础洞察 -->
<div class="insights-section">
<h3>📋 基础洞察</h3>
<div class="insights-list">
${basicInsights.map((insight, index) => `
<div class="insight-item" onclick="app.toggleInsightDetail(${index})">
<div class="insight-header">
<h4>${insight.title}</h4>
<span class="insight-icon">▼</span>
</div>
<div class="insight-description">${insight.description}</div>
<div class="insight-detail" id="detail-${index}" style="display: none;">
${insight.detail || '暂无详细信息'}
</div>
</div>
`).join('') || '<div class="empty-state">暂无基础洞察</div>'}
</div>
</div>
<!-- 进阶洞察 -->
<div class="insights-section" style="margin-top: 16px;">
<h3>📊 进阶分析</h3>
<div class="insights-list">
${advancedInsights.map((insight, index) => `
<div class="insight-item">
<h4>${insight.title}</h4>
<p>${insight.description}</p>
${insight.action ? `<button class="btn btn-sm" onclick="${insight.action}">${insight.actionText}</button>` : ''}
</div>
`).join('') || '<div class="empty-state">暂无进阶分析</div>'}
</div>
</div>
<!-- 个性化建议 -->
<div class="insights-section" style="margin-top: 16px;">
<h3>🎯 优化建议</h3>
<div class="insights-list">
${suggestionInsights.map(insight => `
<div class="insight-item suggestion">
<h4>${insight.title}</h4>
<p>${insight.description}</p>
</div>
`).join('') || '<div class="empty-state">暂无优化建议</div>'}
</div>
</div>
</div>
`;
}
// 生成增强版智能洞察
generateEnhancedInsights(notes) {
const insights = [];
const now = Date.now();
// 1. 基础洞察 - 长时间未更新的笔记
const oldNotes = notes.filter(note => {
const daysSinceUpdate = (now - new Date(note.updatedAt || note.createdAt).getTime()) / (1000 * 60 * 60 * 24);
return daysSinceUpdate > 30;
});
if (oldNotes.length > 0) {
const noteTitles = oldNotes.slice(0, 3).map(n => n.title).join('、');
const moreCount = oldNotes.length > 3 ? `等${oldNotes.length}个` : '';
insights.push({
type: 'basic',
title: '有笔记需要更新',
description: `您有 ${oldNotes.length} 个笔记超过30天未更新,建议检查并更新。`,
detail: `长时间未更新的笔记包括:${noteTitles}${moreCount}。定期更新笔记有助于保持内容的时效性和完整性。`
});
}
// 2. 基础洞察 - 笔记内容分析
if (notes.length > 0) {
const avgWords = Math.round(notes.reduce((sum, note) => sum + (note.wordCount || 0), 0) / notes.length);
if (avgWords < 100) {
insights.push({
type: 'basic',
title: '笔记内容偏简短',
description: `您的笔记平均字数为 ${avgWords} 字,低于平均水平。`,
detail: '简短的笔记可能无法完整记录信息,建议针对核心笔记补充更多细节、案例或思考,提升笔记的实用价值。'
});
} else if (avgWords > 500) {
insights.push({
type: 'basic',
title: '笔记内容丰富',
description: `您的笔记平均字数为 ${avgWords} 字,内容较为丰富。`,
detail: '丰富的笔记内容有助于完整记录信息,但建议对长笔记进行结构化整理(如分段、加标题),提升可读性。'
});
}
}
// 3. 进阶洞察 - 分类分布分析
const categoryCount = {};
notes.forEach(note => {
const category = note.category || '未分类';
categoryCount[category] = (categoryCount[category] || 0) + 1;
});
const maxCategory = Object.entries(categoryCount).sort((a, b) => b[1] - a[1])[0];
if (maxCategory && maxCategory[1] > notes.length * 0.5) {
insights.push({
type: 'advanced',
title: '分类分布不均',
description: `您的 "${maxCategory[0]}" 分类包含 ${maxCategory[1]} 个笔记,占总数的 ${Math.round(maxCategory[1]/notes.length*100)}%。`,
action: 'app.suggestCategoryOptimization()',
actionText: '优化分类'
});
}
// 4. 进阶洞察 - 创作高峰时段
const hourCount = Array(24).fill(0);
notes.forEach(note => {
const hour = new Date(note.createdAt).getHours();
hourCount[hour]++;
});
const peakHour = hourCount.indexOf(Math.max(...hourCount));
if (Math.max(...hourCount) > 0) {
insights.push({
type: 'advanced',
title: '创作高峰时段',
description: `您通常在 ${peakHour}:00-${peakHour+1}:00 创作笔记,该时段创建了 ${Math.max(...hourCount)} 个笔记。`,
detail: '建议利用创作高峰时段处理重要的笔记创作,低峰时段可用于整理和编辑已有笔记。'
});
}
// 5. 进阶洞察 - 关键词提取
const allContent = notes.map(n => n.content || '').join(' ');
const keywords = this.extractKeywords(allContent, 5);
if (keywords.length > 0) {
insights.push({
type: 'advanced',
title: '核心关键词',
description: `您的笔记中高频出现的关键词:${keywords.join('、')}。`,
action: 'app.addKeywordsAsTags()',
actionText: '添加为标签'
});
}
// 6. 个性化建议 - 未分类笔记
const uncategorizedNotes = notes.filter(n => !n.category || n.category === '未分类');
if (uncategorizedNotes.length > 3) {
insights.push({
type: 'suggestion',
title: '整理未分类笔记',
description: `您有 ${uncategorizedNotes.length} 个笔记未分类,建议创建合适的分类并归类,提升查找效率。`
});
}
// 7. 个性化建议 - 重复内容检测
const similarNotes = this.detectSimilarNotes(notes);
if (similarNotes.length > 0) {
insights.push({
type: 'suggestion',
title: '检测到相似笔记',
description: `发现 ${similarNotes.length} 组相似笔记,建议合并或整理,避免内容冗余。`
});
}
return insights;
}
// 辅助方法:计算平均更新周期
calculateAvgUpdateCycle(notes) {
if (notes.length === 0) return 0;
const updateIntervals = notes
.filter(n => n.createdAt && n.updatedAt)
.map(n => (new Date(n.updatedAt).getTime() - new Date(n.createdAt).getTime()) / (1000 * 60 * 60 * 24));
return updateIntervals.length > 0
? Math.round(updateIntervals.reduce((sum, val) => sum + val, 0) / updateIntervals.length)
: 0;
}
// 辅助方法:简单关键词提取(基于词频)
extractKeywords(text, limit = 5) {
if (!text) return [];
// 过滤停用词和特殊字符
const stopWords = ['的', '了', '是', '我', '你', '他', '在', '有', '和', '就', '都', '而', '及', '与'];
const cleanText = text.replace(/[^\u4e00-\u9fa5a-zA-Z]/g, ' ').toLowerCase();
// 分词并统计词频
const words = cleanText.split(/\s+/).filter(w => w.length > 1 && !stopWords.includes(w));
const wordCount = {};
words.forEach(word => {
wordCount[word] = (wordCount[word] || 0) + 1;
});
// 按词频排序取前N个
return Object.entries(wordCount)
.sort((a, b) => b[1] - a[1])
.slice(0, limit)
.map(entry => entry[0]);
}
// 辅助方法:简单相似笔记检测(基于标题相似度)
detectSimilarNotes(notes) {
const similarGroups = [];
const processed = new Set();
for (let i = 0; i < notes.length; i++) {
if (processed.has(i) || !notes[i].title) continue;
const group = [notes[i]];
for (let j = i + 1; j < notes.length; j++) {
if (processed.has(j) || !notes[j].title) continue;
// 简单的标题相似度计算(编辑距离)
const similarity = this.calculateTitleSimilarity(notes[i].title, notes[j].title);
if (similarity > 0.8) {
group.push(notes[j]);
processed.add(j);
}
}
if (group.length > 1) {
similarGroups.push(group);
}
processed.add(i);
}
return similarGroups;
}
// 辅助方法:计算标题相似度(简单编辑距离)
calculateTitleSimilarity(title1, title2) {
const maxLen = Math.max(title1.length, title2.length);
const minLen = Math.min(title1.length, title2.length);
let matchCount = 0;
for (let i = 0; i < minLen; i++) {
if (title1[i] === title2[i]) matchCount++;
}
return matchCount / maxLen;
}
// 交互方法:切换洞察详情
toggleInsightDetail(index) {
const detailEl = document.getElementById(`detail-${index}`);
const iconEl = detailEl?.parentNode?.querySelector('.insight-icon');
if (detailEl) {
detailEl.style.display = detailEl.style.display === 'none' ? 'block' : 'none';
if (iconEl) {
iconEl.textContent = detailEl.style.display === 'none' ? '▼' : '▲';
}
}
}
// 交互方法:刷新洞察
async refreshInsights() {
Utils.showToast('正在重新分析数据...', 'loading');
await this.renderInsights();
Utils.showToast('洞察已更新', 'success');
}
// 交互方法:分类优化建议
suggestCategoryOptimization() {
Utils.showToast('已为您生成分类优化方案,即将跳转至分类管理页面', 'info');
// 实际项目中可跳转至分类管理页面
}
// 交互方法:添加关键词为标签
addKeywordsAsTags() {
Utils.showToast('关键词已自动添加为笔记标签', 'success');
// 实际项目中可执行添加标签逻辑
}
// 挂载全局方法
window.app = {
...window.app,
renderInsights: () => this.renderInsights(),
toggleInsightDetail: (index) => this.toggleInsightDetail(index),
refreshInsights: () => this.refreshInsights(),
suggestCategoryOptimization: () => this.suggestCategoryOptimization(),
addKeywordsAsTags: () => this.addKeywordsAsTags()
};
🔌 OpenHarmony 原生代码
// InsightsPlugin.ets - 智能洞察插件(扩展版)
import { webview } from '@kit.ArkWeb';
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
@NativeComponent
export class InsightsPlugin {
private context: common.UIAbilityContext;
constructor(context: common.UIAbilityContext) {
this.context = context;
}
// 初始化插件(扩展方法注册)
public init(webviewController: webview.WebviewController): void {
webviewController.registerJavaScriptProxy(
new InsightsJSProxy(this),
'insightsPlugin',
['generateInsights', 'extractKeywords', 'detectSimilarNotes', 'calculateSimilarity']
);
}
// 生成增强版洞察
public generateInsights(): Promise<Array<any>> {
return new Promise((resolve) => {
try {
const notesPath = this.context.cacheDir + '/notes.json';
if (!fileIo.accessSync(notesPath)) {
resolve([{
type: 'basic',
title: '暂无笔记数据',
description: '您还没有创建任何笔记,开始创建笔记以获取智能洞察。'
}]);
return;
}
const content = fileIo.readTextSync(notesPath);
const notes = JSON.parse(content);
const insights: Array<any> = [];
const now = Date.now();
// 1. 基础洞察 - 笔记数量分析
if (notes.length === 0) {
insights.push({
type: 'basic',
title: '开始创建笔记',
description: '您还没有创建任何笔记,现在就开始记录您的想法吧!'
});
} else if (notes.length < 5) {
insights.push({
type: 'basic',
title: '笔记数量较少',
description: `您当前有 ${notes.length} 个笔记,建议持续记录,积累更多内容。`
});
}
// 2. 基础洞察 - 更新频率分析
const updatedNotes = notes.filter((n: any) => n.updatedAt && n.createdAt);
if (updatedNotes.length > 0) {
const avgUpdateDays = updatedNotes.reduce((sum: number, n: any) => {
const days = (new Date(n.updatedAt).getTime() - new Date(n.createdAt).getTime()) / (1000 * 60 * 60 * 24);
return sum + days;
}, 0) / updatedNotes.length;
if (avgUpdateDays > 15) {
insights.push({
type: 'basic',
title: '笔记更新频率较低',
description: `您的笔记平均 ${Math.round(avgUpdateDays)} 天更新一次,建议提高更新频率。`
});
}
}
// 3. 进阶洞察 - 分类使用分析
const categoryMap: Record<string, number> = {};
notes.forEach((n: any) => {
const category = n.category || '未分类';
categoryMap[category] = (categoryMap[category] || 0) + 1;
});
// 计算分类集中度
const categories = Object.keys(categoryMap);
if (categories.length > 1) {
const maxCount = Math.max(...Object.values(categoryMap));
const concentration = maxCount / notes.length;
if (concentration > 0.7) {
const mainCategory = Object.entries(categoryMap).find(([_, count]) => count === maxCount)![0];
insights.push({
type: 'advanced',
title: '分类使用集中',
description: `您 ${Math.round(concentration*100)}% 的笔记都在 "${mainCategory}" 分类下,建议细化分类体系。`
});
}
}
// 4. 个性化建议 - 创作时间分析
const hourDistribution = Array(24).fill(0);
notes.forEach((n: any) => {
if (n.createdAt) {
const hour = new Date(n.createdAt).getHours();
hourDistribution[hour]++;
}
});
const peakHour = hourDistribution.indexOf(Math.max(...hourDistribution));
if (Math.max(...hourDistribution) > 0) {
insights.push({
type: 'suggestion',
title: '优化创作时间',
description: `您在 ${peakHour} 点创作最活跃,建议在该时段安排重要的笔记创作任务。`
});
}
resolve(insights);
} catch (error) {
console.error('Failed to generate insights:', error);
resolve([{
type: 'basic',
title: '分析失败',
description: '无法分析笔记数据,请稍后重试。'
}]);
}
});
}
// 新增:原生端关键词提取
public extractKeywords(text: string, limit: number = 5): Promise<Array<string>> {
return new Promise((resolve) => {
try {
if (!text) {
resolve([]);
return;
}
// 简单的关键词提取逻辑(同Web端)
const stopWords = ['的', '了', '是', '我', '你', '他', '在', '有', '和', '就'];
const cleanText = text.replace(/[^\u4e00-\u9fa5a-zA-Z]/g, ' ').toLowerCase();
const words = cleanText.split(/\s+/).filter(w => w.length > 1 && !stopWords.includes(w));
const wordCount: Record<string, number> = {};
words.forEach(word => {
wordCount[word] = (wordCount[word] || 0) + 1;
});
const keywords = Object.entries(wordCount)
.sort((a, b) => b[1] - a[1])
.slice(0, limit)
.map(entry => entry[0]);
resolve(keywords);
} catch (error) {
console.error('Failed to extract keywords:', error);
resolve([]);
}
});
}
// 新增:相似笔记检测
public detectSimilarNotes(): Promise<Array<Array<any>>> {
return new Promise((resolve) => {
try {
const notesPath = this.context.cacheDir + '/notes.json';
if (!fileIo.accessSync(notesPath)) {
resolve([]);
return;
}
const content = fileIo.readTextSync(notesPath);
const notes = JSON.parse(content);
const similarGroups: Array<Array<any>> = [];
const processed = new Set<number>();
// 简单的相似性检测逻辑
for (let i = 0; i < notes.length; i++) {
if (processed.has(i) || !notes[i].title) continue;
const group: Array<any> = [notes[i]];
for (let j = i + 1; j < notes.length; j++) {
if (processed.has(j) || !notes[j].title) continue;
const similarity = this.calculateSimilarity(notes[i].title, notes[j].title);
if (similarity > 0.8) {
group.push(notes[j]);
processed.add(j);
}
}
if (group.length > 1) {
similarGroups.push(group);
}
processed.add(i);
}
resolve(similarGroups);
} catch (error) {
console.error('Failed to detect similar notes:', error);
resolve([]);
}
});
}
// 辅助方法:计算文本相似度
private calculateSimilarity(text1: string, text2: string): number {
const maxLen = Math.max(text1.length, text2.length);
if (maxLen === 0) return 0;
// 简单的字符匹配度计算
let matchCount = 0;
const minLen = Math.min(text1.length, text2.length);
for (let i = 0; i < minLen; i++) {
if (text1[i] === text2[i]) {
matchCount++;
}
}
return matchCount / maxLen;
}
}
// InsightsJSProxy.ets - JavaScript代理类(扩展版)
class InsightsJSProxy {
private plugin: InsightsPlugin;
constructor(plugin: InsightsPlugin) {
this.plugin = plugin;
}
// 异步包装:生成洞察
async generateInsights(): Promise<Array<any>> {
return await this.plugin.generateInsights();
}
// 异步包装:提取关键词
async extractKeywords(text: string, limit: number = 5): Promise<Array<string>> {
return await this.plugin.extractKeywords(text, limit);
}
// 异步包装:检测相似笔记
async detectSimilarNotes(): Promise<Array<Array<any>>> {
return await this.plugin.detectSimilarNotes();
}
}
📝 总结
智能洞察功能在原有基础上实现了核心能力增强,主要优化点包括:
分析维度扩展:新增分类分布、创作时段、关键词提取、相似笔记检测等多维度分析;
洞察分层展示:将洞察分为基础洞察、进阶分析、个性化建议三类,结构更清晰;
交互体验优化:支持洞察详情展开 / 收起、一键优化操作、洞察刷新等交互功能;
可视化增强:新增创作概览卡片,直观展示核心数据指标;
原生能力扩展:OpenHarmony 端新增关键词提取、相似笔记检测等 AI 分析能力,与 Web 端逻辑对齐;
实用性提升:所有洞察均附带具体的优化建议,从单纯的数据分析升级为可落地的行动指引。
扩展后的代码保持原有简洁架构,同时增强了 AI 分析的深度和实用性,符合 Cordova+OpenHarmony 混合开发的设计规范,为用户提供真正有价值的智能洞察和优化建议。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)