【open harmony/harmonyos】从关键词到星图:实现一个自动生成知识图谱的 ArkTS 应用
2026/6/30 1:02:32 网站建设 项目流程

【open harmony/harmonyos】从关键词到星图:实现一个自动生成知识图谱的 ArkTS 应用

前言 ✨

在知识管理、学习工具、AI 应用中,“关键词”是非常常见的输入形式。

比如用户输入一组词:

太阳, 月亮, 银河, 彗星, 星云, 行星

如果只是把它们放进列表里,信息会比较平;如果把它们自动生成一个星图,就会更直观、更有探索感。

这篇文章会结合我的 HarmonyOS / OpenHarmony 项目星图 Xingtu,分享如何使用 ArkTS 实现一个“从关键词生成知识星图”的功能。

这个功能主要包含:

  • 📝 输入主题和关键词
  • 🧹 自动解析、清洗、去重
  • 🔵 创建中心节点
  • 🌌 生成环绕节点
  • ✨ 自动建立节点连线
  • 👆 生成后直接进入可旋转缩放的星图界面

一、功能效果说明

在项目中,用户可以点击“词图生成”,输入一个主题和一组相关词。

例如:

主题:宇宙 关键词:太阳, 月亮, 银河, 彗星, 星云, 行星

生成后,系统会创建一个以“宇宙”为中心的星图:

  • “宇宙”作为中心节点
  • “太阳、月亮、银河”等作为环绕节点
  • 中心节点和每个关键词节点建立连接
  • 关键词节点之间也可以生成辅助连接

这样用户看到的不是一组孤立文字,而是一张可探索的知识关系图。🚀

二、输入弹层设计

词图生成入口封装在XingtuGenerateWordMapSheet组件中。

它包含两个输入项:

  • 主题名,可选
  • 相关词,用逗号、换行等符号分隔

核心代码如下:

@ComponentexportstructXingtuGenerateWordMapSheet{visible:boolean=false;onCancel:() =>void=() =>{};onGenerate:(themeTitle:string, rawWords:string) =>void=() =>{};@StatethemeTitle:string='';@StatewordsText:string='';privatesubmit():void{this.onGenerate(this.themeTitle.trim(),this.wordsText.trim());this.themeTitle='';this.wordsText=''; } }

这里没有把生成逻辑直接写在 UI 组件中,而是通过onGenerate回调交给外层处理。

这样做的好处是:

  • UI 组件只负责输入和展示
  • 数据生成逻辑放在 Store 中
  • 后续如果换成 AI 生成、接口生成,也更容易扩展

三、输入界面实现 📝

弹层的 UI 使用玻璃拟态风格,和星图主界面保持一致。

Column({space: 12 }){Text('生成词语星图').fontSize(22).fontWeight(FontWeight.Bold).fontColor(XingtuTheme.textPrimary)Text('输入主题和一组相关词,系统会自动生成可旋转、可缩放的 3D 星图。').fontSize(13).fontColor(XingtuTheme.textSecondary)TextInput({text:this.themeTitle,placeholder: '主题名,可选,例如:宇宙、品牌、课程' }).height(46) .borderRadius(14).backgroundColor(XingtuTheme.surfaceElevated).fontColor(XingtuTheme.textPrimary).onChange((value:string)=> this.themeTitle = value)TextInput({text:this.wordsText,placeholder: '相关词,用逗号分隔,例如:太阳, 月亮, 银河, 彗星' }).height(76) .borderRadius(14).backgroundColor(XingtuTheme.surfaceElevated).fontColor(XingtuTheme.textPrimary).onChange((value:string)=> this.wordsText = value) } .padding({ left:18, right:18, top:18, bottom:18}) .borderRadius(28).backgroundColor(XingtuTheme.materialGlass).backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THIN)

这里有一个小设计:主题名是可选的。

如果用户不填主题,系统会默认把第一个关键词作为中心节点。这可以降低输入成本,让用户更快生成图谱。

四、从页面触发生成逻辑

在主壳组件XingtuAppShell中,生成弹层通过showWordMapSheet控制显示。

privateopenWordMapSheet(): void {this.showCreateSheet =false;this.showCreateHint =false;this.showWordMapSheet =true;this.store.selectNode(null);this.revision +=1; }

当用户点击“生成星图”后,页面会调用 Store 中的generateWordMap

XingtuGenerateWordMapSheet({ visible:this.showWordMapSheet, onCancel: () => {this.showWordMapSheet =false; }, onGenerate: (themeTitle: string, rawWords: string) => {constgeneratedCount: number =this.store.generateWordMap(themeTitle, rawWords);if(generatedCount >0) {this.switchTab('starMap');this.revision +=1; }this.showWordMapSheet =false; } })

这里的体验处理比较关键:

  • 生成成功后自动切回“星图”页面
  • 更新revision触发界面刷新
  • 关闭输入弹层

用户不会停留在输入表单中,而是直接看到生成结果。✨

五、关键词解析与去重 🧹

用户输入的关键词可能来自不同场景:

  • 逗号分隔
  • 中文逗号分隔
  • 顿号分隔
  • 分号分隔
  • 换行分隔
  • 中间带空格
  • 有重复词

所以需要先对输入内容做清洗。

项目中使用parseWordList方法处理关键词。

privateparseWordList(rawWords:string):string[] {constnormalizedItems:string[] = rawWords .split(/[\n,,;;、]+/) .map((item:string) =>item.trim()) .filter((item:string) =>item.length>0);constseen:Set<string> =newSet<string>();constwords:string[] = []; normalizedItems.forEach((item:string) =>{constkey:string= item.toLowerCase();if(!seen.has(key)) { seen.add(key); words.push(item); } });returnwords; }

这个方法做了三件事:

  • 支持多种分隔符
  • 自动去掉空白内容
  • 使用Set去重

这一步虽然不复杂,但非常影响实际体验。用户输入越自由,程序就越需要做好兜底。

六、生成中心节点 🔵

生成星图的第一步,是确定中心节点。

let centerTitle:string= normalizedTheme; let orbitWords:string[] =words;if(centerTitle.length===0) { centerTitle =words[0]; orbitWords =words.slice(1); }

逻辑是:

  • 如果用户填写了主题,就用主题作为中心节点
  • 如果用户没填主题,就用第一个关键词作为中心节点
  • 剩余关键词作为环绕节点

然后创建中心节点:

const centerNode: XingtuNode = createNodeAtPosition({title: centerTitle, note: orbitWords.length> 0 ? `${orbitWords.length} 个关联词` :'中心词', tags: normalizedTheme.length> 0 ? ['theme','center'] : ['center'] }, {x: 0, y: 0, z: 40 });

中心节点放在接近画面中心的位置,作为整张星图的核心。

七、生成环绕节点 🌌

关键词节点不能全部堆在一起,需要分布在中心节点周围。

项目中使用createOrbitPosition生成环绕坐标。

privatecreateOrbitPosition(index:number, total:number): Vec3 { constcount:number= Math.max(1, total); const goldenAngle:number= Math.PI * (3- Math.sqrt(5)); const ratio:number=count===1?0.5:index/ (count-1); const yUnit:number=1- ratio *2; const radiusUnit:number= Math.sqrt(Math.max(0.08,1- yUnit * yUnit)); const theta:number= goldenAngle *index; const radius:number=180+ (index%3) *34;return{ x: Math.cos(theta) * radiusUnit * radius, y: yUnit *170+ ((index%2) -0.5) *24, z: Math.sin(theta) * radiusUnit * radius }; }

这里使用了一个类似黄金角的分布方式,让节点不会简单排成圆环,而是更自然地散布在 3D 空间中。

这样生成的节点会更像“星云”或“知识空间”,而不是普通二维图表。✨

八、建立节点连线

生成环绕节点时,会同时建立中心节点到关键词节点的关系。

orbitWords.forEach((word:string, index:number) =>{constposition =this.createOrbitPosition(index, orbitWords.length);constnode:XingtuNode=createNodeAtPosition({title: word,note:`${centerTitle}关联元素`,tags: normalizedTheme.length>0? ['word-map', normalizedTheme] : ['word-map'] }, position); generatedNodes.push(node); orbitNodeIds.push(node.id); generatedEdges.push(this.createEdge(centerNode.id, node.id)); });

当关键词数量较多时,还会给相邻关键词增加辅助连接:

if(orbitNodeIds.length>2) { orbitNodeIds.forEach((nodeId:string, index:number) =>{constnextIndex:number= index +1;if(nextIndex < orbitNodeIds.length) { generatedEdges.push(this.createEdge(nodeId, orbitNodeIds[nextIndex])); } }); }

这样生成出来的图谱不是一堆孤立节点,而是一个有中心、有扩散、有关系链路的知识网络。

九、更新 Store 并重置相机

生成完成后,需要把旧图谱替换为新图谱,并重置选中状态和相机状态。

this.nodes = generatedNodes;this.edges = generatedEdges;this.selectedNodeId = centerNode.id;this.linkingSourceId =null;this.camera = defaultCamera();returngeneratedNodes.length;

这里有两个体验细节:

  • 默认选中中心节点,让用户知道本次生成的主题是什么
  • 重置相机角度和缩放,避免用户在之前的视角中看不到新图谱

这类细节对生成类功能非常重要。生成成功不只是数据成功,还要让用户立刻“看见结果”。

十、完整生成流程回顾

整个关键词生成星图的流程如下:

用户输入主题和关键词 ↓ 解析关键词并去重 ↓ 确定中心节点 ↓ 为每个关键词生成3D坐标 ↓ 创建节点和连线 ↓ 更新Store↓ 切回星图页面并刷新UI

用代码来看,核心入口就是generateWordMap

generateWordMap(themeTitle:string,rawWords:string): number { const words:string[]= this.parseWordList(rawWords); const normalizedTheme:string= themeTitle.trim();if(words.length===0&&normalizedTheme.length===0) { return0; }letcenterTitle:string= normalizedTheme;letorbitWords:string[]= words;if(centerTitle.length===0) { centerTitle = words[0]; orbitWords = words.slice(1); } const centerNode: XingtuNode = createNodeAtPosition({...}, {x: 0,y: 0,z: 40 }); const generatedNodes: XingtuNode[]=[centerNode]; const generatedEdges: XingtuEdge[]=[]; orbitWords.forEach((word:string,index:number)=> { const position = this.createOrbitPosition(index,orbitWords.length); const node: XingtuNode = createNodeAtPosition({...},position); generatedNodes.push(node); generatedEdges.push(this.createEdge(centerNode.id,node.id)); }); this.nodes = generatedNodes; this.edges = generatedEdges; this.selectedNodeId = centerNode.id; this.camera = defaultCamera(); return generatedNodes.length; }

十一、可以继续扩展的方向 🧠

当前版本是基于用户输入关键词生成星图,后续还可以继续扩展:

  • 接入端侧 AI,自动扩展相关词
  • 给节点增加分类、颜色和权重
  • 根据词频或重要程度调整节点大小
  • 支持多个主题图谱保存
  • 支持导出图片或分享图谱
  • 支持从文章中提取关键词生成星图

这样,这个功能就可以从“词图生成器”逐步变成一个真正的知识组织工具。

十二、总结 🌟

这篇文章分享了如何在 HarmonyOS / OpenHarmony 中使用 ArkTS 实现一个“从关键词到星图”的功能。

核心实现思路是:

  • 用输入弹层收集主题和关键词
  • 用正则拆分多种分隔符
  • Set做关键词去重
  • 创建中心节点和环绕节点
  • 使用 3D 坐标生成空间布局
  • 自动创建节点关系边
  • 生成后切回星图页面并刷新

这个功能虽然不是复杂 AI,但已经具备了很强的产品表达力。用户输入一组词,就能立即看到一张可旋转、可缩放的知识星图,体验会比普通列表更直观,也更有探索感。✨

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询