文章目录
-
- 每日一句正能量
- 前言
- 一、前言:AI智能写作3.0时代的智能体革命
- 二、核心特性解析与技术选型
-
- [2.1 HMAF在智能写作场景中的价值](#2.1 HMAF在智能写作场景中的价值)
- [2.2 沉浸光感在智能写作中的创新应用](#2.2 沉浸光感在智能写作中的创新应用)
- [2.3 悬浮导航的创作适配](#2.3 悬浮导航的创作适配)
- 三、项目实战:"文思智脑"架构设计
-
- [3.1 应用场景与功能规划](#3.1 应用场景与功能规划)
- [3.2 技术架构图](#3.2 技术架构图)
- 四、环境配置与模块依赖
-
- [4.1 模块依赖配置](#4.1 模块依赖配置)
- [4.2 权限声明(module.json5)](#4.2 权限声明(module.json5))
- 五、核心组件实战
-
- [5.1 窗口沉浸配置(EntryAbility.ets)](#5.1 窗口沉浸配置(EntryAbility.ets))
- [5.2 创作流光效系统(WritingFlowLightEffect.ets)](#5.2 创作流光效系统(WritingFlowLightEffect.ets))
- [5.3 HMAF四层智能体调度器(WritingAgentScheduler.ets)](#5.3 HMAF四层智能体调度器(WritingAgentScheduler.ets))
- [5.4 悬浮创作导航(WritingFloatNavigation.ets)](#5.4 悬浮创作导航(WritingFloatNavigation.ets))
- [5.5 写作编辑器(WritingEditor.ets)](#5.5 写作编辑器(WritingEditor.ets))
- [5.6 浮动灵感面板(InspirationPanel.ets)](#5.6 浮动灵感面板(InspirationPanel.ets))
- [5.7 浮动大纲窗口(OutlineWindow.ets)](#5.7 浮动大纲窗口(OutlineWindow.ets))
- [5.8 多窗口光效同步管理器(WindowLightSync.ets)](#5.8 多窗口光效同步管理器(WindowLightSync.ets))
- [5.9 主页面集成(WritingStudioPage.ets)](#5.9 主页面集成(WritingStudioPage.ets))
- 六、关键技术总结
-
- [6.1 HMAF智能写作智能体开发清单](#6.1 HMAF智能写作智能体开发清单)
- [6.2 沉浸光感实现清单](#6.2 沉浸光感实现清单)
- [6.3 创作流阶段光效映射](#6.3 创作流阶段光效映射)
- [6.4 智能体状态徽章动画](#6.4 智能体状态徽章动画)
- [6.5 性能优化建议](#6.5 性能优化建议)
- 七、总结与展望

每日一句正能量
我们终其一生都在被爱悄悄照亮。
爱不一定轰轰烈烈,更多时候它以隐微的方式存在------朋友的倾听、陌生人的善意、自然的一缕阳光,甚至自己对自己的接纳。我们活在爱的光照中,只是常常忽略了它。
前言
摘要:2026年,内容创作进入"智能体协同写作"时代。HarmonyOS 6(API 23)引入的鸿蒙智能体框架(HMAF)将AI能力下沉至系统层,配合悬浮导航与沉浸光感特性,为PC端智能写作带来了"文思即光效、创作即导航"的全新交互范式。本文将实战开发一款面向HarmonyOS PC的"文思智脑"应用,展示如何利用HMAF构建"灵感激发-大纲构建-内容生成-润色优化"四层智能体协作架构,通过悬浮导航实现创作状态实时追踪,基于沉浸光感打造"创作流即氛围"的沉浸体验,以及基于多窗口架构构建浮动灵感面板、实时大纲窗口和风格选择器的协作创作体验。
一、前言:AI智能写作3.0时代的智能体革命
2026年,中国内容创作者规模突破1.2亿,但传统写作工具面临三大痛点:
- 灵感枯竭:创作者在长时间写作中容易陷入思维瓶颈,平均每小时产生有效灵感不足3个
- 结构混乱:长篇内容的大纲构建与逻辑梳理耗费大量时间,一篇5000字文章的提纲整理需要2-3小时
- 风格单一:创作者难以快速切换写作风格,跨领域写作时需要反复调整语调和表达方式
HarmonyOS 6(API 23)的HMAF框架配合**悬浮导航(Float Navigation)与沉浸光感(Immersive Light Effects)**特性,为智能写作带来了革命性解决方案:
- 智能体协同创作:HMAF构建的"灵感智能体"可实时分析写作上下文,自动推荐相关素材与灵感方向,响应延迟降至800ms
- 创作流光效感知:根据当前写作速度、字数积累、段落完成度动态切换环境光色,让创作者"看见"自己的创作流状态
- 悬浮创作导航:底部悬浮导航实时显示四大智能体运行状态与创作进度徽章,创作者无需切换页面即可掌握全局
- PC多窗口协作:主写作编辑器 + 浮动灵感面板窗口 + 浮动大纲窗口 + 浮动风格选择器的四层架构,通过光效联动实现"一眼全局"
本文核心亮点:
- 四层智能体架构:灵感智能体(素材推荐)、大纲智能体(结构构建)、生成智能体(内容创作)、润色智能体(优化提升)协同工作
- 创作流脉搏光效:根据写作速度(慢速蓝→平稳绿→流畅橙→心流红)动态渲染全屏氛围光
- 段落完成光效:基于段落完成度,触发不同光效反馈(起步黄→进展绿→完成金)
- 悬浮创作导航:底部悬浮页签承载"写作/灵感/大纲/润色"四大模块,实时显示智能体状态徽章与创作进度脉冲
- 多窗口光效同步 :主窗口与三个浮动子窗口通过
WindowLightSync实现跨窗口光效联动,焦点感知自动调节
二、核心特性解析与技术选型
2.1 HMAF在智能写作场景中的价值
HMAF(Harmony Intelligent Agent Framework)提供四种编排模式,在智能写作场景中各有妙用:
| 编排模式 | 智能写作应用场景 | 技术实现 |
|---|---|---|
| LLM模式 | 生成智能体根据上下文自动续写内容 | 基于前文语义自动调用LLM生成连贯段落 |
| 工作流模式 | 大纲智能体按预设流程构建文章结构 | 主题分析→关键词提取→逻辑框架→章节分配→内容要点 |
| A2A模式 | 四大智能体间实时协作与任务分发 | 灵感智能体发现热点素材时,生成智能体同步调整写作方向 |
| OpenClaw模式 | 创作者通过自然语言直接指挥智能体 | "把这段改成更正式的学术风格,增加数据支撑" |
2.2 沉浸光感在智能写作中的创新应用
传统写作软件采用固定UI,创作者难以感知自己的创作状态。HarmonyOS 6的沉浸光感特性带来三种创新:
创作流脉搏光效:根据写作速度动态调整背景光色与脉冲频率
- 慢速期(<200字/小时):深海蓝,缓慢呼吸(4秒/周期)
- 平稳期(200-500字/小时):薄荷绿,平稳律动(2秒/周期)
- 流畅期(500-1000字/小时):活力橙,快速脉冲(1秒/周期)
- 心流期(>1000字/小时):炽烈红,高频闪烁(0.5秒/周期)
段落完成光效:基于段落完成度实时驱动光效
- 起步阶段(<30%):暖黄色光晕从底部升起,提示继续
- 进展阶段(30-70%):薄荷绿光晕从中心扩散,鼓励坚持
- 完成阶段(>70%):金色粒子效果从顶部洒落,庆祝成就
风格主题光效:根据当前写作风格渲染光效主题
- 学术风格:冷静蓝色调,配合简洁几何光效
- 文艺风格:温暖橙色调,配合柔和波浪光效
- 商务风格:专业青色调,配合利落线条光效
- 创意风格:多彩紫色调,配合灵动粒子光效
2.3 悬浮导航的创作适配
传统写作软件采用顶部固定工具栏,占用宝贵竖屏空间。HarmonyOS 6的悬浮导航特性带来:
- 底部悬浮页签:不遮挡写作编辑器,支持透明度三档调节(55%/70%/85%)
- 智能体状态徽章:每个页签实时显示对应智能体运行状态(空闲/思考/执行/完成/异常)
- 创作进度实时徽章:导航栏中央显示当前字数与章节完成度,点击展开详细数据
- 快捷操作入口:长按导航栏唤起快捷菜单,一键切换写作模式/紧急保存/智能体开关
三、项目实战:"文思智脑"架构设计
3.1 应用场景与功能规划
面向HarmonyOS PC的智能写作场景,核心功能包括:
| 功能模块 | 技术实现 | 沉浸光感/HMAF应用 |
|---|---|---|
| 主写作编辑器 | TextArea + RichText |
创作流光效背景 |
| 悬浮创作导航 | HdsTabs + systemMaterialEffect |
玻璃拟态页签,智能体状态徽章 |
| 灵感智能体 | HMAF Agent Framework Kit | 灵感推荐状态光效反馈 |
| 大纲智能体 | HMAF + 结构分析引擎 | 大纲构建光效驱动 |
| 生成智能体 | HMAF + 内容生成引擎 | 生成进度光效反馈 |
| 润色智能体 | HMAF + 语言优化引擎 | 润色建议光效 |
| 浮动灵感面板 | 子窗口 + List |
灵感类型色光效同步 |
| 浮动大纲窗口 | 子窗口 + Tree |
章节主题色光效同步 |
| 浮动风格选择器 | 子窗口 + Grid |
风格主题色光效 |
3.2 技术架构图
┌─────────────────────────────────────────────────────────────┐
│ HarmonyOS 6 PC 主窗口 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 沉浸光感层 (AmbientLightLayer) │ │
│ │ 创作流光效 + 段落完成光效 + 风格主题光效 │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 主写作编辑器 (TextArea + RichText) │ │
│ │ 富文本编辑 + 实时预览 + 智能提示 │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 悬浮创作导航 (FloatNavigation) │ │
│ │ 写作/灵感/大纲/润色 页签 + 智能体状态徽章 + 进度徽章 │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 浮动灵感面板 │ │ 浮动大纲窗口 │ │ 浮动风格选择器 │
│ (灵感+类型色) │ │ (章节+主题色) │ │ (风格+主题色) │
└───────────────┘ └───────────────┘ └───────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 灵感智能体 │ │ 大纲智能体 │ │ 生成智能体 │
│ (素材灵感推荐) │ │ (文章结构构建) │ │ (内容自动续写) │
└───────────────┘ └───────────────┘ └───────────────┘
│
▼
┌───────────────┐
│ 润色智能体 │
│ (语言优化提升) │
└───────────────┘
四、环境配置与模块依赖
4.1 模块依赖配置
在entry/oh-package.json5中添加以下依赖:
json
{
"dependencies": {
"@kit.ArkUI": "1.0.0",
"@kit.WindowManagerKit": "1.0.0",
"@kit.SensorServiceKit": "1.0.0",
"@kit.UIDesignKit": "1.0.0",
"@kit.AgentFrameworkKit": "1.0.0",
"@kit.IntentsKit": "1.0.0",
"@kit.NNKit": "1.0.0",
"@kit.MediaKit": "1.0.0"
}
}
4.2 权限声明(module.json5)
json
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_permission_reason"
},
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"reason": "$string:float_window_permission_reason"
},
{
"name": "ohos.permission.READ_USER_STORAGE",
"reason": "$string:storage_permission_reason"
},
{
"name": "ohos.permission.WRITE_USER_STORAGE",
"reason": "$string:storage_permission_reason"
}
]
}
}
五、核心组件实战
5.1 窗口沉浸配置(EntryAbility.ets)
typescript
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.WindowManagerKit';
export default class EntryAbility extends UIAbility {
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
const mainWindow = await windowStage.createSubWindow('writing_main');
// 启用全屏沉浸模式,隐藏系统标题栏
await mainWindow.setWindowLayoutFullScreen(true);
// 设置窗口背景为透明,允许沉浸光效层透传
await mainWindow.setWindowBackgroundColor('#00000000');
// 加载主页面
windowStage.loadContent('pages/WritingStudioPage', (err) => {
if (err) {
console.error('Failed to load WritingStudioPage:', err.message);
}
});
// 初始化窗口焦点监听,用于光效联动
mainWindow.on('windowFocusChange', (isFocused: boolean) => {
AppStorage.setOrCreate('window_focused', isFocused);
});
}
onWindowStageDestroy(): void {
// 清理写作资源
}
}
5.2 创作流光效系统(WritingFlowLightEffect.ets)
typescript
// entry/src/main/ets/components/WritingFlowLightEffect.ets
import { HdsNavigation, SystemMaterialEffect } from '@kit.UIDesignKit';
// 创作流阶段枚举
export enum WritingFlowPhase {
SLOW = 'slow', // 慢速 <200字/小时
STEADY = 'steady', // 平稳 200-500字/小时
FLUID = 'fluid', // 流畅 500-1000字/小时
FLOW = 'flow' // 心流 >1000字/小时
}
// 段落完成度枚举
export enum ParagraphProgress {
STARTING = 'starting', // 起步 <30%
PROGRESSING = 'progressing', // 进展 30-70%
COMPLETING = 'completing' // 完成 >70%
}
// 写作风格枚举
export enum WritingStyle {
ACADEMIC = 'academic', // 学术
LITERARY = 'literary', // 文艺
BUSINESS = 'business', // 商务
CREATIVE = 'creative' // 创意
}
// 智能体状态枚举
export enum AgentState {
IDLE = 'idle',
THINKING = 'thinking',
EXECUTING = 'executing',
COMPLETED = 'completed',
ERROR = 'error'
}
@Component
export struct WritingFlowLightEffect {
@Prop wordsPerHour: number = 0;
@Prop paragraphProgress: number = 0;
@Prop currentStyle: WritingStyle = WritingStyle.CREATIVE;
@State lightIntensity: number = 0.6;
@State pulsePhase: number = 0;
// 创作流主题色映射
private flowColors: Map<WritingFlowPhase, string> = new Map([
[WritingFlowPhase.SLOW, '#1E3A8A'], // 深海蓝
[WritingFlowPhase.STEADY, '#10B981'], // 薄荷绿
[WritingFlowPhase.FLUID, '#F59E0B'], // 活力橙
[WritingFlowPhase.FLOW, '#EF4444'] // 炽烈红
]);
// 段落完成色映射
private progressColors: Map<ParagraphProgress, string> = new Map([
[ParagraphProgress.STARTING, '#FCD34D'], // 暖黄色
[ParagraphProgress.PROGRESSING, '#10B981'], // 薄荷绿
[ParagraphProgress.COMPLETING, '#FCD34D'] // 金色
]);
// 写作风格色映射
private styleColors: Map<WritingStyle, string> = new Map([
[WritingStyle.ACADEMIC, '#60A5FA'], // 冷静蓝
[WritingStyle.LITERARY, '#F97316'], // 温暖橙
[WritingStyle.BUSINESS, '#06B6D4'], // 专业青
[WritingStyle.CREATIVE, '#8B5CF6'] // 多彩紫
]);
// 脉冲周期映射(毫秒)
private pulseDurations: Map<WritingFlowPhase, number> = new Map([
[WritingFlowPhase.SLOW, 4000],
[WritingFlowPhase.STEADY, 2000],
[WritingFlowPhase.FLUID, 1000],
[WritingFlowPhase.FLOW, 500]
]);
private getCurrentFlowPhase(): WritingFlowPhase {
if (this.wordsPerHour < 200) return WritingFlowPhase.SLOW;
if (this.wordsPerHour < 500) return WritingFlowPhase.STEADY;
if (this.wordsPerHour < 1000) return WritingFlowPhase.FLUID;
return WritingFlowPhase.FLOW;
}
private getCurrentProgressPhase(): ParagraphProgress {
if (this.paragraphProgress < 30) return ParagraphProgress.STARTING;
if (this.paragraphProgress < 70) return ParagraphProgress.PROGRESSING;
return ParagraphProgress.COMPLETING;
}
private getThemeColor(): string {
// 段落完成度优先于创作流
if (this.paragraphProgress > 0) {
return this.progressColors.get(this.getCurrentProgressPhase()) || '#FCD34D';
}
// 写作风格作为基础色调
return this.styleColors.get(this.currentStyle) || this.flowColors.get(this.getCurrentFlowPhase()) || '#1E3A8A';
}
private getPulseDuration(): number {
return this.pulseDurations.get(this.getCurrentFlowPhase()) || 4000;
}
// 创作流强度影响光效强度
private getIntensityByFlow(): number {
if (this.wordsPerHour > 1000) return 1.0;
if (this.wordsPerHour > 500) return 0.8;
if (this.wordsPerHour > 200) return 0.6;
return 0.3;
}
aboutToAppear(): void {
// 启动光效脉冲动画
this.startPulseAnimation();
}
private startPulseAnimation(): void {
setInterval(() => {
this.pulsePhase = this.pulsePhase === 0 ? 1 : 0;
}, this.getPulseDuration() / 2);
}
build() {
Stack() {
// 底层:创作流脉搏光效(大面积模糊光晕)
Column()
.width(800)
.height(800)
.backgroundColor(this.getThemeColor())
.blur(200)
.opacity(this.getIntensityByFlow() * 0.25)
.position({ x: '50%', y: '30%' })
.anchor('50%')
.scale({
x: this.pulsePhase === 0 ? 1.0 : 1.3,
y: this.pulsePhase === 0 ? 1.0 : 1.3
})
.animation({
duration: this.getPulseDuration(),
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
})
// 中层:段落完成光效(底部渐变)
if (this.paragraphProgress > 0) {
Column()
.width('100%')
.height(200)
.backgroundColor(this.progressColors.get(this.getCurrentProgressPhase()) || '#FCD34D')
.opacity(0.15)
.blur(80)
.position({ x: 0, y: '75%' })
.linearGradient({
direction: GradientDirection.Top,
colors: [
[this.progressColors.get(this.getCurrentProgressPhase()) || '#FCD34D', 0.0],
['transparent', 1.0]
]
})
.animation({
duration: 2000,
curve: Curve.EaseInOut
})
}
// 中层:写作风格光效(风格化背景)
Column()
.width('100%')
.height('100%')
.backgroundColor('transparent')
.border({
width: 1,
color: `${this.styleColors.get(this.currentStyle) || '#8B5CF6'}30`
})
// 顶层:心流粒子效果(仅在心流期显示)
if (this.getCurrentFlowPhase() === WritingFlowPhase.FLOW) {
this.buildFlowParticles()
}
}
.width('100%')
.height('100%')
.backgroundColor('#050508')
}
@Builder
buildFlowParticles(): void {
ForEach([0, 1, 2, 3, 4], (index: number) => {
Column()
.width(4)
.height(4)
.backgroundColor('#FCD34D')
.borderRadius(2)
.opacity(0.6)
.position({
x: `${20 + index * 15}%`,
y: `${30 + index * 10}%`
})
.animation({
duration: 1500 + index * 300,
curve: Curve.Linear,
iterations: -1,
playMode: PlayMode.Alternate
})
.translate({
y: this.pulsePhase === 0 ? -20 : -100
})
})
}
}
5.3 HMAF四层智能体调度器(WritingAgentScheduler.ets)
typescript
// entry/src/main/ets/agents/WritingAgentScheduler.ets
import { hmaf } from '@kit.AgentFrameworkKit';
import { intents } from '@kit.IntentsKit';
// 智能体类型枚举
export enum AgentType {
INSPIRATION = 'inspiration', // 灵感智能体
OUTLINE = 'outline', // 大纲智能体
GENERATOR = 'generator', // 生成智能体
POLISHER = 'polisher' // 润色智能体
}
// 智能体人格色彩映射
export enum AgentPersonality {
INSPIRATION = '#FCD34D', // 灵感金
OUTLINE = '#8B5CF6', // 大纲紫
GENERATOR = '#06B6D4', // 生成青
POLISHER = '#10B981' // 润色绿
}
export class WritingAgentScheduler {
private static instance: WritingAgentScheduler;
private hmafSession: hmaf.AgentSession | null = null;
private intentEngine: intents.IntentEngine | null = null;
// 智能体状态管理
private agentStates: Map<string, AgentState> = new Map([
['inspiration-1', AgentState.IDLE],
['outline-1', AgentState.IDLE],
['generator-1', AgentState.IDLE],
['polisher-1', AgentState.IDLE]
]);
private constructor() {}
static getInstance(): WritingAgentScheduler {
if (!WritingAgentScheduler.instance) {
WritingAgentScheduler.instance = new WritingAgentScheduler();
}
return WritingAgentScheduler.instance;
}
async initialize(): Promise<void> {
// 初始化HMAF多智能体会话
this.hmafSession = await hmaf.createAgentSession({
mode: hmaf.AgentMode.MULTI_AGENT,
enableDistributed: true,
maxConcurrentAgents: 4
});
// 初始化意图引擎
this.intentEngine = await intents.createIntentEngine({
supportedDomains: ['inspiration_generation', 'outline_construction', 'content_generation', 'text_polishing']
});
// 注册四大智能体
await this.registerAgents();
// 启动状态监听
this.startStateMonitoring();
}
private async registerAgents(): Promise<void> {
// 1. 灵感智能体:素材推荐与灵感激发
await this.hmafSession?.registerAgent({
agentId: 'inspiration-1',
agentType: AgentType.INSPIRATION,
capabilities: ['topic_analysis', 'material_recommendation', 'trend_tracking', 'analogy_generation', 'hook_design'],
modelConfig: {
modelType: 'llm',
temperature: 0.9,
maxTokens: 512
}
});
// 2. 大纲智能体:文章结构构建
await this.hmafSession?.registerAgent({
agentId: 'outline-1',
agentType: AgentType.OUTLINE,
capabilities: ['structure_design', 'logic_flow', 'chapter_allocation', 'keypoint_extraction', 'transition_design'],
modelConfig: {
modelType: 'llm',
temperature: 0.4,
maxTokens: 1024
}
});
// 3. 生成智能体:内容自动续写
await this.hmafSession?.registerAgent({
agentId: 'generator-1',
agentType: AgentType.GENERATOR,
capabilities: ['context_continuation', 'style_adaptation', 'fact_insertion', 'example_generation', 'transition_writing'],
modelConfig: {
modelType: 'llm',
temperature: 0.7,
maxTokens: 2048
}
});
// 4. 润色智能体:语言优化提升
await this.hmafSession?.registerAgent({
agentId: 'polisher-1',
agentType: AgentType.POLISHER,
capabilities: ['grammar_check', 'style_enhancement', 'readability_optimization', 'redundancy_removal', 'tone_adjustment'],
modelConfig: {
modelType: 'llm',
temperature: 0.3,
maxTokens: 1024
}
});
}
// 获取灵感推荐
async getInspirations(topic: string, currentContext: string): Promise<{ ideas: Inspiration[]; materials: Material[]; trends: Trend[] }> {
this.updateAgentState('inspiration-1', AgentState.THINKING);
const result = await this.hmafSession?.sendTask({
targetAgent: 'inspiration-1',
taskType: 'get_inspirations',
payload: {
topic: topic,
currentContext: currentContext,
maxIdeas: 5,
includeMaterials: true,
includeTrends: true
}
});
this.updateAgentState('inspiration-1', AgentState.COMPLETED);
return {
ideas: result?.ideas || [],
materials: result?.materials || [],
trends: result?.trends || []
};
}
// 构建文章大纲
async buildOutline(topic: string, style: string, wordCount: number): Promise<{ sections: Section[]; logicFlow: string; keywords: string[] }> {
this.updateAgentState('outline-1', AgentState.THINKING);
const result = await this.hmafSession?.sendTask({
targetAgent: 'outline-1',
taskType: 'build_outline',
payload: {
topic: topic,
style: style, // 'academic', 'literary', 'business', 'creative'
wordCount: wordCount,
structure: 'standard', // 'standard', 'inverted_pyramid', 'problem_solution'
includeSubsections: true
}
});
this.updateAgentState('outline-1', AgentState.COMPLETED);
return {
sections: result?.sections || [],
logicFlow: result?.logicFlow || '',
keywords: result?.keywords || []
};
}
// 生成内容续写
async generateContinuation(context: string, style: string, length: number): Promise<{ content: string; suggestions: string[]; confidence: number }> {
this.updateAgentState('generator-1', AgentState.EXECUTING);
const result = await this.hmafSession?.sendTask({
targetAgent: 'generator-1',
taskType: 'generate_continuation',
payload: {
context: context,
style: style,
length: length, // 字数
tone: 'consistent',
includeExamples: true,
includeData: true
}
});
this.updateAgentState('generator-1', AgentState.COMPLETED);
return {
content: result?.content || '',
suggestions: result?.suggestions || [],
confidence: result?.confidence || 0
};
}
// 润色优化
async polishText(text: string, targetStyle: string, focus: string): Promise<{ polishedText: string; changes: Change[]; readability: ReadabilityScore }> {
this.updateAgentState('polisher-1', AgentState.EXECUTING);
const result = await this.hmafSession?.sendTask({
targetAgent: 'polisher-1',
taskType: 'polish_text',
payload: {
text: text,
targetStyle: targetStyle,
focus: focus, // 'grammar', 'style', 'readability', 'conciseness'
preserveMeaning: true,
maxChanges: 20
}
});
this.updateAgentState('polisher-1', AgentState.COMPLETED);
return {
polishedText: result?.polishedText || '',
changes: result?.changes || [],
readability: result?.readabilityScore || {}
};
}
private updateAgentState(agentId: string, state: AgentState): void {
this.agentStates.set(agentId, state);
AppStorage.setOrCreate('agent_state_update', { agentId, state });
}
getAgentState(agentId: string): AgentState {
return this.agentStates.get(agentId) || AgentState.IDLE;
}
private startStateMonitoring(): void {
// 监听智能体状态变化,同步到UI
this.hmafSession?.on('agentStateChange', (event: { agentId: string; state: string }) => {
this.updateAgentState(event.agentId, event.state as AgentState);
});
}
}
// 灵感
export interface Inspiration {
id: string;
title: string;
description: string;
relevance: number;
category: string;
}
// 素材
export interface Material {
id: string;
title: string;
source: string;
summary: string;
url: string;
}
// 趋势
export interface Trend {
id: string;
topic: string;
heat: number;
direction: 'rising' | 'stable' | 'falling';
}
// 章节
export interface Section {
id: string;
title: string;
level: number;
wordCount: number;
keyPoints: string[];
parentId?: string;
}
// 修改
export interface Change {
type: 'grammar' | 'style' | 'wording' | 'structure';
original: string;
replacement: string;
reason: string;
position: number;
}
// 可读性评分
export interface ReadabilityScore {
score: number;
grade: string;
complexity: number;
clarity: number;
}
5.4 悬浮创作导航(WritingFloatNavigation.ets)
typescript
// entry/src/main/ets/components/WritingFloatNavigation.ets
import { window } from '@kit.ArkUI';
import { AgentState, AgentType, AgentPersonality } from '../agents/WritingAgentScheduler';
import { WritingFlowPhase } from './WritingFlowLightEffect';
interface NavItem {
id: string;
icon: Resource;
label: string;
page: string;
agentType?: AgentType;
}
@Component
export struct WritingFloatNavigation {
@State currentIndex: number = 0;
@State navTransparency: number = 0.70;
@State isExpanded: boolean = false;
@State bottomAvoidHeight: number = 0;
@State wordCount: number = 0;
@State chapterProgress: number = 0;
@State currentPhase: WritingFlowPhase = WritingFlowPhase.SLOW;
@State agentStates: Map<string, AgentState> = new Map([
['inspiration-1', AgentState.IDLE],
['outline-1', AgentState.IDLE],
['generator-1', AgentState.IDLE],
['polisher-1', AgentState.IDLE]
]);
private navItems: NavItem[] = [
{ id: 'write', icon: $r('app.media.ic_edit'), label: '写作', page: 'WritePage' },
{ id: 'inspiration', icon: $r('app.media.ic_lightbulb'), label: '灵感', page: 'InspirationPage', agentType: AgentType.INSPIRATION },
{ id: 'outline', icon: $r('app.media.ic_list'), label: '大纲', page: 'OutlinePage', agentType: AgentType.OUTLINE },
{ id: 'polish', icon: $r('app.media.ic_magic'), label: '润色', page: 'PolishPage', agentType: AgentType.POLISHER },
{ id: 'settings', icon: $r('app.media.ic_settings'), label: '设置', page: 'SettingsPage' }
];
aboutToAppear(): void {
this.getBottomAvoidArea();
// 监听智能体状态更新
AppStorage.watch('agent_state_update', (update: { agentId: string; state: string }) => {
this.agentStates.set(update.agentId, update.state as AgentState);
});
// 监听创作指标
AppStorage.watch('writing_metrics', (metrics: { wordCount: number; chapterProgress: number }) => {
this.wordCount = metrics.wordCount;
this.chapterProgress = metrics.chapterProgress;
this.updateFlowPhase();
});
}
private updateFlowPhase(): void {
// 估算写作速度(简化计算)
const wordsPerHour = this.wordCount; // 实际应根据时间计算
if (wordsPerHour < 200) this.currentPhase = WritingFlowPhase.SLOW;
else if (wordsPerHour < 500) this.currentPhase = WritingFlowPhase.STEADY;
else if (wordsPerHour < 1000) this.currentPhase = WritingFlowPhase.FLUID;
else this.currentPhase = WritingFlowPhase.FLOW;
}
private async getBottomAvoidArea(): Promise<void> {
try {
const mainWindow = await window.getLastWindow();
const avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
this.bottomAvoidHeight = avoidArea.bottomRect.height;
} catch (error) {
console.error('Failed to get avoid area:', error);
}
}
private getAgentStateForNavItem(item: NavItem): AgentState {
if (!item.agentType) return AgentState.IDLE;
const agentIdMap: Record<string, string> = {
[AgentType.INSPIRATION]: 'inspiration-1',
[AgentType.OUTLINE]: 'outline-1',
[AgentType.GENERATOR]: 'generator-1',
[AgentType.POLISHER]: 'polisher-1'
};
return this.agentStates.get(agentIdMap[item.agentType]) || AgentState.IDLE;
}
private getPhaseColor(): string {
const colors: Record<WritingFlowPhase, string> = {
[WritingFlowPhase.SLOW]: '#1E3A8A',
[WritingFlowPhase.STEADY]: '#10B981',
[WritingFlowPhase.FLUID]: '#F59E0B',
[WritingFlowPhase.FLOW]: '#EF4444'
};
return colors[this.currentPhase];
}
private getStateBadgeColor(state: AgentState): string {
const colors: Record<AgentState, string> = {
[AgentState.IDLE]: '#888888',
[AgentState.THINKING]: '#8B5CF6',
[AgentState.EXECUTING]: '#F97316',
[AgentState.COMPLETED]: '#10B981',
[AgentState.ERROR]: '#EF4444'
};
return colors[state] || '#888888';
}
private getStateBadgeAnimation(state: AgentState): object {
switch (state) {
case AgentState.THINKING:
return {
duration: 1500,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
};
case AgentState.EXECUTING:
return {
duration: 800,
curve: Curve.Linear,
iterations: -1
};
case AgentState.ERROR:
return {
duration: 400,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
};
default:
return { duration: 0 };
}
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
Column() {
this.contentBuilder()
}
.padding({ bottom: this.bottomAvoidHeight + 90 })
// 悬浮导航容器
Column() {
Stack() {
// 玻璃拟态背景层
Column()
.width('100%')
.height('100%')
.backgroundBlurStyle(BlurStyle.REGULAR)
.opacity(this.navTransparency)
.backdropFilter($r('sys.blur.20'))
// 渐变叠加层
Column()
.width('100%')
.height('100%')
.linearGradient({
direction: GradientDirection.Top,
colors: [
['rgba(255,255,255,0.15)', 0.0],
['rgba(255,255,255,0.05)', 1.0]
]
})
}
.width('100%')
.height('100%')
.borderRadius(28)
.shadow({
radius: 24,
color: 'rgba(0,0,0,0.25)',
offsetX: 0,
offsetY: -6
})
Column() {
// 创作信息栏(展开时显示)
if (this.isExpanded) {
Row() {
Column() {
Text(`${this.wordCount.toLocaleString()}字`)
.fontSize(13)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
Text('当前字数')
.fontSize(10)
.fontColor('rgba(255,255,255,0.6)')
}
.layoutWeight(1)
Column() {
Text(`${this.chapterProgress}%`)
.fontSize(13)
.fontColor(this.getProgressColor())
.fontWeight(FontWeight.Bold)
Text('章节进度')
.fontSize(10)
.fontColor('rgba(255,255,255,0.6)')
}
.layoutWeight(1)
Column() {
Text(this.getPhaseLabel())
.fontSize(13)
.fontColor(this.getPhaseColor())
.fontWeight(FontWeight.Bold)
Text('创作状态')
.fontSize(10)
.fontColor('rgba(255,255,255,0.6)')
}
.layoutWeight(1)
}
.width('100%')
.height(50)
.padding({ left: 16, right: 16 })
.backgroundColor('rgba(0,0,0,0.2)')
.borderRadius({ topLeft: 28, topRight: 28 })
}
// 导航页签
Row() {
ForEach(this.navItems, (item: NavItem, index: number) => {
Column() {
Stack() {
Image(item.icon)
.width(26)
.height(26)
.fillColor(this.currentIndex === index ? this.getPhaseColor() : '#AAAAAA')
// 智能体状态徽章
if (item.agentType && this.getAgentStateForNavItem(item) !== AgentState.IDLE) {
Column()
.width(10)
.height(10)
.backgroundColor(this.getStateBadgeColor(this.getAgentStateForNavItem(item)))
.borderRadius(5)
.position({ x: 20, y: -4 })
.shadow({
radius: 8,
color: this.getStateBadgeColor(this.getAgentStateForNavItem(item)),
offsetX: 0,
offsetY: 0
})
.animation(this.getStateBadgeAnimation(this.getAgentStateForNavItem(item)))
}
}
.width(44)
.height(44)
Text(item.label)
.fontSize(11)
.fontColor(this.currentIndex === index ? this.getPhaseColor() : '#BBBBBB')
.margin({ top: 4 })
}
.layoutWeight(1)
.onClick(() => {
this.currentIndex = index;
this.triggerHapticFeedback();
AppStorage.setOrCreate('nav_page_change', item.page);
})
})
}
.width('100%')
.height(this.isExpanded ? 70 : 80)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.SpaceAround)
// 透明度调节(展开时显示)
if (this.isExpanded) {
Row() {
Text('透明度')
.fontSize(12)
.fontColor('rgba(255,255,255,0.7)')
.margin({ right: 8 })
Slider({
value: this.navTransparency * 100,
min: 55,
max: 85,
step: 15,
style: SliderStyle.InSet
})
.width(120)
.onChange((value: number) => {
this.navTransparency = value / 100;
})
Text(`${Math.round(this.navTransparency * 100)}%`)
.fontSize(12)
.fontColor('rgba(255,255,255,0.7)')
.margin({ left: 8 })
}
.width('100%')
.height(40)
.justifyContent(FlexAlign.Center)
}
}
.width('100%')
.height('100%')
}
.width('92%')
.height(this.isExpanded ? 160 : 80)
.margin({ bottom: this.bottomAvoidHeight + 12, left: '4%', right: '4%' })
.animation({
duration: 350,
curve: Curve.Spring,
iterations: 1
})
.gesture(
LongPressGesture({ duration: 600 })
.onAction(() => {
this.isExpanded = !this.isExpanded;
})
)
}
.width('100%')
.height('100%')
}
private getPhaseLabel(): string {
const labels: Record<WritingFlowPhase, string> = {
[WritingFlowPhase.SLOW]: '慢速',
[WritingFlowPhase.STEADY]: '平稳',
[WritingFlowPhase.FLUID]: '流畅',
[WritingFlowPhase.FLOW]: '心流'
};
return labels[this.currentPhase];
}
private getProgressColor(): string {
if (this.chapterProgress >= 80) return '#10B981';
if (this.chapterProgress >= 40) return '#F59E0B';
return '#EF4444';
}
@BuilderParam contentBuilder: () => void = this.defaultContentBuilder;
@Builder
defaultContentBuilder(): void {
Column() {
Text('写作编辑区域')
.fontSize(16)
.fontColor('#999999')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
private triggerHapticFeedback(): void {
try {
import('@kit.SensorServiceKit').then(sensor => {
sensor.vibrator.startVibration({
type: 'time',
duration: 40
}, { id: 0 });
});
} catch (error) {
console.error('Haptic feedback failed:', error);
}
}
}
5.5 写作编辑器(WritingEditor.ets)
typescript
// entry/src/main/ets/components/WritingEditor.ets
import { WritingAgentScheduler, Inspiration, Section, Change } from '../agents/WritingAgentScheduler';
import { WritingStyle } from './WritingFlowLightEffect';
@Component
export struct WritingEditor {
@State content: string = '';
@State wordCount: number = 0;
@State selectedText: string = '';
@State currentStyle: WritingStyle = WritingStyle.CREATIVE;
@State showStyleMenu: boolean = false;
@State suggestions: string[] = [];
private scheduler: WritingAgentScheduler = WritingAgentScheduler.getInstance();
private lastTypingTime: number = 0;
private typingTimer: number = 0;
aboutToAppear(): void {
// 监听字数变化
AppStorage.watch('content_update', (text: string) => {
this.content = text;
this.wordCount = this.countWords(text);
this.handleTyping();
});
}
private countWords(text: string): number {
// 中文字符 + 英文单词计数
const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
const englishWords = (text.match(/[a-zA-Z]+/g) || []).length;
return chineseChars + englishWords;
}
private handleTyping(): void {
const now = Date.now();
this.lastTypingTime = now;
// 清除之前的定时器
clearTimeout(this.typingTimer);
// 3秒无输入后触发智能体分析
this.typingTimer = setTimeout(() => {
this.analyzeContext();
}, 3000);
// 同步写作指标
AppStorage.setOrCreate('writing_metrics', {
wordCount: this.wordCount,
chapterProgress: this.calculateProgress()
});
}
private calculateProgress(): number {
// 简化进度计算,实际应根据大纲目标字数
return Math.min(100, Math.round((this.wordCount / 3000) * 100));
}
private async analyzeContext(): Promise<void> {
if (this.wordCount < 50) return;
// 触发灵感智能体
const lastParagraph = this.getLastParagraph();
if (lastParagraph) {
const inspirations = await this.scheduler.getInspirations('', lastParagraph);
this.suggestions = inspirations.ideas.map(i => i.title);
}
}
private getLastParagraph(): string {
const paragraphs = this.content.split('\n').filter(p => p.trim());
return paragraphs[paragraphs.length - 1] || '';
}
private async continueWriting(): Promise<void> {
const continuation = await this.scheduler.generateContinuation(
this.content,
this.currentStyle,
200
);
if (continuation.content) {
this.content += '\n\n' + continuation.content;
AppStorage.setOrCreate('content_update', this.content);
}
}
private async polishSelected(): Promise<void> {
if (!this.selectedText) return;
const result = await this.scheduler.polishText(
this.selectedText,
this.currentStyle,
'style'
);
if (result.polishedText) {
this.content = this.content.replace(this.selectedText, result.polishedText);
AppStorage.setOrCreate('content_update', this.content);
}
}
private getStyleLabel(style: WritingStyle): string {
const labels: Record<WritingStyle, string> = {
[WritingStyle.ACADEMIC]: '学术',
[WritingStyle.LITERARY]: '文艺',
[WritingStyle.BUSINESS]: '商务',
[WritingStyle.CREATIVE]: '创意'
};
return labels[style];
}
build() {
Column() {
// 工具栏
Row({ space: 12 }) {
// 风格选择
Button(this.getStyleLabel(this.currentStyle))
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('rgba(255,255,255,0.1)')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
this.showStyleMenu = !this.showStyleMenu;
})
Button('✨ AI续写')
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#06B6D4')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
this.continueWriting();
})
Button('💎 润色')
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#8B5CF6')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
this.polishSelected();
})
Button('💾 保存')
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#10B981')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
// 保存内容
})
Text(`${this.wordCount}字`)
.fontSize(12)
.fontColor('rgba(255,255,255,0.6)')
.margin({ left: 12 })
}
.width('100%')
.height(50)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.Start)
// 风格菜单
if (this.showStyleMenu) {
Row({ space: 8 }) {
ForEach([
{ style: WritingStyle.ACADEMIC, label: '学术', color: '#60A5FA' },
{ style: WritingStyle.LITERARY, label: '文艺', color: '#F97316' },
{ style: WritingStyle.BUSINESS, label: '商务', color: '#06B6D4' },
{ style: WritingStyle.CREATIVE, label: '创意', color: '#8B5CF6' }
], (item: { style: WritingStyle; label: string; color: string }) => {
Text(item.label)
.fontSize(12)
.fontColor(this.currentStyle === item.style ? '#FFFFFF' : 'rgba(255,255,255,0.7)')
.backgroundColor(this.currentStyle === item.style ? item.color : 'rgba(255,255,255,0.1)')
.padding({ left: 16, right: 16, top: 6, bottom: 6 })
.borderRadius(12)
.onClick(() => {
this.currentStyle = item.style;
this.showStyleMenu = false;
AppStorage.setOrCreate('current_style', item.style);
})
})
}
.width('100%')
.height(40)
.padding({ left: 16, right: 16 })
}
// 智能提示
if (this.suggestions.length > 0) {
Row({ space: 8 }) {
Text('💡 灵感:')
.fontSize(11)
.fontColor('#FCD34D')
ForEach(this.suggestions.slice(0, 3), (suggestion: string) => {
Text(suggestion)
.fontSize(11)
.fontColor('rgba(255,255,255,0.7)')
.backgroundColor('rgba(252, 211, 77, 0.1)')
.padding({ left: 10, right: 10, top: 4, bottom: 4 })
.borderRadius(8)
.onClick(() => {
this.content += `\n\n【灵感】${suggestion}:`;
AppStorage.setOrCreate('content_update', this.content);
})
})
}
.width('100%')
.height(36)
.padding({ left: 16, right: 16 })
.backgroundColor('rgba(252, 211, 77, 0.05)')
}
// 编辑器
TextArea({ text: $$this.content })
.width('100%')
.layoutWeight(1)
.backgroundColor('rgba(255,255,255,0.03)')
.fontColor('#FFFFFF')
.fontSize(15)
.placeholder('开始写作...')
.placeholderColor('rgba(255,255,255,0.3)')
.padding(20)
.onChange((value: string) => {
this.content = value;
this.wordCount = this.countWords(value);
AppStorage.setOrCreate('content_update', value);
this.handleTyping();
})
.onSelect((selection: TextSelection) => {
this.selectedText = this.content.substring(selection.start, selection.end);
})
}
.width('100%')
.height('100%')
.backgroundColor('rgba(10, 10, 15, 0.95)')
.borderRadius(16)
}
}
5.6 浮动灵感面板(InspirationPanel.ets)
typescript
// entry/src/main/ets/components/InspirationPanel.ets
import { WritingAgentScheduler, Inspiration, Material, Trend } from '../agents/WritingAgentScheduler';
@Component
export struct InspirationPanel {
@State inspirations: Inspiration[] = [];
@State materials: Material[] = [];
@State trends: Trend[] = [];
@State currentTopic: string = 'HarmonyOS开发';
private scheduler: WritingAgentScheduler = WritingAgentScheduler.getInstance();
aboutToAppear(): void {
this.loadInspirations();
}
private async loadInspirations(): Promise<void> {
const result = await this.scheduler.getInspirations(this.currentTopic, '');
this.inspirations = result.ideas;
this.materials = result.materials;
this.trends = result.trends;
}
private getRelevanceColor(relevance: number): string {
if (relevance > 0.8) return '#10B981';
if (relevance > 0.5) return '#F59E0B';
return '#EF4444';
}
private getTrendIcon(direction: string): string {
const icons: Record<string, string> = {
'rising': '📈',
'stable': '➡️',
'falling': '📉'
};
return icons[direction] || '➡️';
}
build() {
Column() {
// 标题栏
Row() {
Text('💡 灵感面板')
.fontSize(16)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
Button('🔄 刷新')
.fontSize(11)
.fontColor('#FFFFFF')
.backgroundColor('rgba(255,255,255,0.1)')
.padding({ left: 10, right: 10, top: 4, bottom: 4 })
.borderRadius(10)
.onClick(() => {
this.loadInspirations();
})
}
.width('100%')
.height(50)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.SpaceBetween)
// 热门趋势
Column() {
Text('🔥 热门趋势')
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Medium)
.margin({ bottom: 12 })
List() {
ForEach(this.trends.slice(0, 3), (trend: Trend) => {
ListItem() {
Row() {
Text(this.getTrendIcon(trend.direction))
.fontSize(16)
.margin({ right: 8 })
Column() {
Text(trend.topic)
.fontSize(12)
.fontColor('#FFFFFF')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(`热度: ${(trend.heat * 100).toFixed(0)}%`)
.fontSize(10)
.fontColor('rgba(255,255,255,0.5)')
}
.layoutWeight(1)
}
.width('100%')
.padding(8)
.backgroundColor('rgba(255,255,255,0.03)')
.borderRadius(8)
}
.margin({ bottom: 6 })
})
}
.width('100%')
.height(120)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
.margin({ left: 12, right: 12, top: 12 })
// 灵感推荐
List() {
ForEach(this.inspirations, (inspiration: Inspiration) => {
ListItem() {
Column() {
Row() {
Text(inspiration.title)
.fontSize(13)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Medium)
.layoutWeight(1)
Text(`${(inspiration.relevance * 100).toFixed(0)}%`)
.fontSize(10)
.fontColor(this.getRelevanceColor(inspiration.relevance))
.backgroundColor(`${this.getRelevanceColor(inspiration.relevance)}20`)
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.borderRadius(6)
}
.width('100%')
Text(inspiration.description)
.fontSize(11)
.fontColor('rgba(255,255,255,0.6)')
.margin({ top: 6 })
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(inspiration.category)
.fontSize(10)
.fontColor('rgba(255,255,255,0.4)')
.margin({ top: 4 })
}
.width('100%')
.padding(12)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
.onClick(() => {
// 插入灵感到编辑器
AppStorage.setOrCreate('insert_inspiration', inspiration);
})
}
.margin({ bottom: 8 })
})
}
.width('100%')
.layoutWeight(1)
.padding({ left: 12, right: 12 })
// 素材库
Column() {
Text('📚 推荐素材')
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Medium)
.margin({ bottom: 12 })
List() {
ForEach(this.materials.slice(0, 3), (material: Material) => {
ListItem() {
Row() {
Column() {
Text(material.title)
.fontSize(12)
.fontColor('#FFFFFF')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(material.source)
.fontSize(10)
.fontColor('rgba(255,255,255,0.5)')
.margin({ top: 4 })
}
.layoutWeight(1)
Image($r('app.media.ic_external_link'))
.width(16)
.height(16)
.fillColor('rgba(255,255,255,0.5)')
}
.width('100%')
.padding(8)
.backgroundColor('rgba(255,255,255,0.03)')
.borderRadius(8)
}
.margin({ bottom: 6 })
})
}
.width('100%')
.height(120)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
.margin({ left: 12, right: 12, top: 12 })
}
.width('100%')
.height('100%')
.backgroundColor('rgba(10, 10, 15, 0.95)')
.borderRadius(16)
}
}
5.7 浮动大纲窗口(OutlineWindow.ets)
typescript
// entry/src/main/ets/windows/OutlineWindow.ets
import { WritingAgentScheduler, Section } from '../agents/WritingAgentScheduler';
@Component
export struct OutlineWindow {
@State sections: Section[] = [];
@State currentTopic: string = 'HarmonyOS 6智能体开发实战';
@State targetWordCount: number = 5000;
@State currentWordCount: number = 0;
private scheduler: WritingAgentScheduler = WritingAgentScheduler.getInstance();
aboutToAppear(): void {
this.buildOutline();
}
private async buildOutline(): Promise<void> {
const result = await this.scheduler.buildOutline(
this.currentTopic,
'technical',
this.targetWordCount
);
this.sections = result.sections;
}
private getLevelIndent(level: number): number {
return level * 16;
}
private getLevelColor(level: number): string {
const colors = ['#FCD34D', '#8B5CF6', '#06B6D4', '#10B981'];
return colors[level] || '#888888';
}
build() {
Column() {
// 标题栏
Row() {
Text('📋 文章大纲')
.fontSize(16)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
Row({ space: 8 }) {
Text(`${this.currentWordCount}/${this.targetWordCount}字`)
.fontSize(11)
.fontColor('#10B981')
Progress({ value: this.currentWordCount, total: this.targetWordCount, type: ProgressType.Ring })
.width(30)
.height(30)
.color('#10B981')
.backgroundColor('rgba(255,255,255,0.1)')
}
}
.width('100%')
.height(50)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.SpaceBetween)
// 大纲树
List() {
ForEach(this.sections, (section: Section) => {
ListItem() {
Column() {
Row() {
// 层级指示器
Column()
.width(4)
.height(20)
.backgroundColor(this.getLevelColor(section.level))
.borderRadius(2)
.margin({ right: 8 })
Column() {
Text(section.title)
.fontSize(13 - section.level)
.fontColor(section.level === 0 ? '#FFFFFF' : 'rgba(255,255,255,0.8)')
.fontWeight(section.level === 0 ? FontWeight.Bold : FontWeight.Normal)
if (section.keyPoints.length > 0) {
Text(section.keyPoints[0])
.fontSize(10)
.fontColor('rgba(255,255,255,0.5)')
.margin({ top: 4 })
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
}
.layoutWeight(1)
Text(`${section.wordCount}字`)
.fontSize(10)
.fontColor('rgba(255,255,255,0.4)')
}
.width('100%')
.padding({ left: this.getLevelIndent(section.level), right: 12, top: 10, bottom: 10 })
.backgroundColor('rgba(255,255,255,0.03)')
.borderRadius(8)
}
.width('100%')
.margin({ bottom: 4 })
}
})
}
.width('100%')
.layoutWeight(1)
.padding({ left: 12, right: 12 })
// 快捷操作
Row({ space: 12 }) {
Button('➕ 添加章节')
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#8B5CF6')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
// 添加新章节
})
Button('🔄 重新生成')
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('rgba(255,255,255,0.1)')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(16)
.onClick(() => {
this.buildOutline();
})
}
.width('100%')
.height(50)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor('rgba(10, 10, 15, 0.95)')
.borderRadius(16)
}
}
5.8 多窗口光效同步管理器(WindowLightSync.ets)
typescript
// entry/src/main/ets/utils/WindowLightSync.ets
import { window } from '@kit.WindowManagerKit';
export class WindowLightSync {
private static instance: WindowLightSync;
private subWindows: Map<string, window.Window> = new Map();
private currentTheme: string = '#1E3A8A';
private currentIntensity: number = 0.6;
private constructor() {}
static getInstance(): WindowLightSync {
if (!WindowLightSync.instance) {
WindowLightSync.instance = new WindowLightSync();
}
return WindowLightSync.instance;
}
async registerSubWindow(name: string, win: window.Window): Promise<void> {
this.subWindows.set(name, win);
await this.syncLightToWindow(win);
}
async syncGlobalLightEffect(themeColor: string, intensity?: number): Promise<void> {
this.currentTheme = themeColor;
if (intensity !== undefined) {
this.currentIntensity = intensity;
}
for (const [name, win] of this.subWindows) {
await this.syncLightToWindow(win);
}
AppStorage.setOrCreate('global_theme_color', this.currentTheme);
AppStorage.setOrCreate('global_light_intensity', this.currentIntensity);
}
private async syncLightToWindow(win: window.Window): Promise<void> {
try {
await win.setWindowBackgroundColor(`${this.currentTheme}20`);
await win.setWindowShadow({
radius: 20,
color: `${this.currentTheme}40`,
offsetX: 0,
offsetY: 4
});
} catch (error) {
console.error(`Failed to sync light to window:`, error);
}
}
async handleFocusChange(focusedWindowName: string): Promise<void> {
for (const [name, win] of this.subWindows) {
const isFocused = name === focusedWindowName;
const intensity = isFocused ? this.currentIntensity : this.currentIntensity * 0.4;
try {
await win.setWindowBackgroundColor(`${this.currentTheme}${Math.floor(intensity * 255).toString(16).padStart(2, '0')}`);
} catch (error) {
console.error(`Failed to handle focus change:`, error);
}
}
}
async createInspirationWindow(): Promise<window.Window> {
const inspirationWindow = await window.createWindow({
name: 'inspiration_float',
windowType: window.WindowType.TYPE_FLOAT,
ctx: getContext()
});
await inspirationWindow.moveWindowTo(1200, 100);
await inspirationWindow.resize(320, 520);
await inspirationWindow.setWindowLayoutFullScreen(true);
await inspirationWindow.setWindowBackgroundColor('#00000000');
this.registerSubWindow('inspiration', inspirationWindow);
return inspirationWindow;
}
async createOutlineWindow(): Promise<window.Window> {
const outlineWindow = await window.createWindow({
name: 'outline_float',
windowType: window.WindowType.TYPE_FLOAT,
ctx: getContext()
});
await outlineWindow.moveWindowTo(50, 100);
await outlineWindow.resize(300, 450);
await outlineWindow.setWindowLayoutFullScreen(true);
await outlineWindow.setWindowBackgroundColor('#00000000');
this.registerSubWindow('outline', outlineWindow);
return outlineWindow;
}
async createStyleWindow(): Promise<window.Window> {
const styleWindow = await window.createWindow({
name: 'style_float',
windowType: window.WindowType.TYPE_FLOAT,
ctx: getContext()
});
await styleWindow.moveWindowTo(50, 580);
await styleWindow.resize(300, 200);
await styleWindow.setWindowLayoutFullScreen(true);
await styleWindow.setWindowBackgroundColor('#00000000');
this.registerSubWindow('style', styleWindow);
return styleWindow;
}
}
5.9 主页面集成(WritingStudioPage.ets)
typescript
// entry/src/main/ets/pages/WritingStudioPage.ets
import { WritingFlowLightEffect, WritingFlowPhase, WritingStyle } from '../components/WritingFlowLightEffect';
import { WritingFloatNavigation } from '../components/WritingFloatNavigation';
import { WritingEditor } from '../components/WritingEditor';
import { InspirationPanel } from '../components/InspirationPanel';
import { OutlineWindow } from '../windows/OutlineWindow';
import { WindowLightSync } from '../utils/WindowLightSync';
import { WritingAgentScheduler } from '../agents/WritingAgentScheduler';
@Entry
@Component
struct WritingStudioPage {
@State currentPage: string = 'WritePage';
@State wordCount: number = 0;
@State chapterProgress: number = 0;
@State currentStyle: WritingStyle = WritingStyle.CREATIVE;
@State isWriting: boolean = false;
private windowSync: WindowLightSync = WindowLightSync.getInstance();
private scheduler: WritingAgentScheduler = WritingAgentScheduler.getInstance();
aboutToAppear(): async () => {
await this.scheduler.initialize();
await this.initializeWindows();
this.startMetricsSync();
AppStorage.watch('nav_page_change', (page: string) => {
this.currentPage = page;
});
AppStorage.watch('current_style', (style: WritingStyle) => {
this.currentStyle = style;
});
}
private async initializeWindows(): Promise<void> {
await this.windowSync.createInspirationWindow();
await this.windowSync.createOutlineWindow();
await this.windowSync.createStyleWindow();
}
private startMetricsSync(): void {
AppStorage.watch('writing_metrics', (metrics: { wordCount: number; chapterProgress: number }) => {
this.wordCount = metrics.wordCount;
this.chapterProgress = metrics.chapterProgress;
// 同步光效
const phase = this.getCurrentPhase();
const themeColor = this.getPhaseColor(phase);
this.windowSync.syncGlobalLightEffect(themeColor, this.getIntensityByProgress());
});
}
private getCurrentPhase(): WritingFlowPhase {
// 简化计算,实际应根据时间
if (this.wordCount < 200) return WritingFlowPhase.SLOW;
if (this.wordCount < 500) return WritingFlowPhase.STEADY;
if (this.wordCount < 1000) return WritingFlowPhase.FLUID;
return WritingFlowPhase.FLOW;
}
private getPhaseColor(phase: WritingFlowPhase): string {
const colors: Record<WritingFlowPhase, string> = {
[WritingFlowPhase.SLOW]: '#1E3A8A',
[WritingFlowPhase.STEADY]: '#10B981',
[WritingFlowPhase.FLUID]: '#F59E0B',
[WritingFlowPhase.FLOW]: '#EF4444'
};
return colors[phase];
}
private getIntensityByProgress(): number {
if (this.chapterProgress > 70) return 1.0;
if (this.chapterProgress > 30) return 0.6;
return 0.3;
}
build() {
Stack() {
// 底层:沉浸光效层
WritingFlowLightEffect({
wordsPerHour: this.wordCount,
paragraphProgress: this.chapterProgress,
currentStyle: this.currentStyle
})
// 中层:主内容区域
Column() {
this.buildHeader()
Stack() {
if (this.currentPage === 'WritePage') {
WritingEditor()
} else if (this.currentPage === 'InspirationPage') {
InspirationPanel()
} else if (this.currentPage === 'OutlinePage') {
OutlineWindow()
} else if (this.currentPage === 'PolishPage') {
this.buildPolishPage()
}
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
// 顶层:悬浮导航
WritingFloatNavigation({
contentBuilder: () => {}
})
}
.width('100%')
.height('100%')
.backgroundColor('#050508')
.expandSafeArea(
[SafeAreaType.SYSTEM],
[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM, SafeAreaEdge.START, SafeAreaEdge.END]
)
}
@Builder
buildHeader(): void {
Row() {
Column() {
Text('✍️ 文思智脑')
.fontSize(20)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
Text(`字数: ${this.wordCount.toLocaleString()} | 进度: ${this.chapterProgress}% | 风格: ${this.getStyleLabel()}`)
.fontSize(12)
.fontColor('rgba(255,255,255,0.6)')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
Row({ space: 12 }) {
Button(this.isWriting ? ' ⏸️ 暂停' : '▶️ 开始写作')
.fontSize(13)
.fontColor('#FFFFFF')
.backgroundColor(this.isWriting ? '#F59E0B' : '#10B981')
.padding({ left: 20, right: 20, top: 8, bottom: 8 })
.borderRadius(20)
.onClick(() => {
this.isWriting = !this.isWriting;
})
Button('🤖 智能体面板')
.fontSize(13)
.fontColor('#FFFFFF')
.backgroundColor('rgba(255,255,255,0.1)')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(20)
.onClick(() => {
AppStorage.setOrCreate('show_agent_panel', true);
})
}
}
.width('100%')
.height(70)
.padding({ left: 24, right: 24 })
.backgroundBlurStyle(BlurStyle.REGULAR)
.backdropFilter($r('sys.blur.20'))
.border({
width: { bottom: 1 },
color: 'rgba(255,255,255,0.1)'
})
.justifyContent(FlexAlign.SpaceBetween)
}
private getStyleLabel(): string {
const labels: Record<WritingStyle, string> = {
[WritingStyle.ACADEMIC]: '学术',
[WritingStyle.LITERARY]: '文艺',
[WritingStyle.BUSINESS]: '商务',
[WritingStyle.CREATIVE]: '创意'
};
return labels[this.currentStyle];
}
@Builder
buildPolishPage(): void {
Column() {
Text('💎 智能润色')
.fontSize(18)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
// 润色选项
Grid() {
GridItem() {
this.buildPolishCard('语法检查', '修正语法错误', '#EF4444', '🔍')
}
GridItem() {
this.buildPolishCard('风格优化', '提升表达质量', '#8B5CF6', '✨')
}
GridItem() {
this.buildPolishCard('可读性', '优化阅读体验', '#06B6D4', '📖')
}
GridItem() {
this.buildPolishCard('精简表达', '去除冗余内容', '#10B981', '✂️')
}
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.width('90%')
.height(280)
.gap(16)
// 润色历史
Column() {
Text('📝 润色历史')
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Medium)
.margin({ bottom: 12 })
List() {
ForEach([
{ type: '语法', desc: '修正了3处主谓不一致', time: '2分钟前' },
{ type: '风格', desc: '优化了段落过渡表达', time: '5分钟前' },
{ type: '可读性', desc: '将长句拆分为短句', time: '10分钟前' }
], (record: { type: string; desc: string; time: string }) => {
ListItem() {
Row() {
Text(record.type)
.fontSize(11)
.fontColor('#FFFFFF')
.backgroundColor('rgba(139, 92, 246, 0.2)')
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.borderRadius(6)
.margin({ right: 8 })
Column() {
Text(record.desc)
.fontSize(12)
.fontColor('#FFFFFF')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(record.time)
.fontSize(10)
.fontColor('rgba(255,255,255,0.5)')
.margin({ top: 4 })
}
.layoutWeight(1)
}
.width('100%')
.padding(10)
.backgroundColor('rgba(255,255,255,0.03)')
.borderRadius(8)
}
.margin({ bottom: 6 })
})
}
.width('100%')
.height(180)
}
.width('90%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
.margin({ top: 20 })
}
.width('100%')
.height('100%')
}
@Builder
buildPolishCard(title: string, desc: string, color: string, icon: string): void {
Column() {
Text(icon)
.fontSize(32)
.margin({ bottom: 8 })
Text(title)
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Medium)
Text(desc)
.fontSize(11)
.fontColor('rgba(255,255,255,0.5)')
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.backgroundColor(`${color}15`)
.borderRadius(12)
.border({ width: 2, color: `${color}30` })
.justifyContent(FlexAlign.Center)
.onClick(() => {
// 触发对应润色功能
})
}
}
六、关键技术总结
6.1 HMAF智能写作智能体开发清单
| 技术点 | API/方法 | 应用场景 |
|---|---|---|
| 智能体会话创建 | hmaf.createAgentSession({ mode: MULTI_AGENT }) |
四层智能体协同写作 |
| 意图解析 | intents.createIntentEngine({ supportedDomains }) |
创作者指令意图识别 |
| 任务分发 | hmafSession.sendTask({ targetAgent, taskType }) |
智能体间写作任务调度 |
| 状态监听 | AppStorage 全局状态回调 |
跨组件写作状态同步 |
| 分布式协同 | enableDistributed: true |
多设备协作写作 |
| LLM灵感生成 | modelType: 'llm' |
灵感智能体推荐素材 |
| 大纲构建 | modelType: 'llm' |
大纲智能体构建结构 |
| 内容续写 | modelType: 'llm' |
生成智能体自动续写 |
6.2 沉浸光感实现清单
| 技术点 | API/方法 | 应用场景 |
|---|---|---|
| 系统材质效果 | systemMaterialEffect: SystemMaterialEffect.IMMERSIVE |
标题栏沉浸效果 |
| 背景模糊 | backgroundBlurStyle(BlurStyle.REGULAR) |
悬浮导航玻璃拟态 |
| 背景滤镜 | backdropFilter($r('sys.blur.20')) |
精细模糊控制 |
| 安全区扩展 | expandSafeArea([SafeAreaType.SYSTEM], [...]) |
全屏沉浸布局 |
| 窗口沉浸 | setWindowLayoutFullScreen(true) |
无边框模式 |
| 光效动画 | animation({ duration, iterations: -1 }) |
创作流脉搏呼吸灯 |
| 动态透明度 | backgroundOpacity |
焦点感知降级 |
| 窗口阴影 | setWindowShadow({ radius, color }) |
跨窗口光效联动 |
6.3 创作流阶段光效映射
| 创作流阶段 | 写作速度 | 主题色 | 脉冲周期 | 光效强度 |
|---|---|---|---|---|
| 慢速 | <200字/小时 | 深海蓝 #1E3A8A | 4秒 | 30% |
| 平稳 | 200-500字/小时 | 薄荷绿 #10B981 | 2秒 | 60% |
| 流畅 | 500-1000字/小时 | 活力橙 #F59E0B | 1秒 | 80% |
| 心流 | >1000字/小时 | 炽烈红 #EF4444 | 0.5秒 | 100% |
6.4 智能体状态徽章动画
| 智能体状态 | 徽章颜色 | 动画效果 | 写作含义 |
|---|---|---|---|
| 空闲 | #888888 | 静态 | 智能体待命 |
| 思考中 | #8B5CF6 | 呼吸脉冲 | LLM分析上下文中 |
| 执行中 | #F97316 | 旋转进度 | 生成/润色处理中 |
| 已完成 | #10B981 | 静态 | 任务执行成功 |
| 异常 | #EF4444 | 快速闪烁 | 生成内容异常 |
6.5 性能优化建议
- 光效渲染优化 :使用
willChange: true标记频繁变化的动画层,避免全量重绘 - 智能体并发控制 :通过
maxConcurrentAgents: 4限制并发,防止资源争抢 - 内容虚拟化:当文章超过10000字时,使用虚拟滚动
- 窗口管理 :子窗口使用
TYPE_FLOAT类型,避免创建过多独立进程 - 输入节流:写作分析频率控制在3秒/次,避免频繁调用智能体
七、总结与展望
本文基于HarmonyOS 6(API 23)的HMAF智能体框架、悬浮导航与沉浸光感特性,构建了一套面向PC端智能写作的"文思智脑"系统。核心创新点包括:
- 四层智能体协作架构:灵感、大纲、生成、润色四大智能体通过HMAF的A2A模式实时协作,将创作者从重复性构思中解放出来
- 创作流光效系统:基于实时写作速度与段落完成度的动态光效渲染,让创作者"看见"自己的创作状态
- 悬浮创作导航:底部玻璃拟态导航承载四大模块,智能体状态徽章实时反馈,创作信息一键展开
- 多窗口光效联动 :主窗口与三个浮动子窗口通过
WindowLightSync实现跨窗口光效同步,焦点感知自动调节 - 风格主题光效:基于当前写作风格渲染不同光效主题,学术蓝、文艺橙、商务青、创意紫
随着HarmonyOS生态的持续发展,智能写作智能体将向着"数字人写作伙伴""多模态交互""跨设备协作创作"等方向演进。HMAF框架的分布式能力与HarmonyOS的跨端协同特性,将为内容创作带来"一机控全局、多屏协同作"的全新体验。
转载自:https://blog.csdn.net/u014727709/article/details/161291623
欢迎 👍点赞✍评论⭐收藏,欢迎指正