打造一个可定制工作流的桌面女友

本文作者为 360 奇舞团前端开发工程师

你是否想过拥有一个可以自定义行为的桌面虚拟角色?本文将带你从零开始,打造一个基于 Live2D 的桌面女友,并赋予她可定制的工作流能力。通过 Electron + LangGraph 的组合,我们可以创建一个既可爱又智能的桌面应用。

通过本项目,你能得到什么:

  1. 一位常驻桌面的虚拟女友:使用 Live2D 技术打造的可爱角色,可以常驻桌面,陪伴你的工作时光

  2. 可定制的工作流系统:通过 LangGraph 构建的工作流引擎,让虚拟角色能够执行各种自定义任务和逻辑

  3. 模板管理系统:可以保存、复用和分享工作流模板,提高工作效率

  4. 高度可扩展的架构:模块化设计,可以轻松添加新的步骤类型、集成 AI 对话、文件操作等功能

项目概览

在开始之前,让我们先了解一下整个项目的架构:

┌─────────────────────────────────────────────────────────┐
│                    用户交互层                             │
│  ┌──────────────┐         ┌──────────────┐              │
│  │  Live2D 模型 │         │  工作流管理  │                │
│  │   (桌面女友)  │         │   界面       │               │
│  └──────────────┘         └──────────────┘              │
└─────────────────────────────────────────────────────────┘
                        ↕
┌─────────────────────────────────────────────────────────┐
│                  Electron 应用层                          │
│  ┌──────────────┐         ┌──────────────┐              │
│  │  Express 服务 │         │  BrowserWindow│             │
│  │  (静态资源)   │         │  (工作流UI)  │               │
│  └──────────────┘         └──────────────┘              │
└─────────────────────────────────────────────────────────┘
                        ↕
┌─────────────────────────────────────────────────────────┐
│                 工作流服务层                               │
│  ┌──────────────┐         ┌──────────────┐              │
│  │  FastAPI     │         │  LangGraph   │              │
│  │  (REST API)  │         │  (工作流引擎) │               │
│  └──────────────┘         └──────────────┘              │
└─────────────────────────────────────────────────────────┘

整个系统分为三个层次:

  1. 用户交互层:Live2D 模型交互和工作流管理界面

  2. Electron 应用层:桌面应用框架和资源服务

  3. 工作流服务层:后端 API 和工作流执行引擎


第一步:获取 Live2D 免费模型

Live2D 官方提供了丰富的免费示例模型,我们可以直接下载使用。

访问下载页面

打开 Live2D 官方示例数据集页面:https://www.live2d.com/zh-CHS/learn/sample/

在这个页面上,你可以看到多个免费模型,包括:

  • Haru:一个可爱的女孩角色

  • Nito:二头身卡通角色

下载模型文件

选择一个你喜欢的模型(推荐从 Haru 开始),下载 FREE 版本。下载后的文件结构通常如下:

haru/
├── haru_greeter_t05.moc3          # 模型数据文件
├── haru_greeter_t05.physics3.json # 物理效果配置
├── haru_greeter_t05.pose3.json    # 姿势配置
├── haru_greeter_t05.cdi3.json     # 显示辅助文件
├── index.json                      # 模型索引文件
├── texture_00.png                  # 纹理贴图
├── texture_01.png                  # 纹理贴图
└── motion/                         # 动作文件夹
    ├── haru_g_idle.motion3.json   # 待机动作
    └── ...                         # 其他动作文件

放置模型文件

将下载的模型文件夹放到项目的 electron/live2d/model/ 目录下,例如:

electron/
└── live2d/
    └── model/
        └── haru/          # 你下载的模型文件夹
            ├── index.json
            └── ...

第二步:初始化 Electron + Live2D 项目

项目结构

首先,我们需要创建一个 Electron 项目,并集成 Live2D 显示功能。这里使用 live2d-widget 项目的构建工程集成 Live2D。

添加构建工程

将下载 live2d-widget 工程放到以下目录:

electron/
└── live2d/
    └── live2d-widget/

安装依赖

在 electron 目录下创建 package.json

{
  "name": "wenko",
"version": "1.0.0",
"main": "main.js",
"scripts": {
    "start": "electron ."
  },
"dependencies": {
    "electron": "^latest",
    "express": "^4.18.0"
  }
}

然后运行:

npm install

创建主窗口

创建 index.html 文件,用于显示 Live2D 模型:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Wenko</title>
</head>
<body>
  <div id="wenko_wifu"></div>
  <script src="http://localhost:8080/live2d/live2d-widget/dist/autoload.js"></script>
</body>
</html>

这里我们通过 localhost:8080 来加载 Live2D 的资源文件,这个服务我们会在下一步创建。

live2d-widget 项目和 Live2D 模型有什么关系?

live2d-widget 项目不包括任何模型,仅负责在网页中加载和运行 Live2D 模型。具体逻辑可参考 autoload.js 。


第三步:配置 Express 静态资源服务

为了让 Live2D 模型文件能够正常加载,我们需要在 Electron 主进程中启动一个 Express 服务器来提供静态文件服务。

修改 main.js

打开 electron/main.js,添加 Express 服务器:

const { app, BrowserWindow } = require('electron');
const path = require('path');
const express = require('express');

// 创建 Express 服务器提供 live2d 静态文件访问
function createStaticServer() {
const expressApp = express();
const port = 8080;

// 提供 live2d 目录的静态文件访问
  expressApp.use('/live2d', express.static(path.join(__dirname, 'live2d')));

  expressApp.listen(port, () => {
    console.log(`Static server running on http://localhost:${port}`);
  });
}

// 启动静态文件服务器
createStaticServer();

// 创建 Electron 窗口
function createWindow() {
const mainWindow = new BrowserWindow({
    width: 350,
    height: 400,
    frame: false,
    transparent: true,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      webSecurity: false
    }
  });

  mainWindow.loadFile('index.html');
}

app.whenReady().then(() => {
  createWindow();
});

工作流程

┌─────────────────┐
│  Electron 启动   │
└────────┬─────────┘
         │
         ├──> 启动 Express 服务器 (端口 8080)
         │    └──> 提供 /live2d/* 静态资源
         │
         └──> 创建 BrowserWindow
              └──> 加载 index.html
                   └──> 通过 http://localhost:8080/live2d/... 加载模型

为什么需要 Express 服务器?

Live2D 的模型文件(.moc3.json.png 等)需要通过 HTTP 协议加载。虽然 Electron 支持 file:// 协议,但某些情况下会遇到跨域问题。使用 Express 提供 HTTP 服务可以:

  1. 避免跨域问题:统一使用 HTTP 协议

  2. 便于调试:可以在浏览器中直接访问资源

  3. 灵活配置:可以添加缓存、压缩等中间件


第四步:构建工作流系统

现在,让我们为桌面女友添加"大脑"——一个可定制的工作流系统。

初始化 LangGraph 项目

在项目根目录下创建 workflow 目录,并初始化 Python 项目:

首先安装 uv(如果还没有安装):

curl -LsSf https://astral.sh/uv/install.sh | sh

然后初始化项目

mkdir workflow
cd workflow

# 使用 uv 初始化项目
uv init

# 添加依赖
uv add langgraph langgraph-cli fastapi uvicorn httpx pydantic python-dotenv

项目结构

workflow/
├── main.py          # FastAPI 应用入口
├── executor.py      # 工作流执行器
├── steps.py         # 步骤定义
├── graph.py         # LangGraph 图定义
├── control_steps.py # 控制流步骤(If/Then/Else)
└── pyproject.toml   # 项目配置

核心组件解析

1. steps.py - 步骤定义

steps.py 定义了所有可用的工作流步骤。每个步骤都是一个类,继承自 Step 基类:

class Step(ABC):
    """步骤基类"""
    
    def __init__(self, step_type: str, params: Dict[str, Any]):
        self.step_type = step_type
        self.params = params
    
    @abstractmethod
    def execute(self, context: StepContext) -> Any:
        """执行步骤"""
        pass

步骤类型示例

  • SetVar:设置变量

    {
      "type": "SetVar",
      "params": {
        "key": "greeting",
        "value": "Hello, World!"
      }
    }
  • GetVar:获取变量

    {
      "type": "GetVar",
      "params": {
        "key": "greeting"
      }
    }
  • EchoInput:回显输入

    {
      "type": "EchoInput",
      "params": {
        "input_key": "user_input",
        "output_key": "response"
      }
    }

步骤注册表

所有步骤都注册在 STEP_REGISTRY 中,方便动态创建:

STEP_REGISTRY = {
    'EchoInput': EchoInputStep,
    'SetVar': SetVarStep,
    'GetVar': GetVarStep,
    # ... 更多步骤类型
}
2. executor.py - 工作流执行器

executor.py 负责执行工作流步骤序列:

class WorkflowExecutor:
    """工作流执行器"""
    
    def execute(self, steps: List[Dict], initial_context: Dict = None):
        # 创建上下文
        context = StepContext(initial_context or {})
        
        # 依次执行每个步骤
        for step_config in steps:
            step_type = step_config.get('type')
            step_params = step_config.get('params', {})
            
            # 从注册表创建步骤实例
            step = create_step(step_type, step_params)
            
            # 执行步骤
            result = step.execute(context)
        
        return {
            'success': True,
            'result': context.variables
        }

执行流程

┌─────────────────┐
│  工作流请求      │
│  {               │
│    steps: [...], │
│    context: {}   │
│  }               │
└────────┬─────────┘
         │
         v
┌─────────────────┐
│  WorkflowExecutor│
└────────┬─────────┘
         │
         v
┌─────────────────┐      ┌──────────────┐
│  StepContext    │<─────│  变量存储     │
│  (上下文)        │      │  variables   │
└────────┬────────┘      └──────────────┘
         │
         v
┌─────────────────────────────────────┐
│  遍历步骤列表                        │
│  ┌──────────┐  ┌──────────┐        │
│  │ Step 1   │→ │ Step 2   │→ ...   │
│  └──────────┘  └──────────┘        │
└─────────────────────────────────────┘
         │
         v
┌─────────────────┐
│  返回执行结果    │
│  {               │
│    success: true,│
│    result: {...} │
│  }               │
└─────────────────┘
3. main.py - REST API 接口

main.py 使用 FastAPI 提供 RESTful API:

核心接口

  1. 执行工作流 - POST /run

    @app.post("/run", response_model=WorkflowResponse)
    async def run_workflow(request: WorkflowRequest):
        executor = WorkflowExecutor()
        result = executor.execute(
            steps=request.steps,
            initial_context=request.initial_context or {}
        )
        return result
  2. 模板管理接口

  • POST /templates - 创建模板

  • GET /templates - 列出所有模板

  • GET /templates/{id} - 获取模板详情

  • PUT /templates/{id} - 更新模板

  • DELETE /templates/{id} - 删除模板

  • GET /templates/search/{query} - 搜索模板

  • POST /templates/{id}/execute - 执行模板

  • 系统接口

    • GET /health - 健康检查

    • GET /steps - 获取步骤注册表

    API 调用示例

    # 执行工作流
    curl -X POST http://localhost:8002/run \
      -H "Content-Type: application/json" \
      -d '{
        "steps": [
          {
            "type": "SetVar",
            "params": {"key": "name", "value": "Wenko"}
          },
          {
            "type": "EchoInput",
            "params": {"input_key": "name", "output_key": "greeting"}
          }
        ],
        "initial_context": {}
      }'

    启动服务

    cd workflow
    uv run python main.py

    服务启动后,访问 http://localhost:8002/docs 可以看到自动生成的 API 文档。


    第五步:构建工作流管理界面

    最后,我们需要一个友善的界面来管理模板和执行工作流。

    修改 main.js 添加工作流窗口

    在 electron/main.js 中添加快捷键监听,打开工作流管理窗口:

    ipcMain.on('wenko_shortcut', async (event, data) => {
    // 处理快捷键事件: action: open
    const { action } = data;
    if (action === 'open') {
        const shortcutWindow = new BrowserWindow({
          width: 1200,
          height: 800,
          title: 'Workflow API 测试工具',
          icon: path.join(__dirname, 'assets', 'favicon.ico'),
          frame: true,
          transparent: false,
          alwaysOnTop: false,
          resizable: true,
          hasShadow: true,
          fullscreenable: true,
          skipTaskbar: false,    // 在任务栏显示
          webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: false,
            contextIsolation: true,
            webSecurity: false// 关闭同源策略和 CSP 检查,方便开发加载任意脚本
          }
        });
        shortcutWindow.loadFile('workflow.html');
      } else {
        console.warn('Unknown action:', action);
      }
    });

    workflow.html 功能模块

    workflow.html 使用 React + Ant Design 构建,包含以下功能:

    1. 工作流执行标签页
    ┌─────────────────────────────────────┐
    │  工作流执行                          │
    ├─────────────────────────────────────┤
    │  工作流步骤 (JSON)                   │
    │  ┌───────────────────────────────┐  │
    │  │ [                            │  │
    │  │   {"type": "SetVar", ...}    │  │
    │  │ ]                            │  │
    │  └───────────────────────────────┘  │
    │                                      │
    │  初始上下文 (JSON, 可选)              │
    │  ┌───────────────────────────────┐  │
    │  │ {"key": "value"}              │  │
    │  └───────────────────────────────┘  │
    │                                      │
    │  ☑ 调试模式                          │
    │                                      │
    │  [执行工作流] [加载示例] [清空]      │
    └─────────────────────────────────────┘
    2. 模板管理标签页
    ┌─────────────────────────────────────┐
    │  模板管理                            │
    ├─────────────────────────────────────┤
    │  [+ 创建新模板]                      │
    │                                      │
    │  ┌───────────────────────────────┐  │
    │  │ 模板名称                        │  │
    │  │ 描述:这是一个示例模板...        │  │
    │  │ 标签:[基础] [示例]              │  │
    │  │ [查看] [执行] [编辑] [删除]     │  │
    │  └───────────────────────────────┘  │
    └─────────────────────────────────────┘
    3. 步骤注册表标签页

    显示所有可用的步骤类型:

    ┌─────────────────────────────────────┐
    │  步骤注册表                          │
    ├─────────────────────────────────────┤
    │  [刷新步骤列表]                      │
    │                                      │
    │  ┌──────┐ ┌──────┐ ┌──────┐        │
    │  │EchoInput│ │SetVar│ │GetVar│        │
    │  └──────┘ └──────┘ └──────┘        │
    │  ┌──────┐ ┌──────┐ ┌──────┐        │
    │  │FetchURL│ │ParseJSON│ │...│        │
    │  └──────┘ └──────┘ └──────┘        │
    └─────────────────────────────────────┘

    模板执行流程

    当用户点击"执行"按钮时:

    ┌─────────────────┐
    │  用户点击执行    │
    └────────┬────────┘
             │
             v
    ┌─────────────────┐
    │  弹出对话框      │
    │  让用户输入上下文│
    └────────┬────────┘
             │
             v
    ┌─────────────────┐
    │  调用 API        │
    │  POST /templates/│
    │  {id}/execute    │
    └────────┬────────┘
             │
             v
    ┌─────────────────┐
    │  显示执行结果    │
    └─────────────────┘

    完整系统架构

    现在,让我们看看整个系统是如何协作的:

    ┌─────────────────────────────────────────────────────────────┐
    │                      用户操作流程                              │
    └─────────────────────────────────────────────────────────────┘
                                │
                                v
            ┌───────────────────────────────────┐
            │  1. 启动 Electron 应用              │
            │     - 显示 Live2D 模型             │
            │     - 启动 Express 静态服务         │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  2. 与 Live2D 模型交互打开管理界面     │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  3. 在工作流界面中:                │
            │     - 创建/编辑模板                 │
            │     - 执行工作流                    │
            │     - 查看步骤注册表                │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  4. 前端调用 FastAPI                │
            │     http://localhost:8002/...       │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  5. FastAPI 处理请求                │
            │     - 解析 JSON                     │
            │     - 调用 WorkflowExecutor         │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  6. WorkflowExecutor 执行步骤      │
            │     - 创建 StepContext             │
            │     - 遍历步骤列表                 │
            │     - 执行每个步骤                 │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  7. 返回执行结果                    │
            │     - 成功/失败状态                 │
            │     - 上下文变量                    │
            └───────────────┬─────────────────────┘
                            │
                            v
            ┌───────────────────────────────────┐
            │  8. 前端显示结果                    │
            │     - 成功提示                     │
            │     - 结果 JSON 展示               │
            └───────────────────────────────────┘

    使用示例

    示例 1:简单的问候工作流

    {
      "steps": [
        {
          "type": "SetVar",
          "params": {
            "key": "name",
            "value": "Wenko"
          }
        },
        {
          "type": "TemplateReplace",
          "params": {
            "template": "你好,{{name}}!今天过得怎么样?",
            "template_key": null,
            "output_key": "greeting"
          }
        }
      ],
    "initial_context": {}
    }

    执行结果:

    {
      "success": true,
      "result": {
        "name": "Wenko",
        "greeting": "你好,Wenko!今天过得怎么样?"
      }
    }

    总结

    通过本文,我们完成了一个完整的可定制工作流桌面女友系统:

    1. ✅ Live2D 模型集成:从官网下载免费模型并集成到 Electron

    2. ✅ 静态资源服务:使用 Express 提供模型文件访问

    3. ✅ 工作流引擎:基于 LangGraph 构建可扩展的工作流系统

    4. ✅ REST API:提供完整的模板管理和执行接口

    5. ✅ 管理界面:友好的 Web 界面用于模板管理

    这个系统具有很强的扩展性:

    • 可以添加更多步骤类型(如 AI 对话、文件操作等)

    • 可以集成更多 Live2D 模型和动作

    • 可以添加数据库持久化模板

    • 可以实现工作流与 Live2D 模型的联动(根据工作流结果触发模型动作)

    希望这篇文章能帮助你打造属于自己的智能桌面女友!🚀


    参考资源

    Live2D 官方示例数据集 https://www.live2d.com/zh-CHS/learn/sample/
    live2d-widget 项目 https://github.com/stevenjoezhang/live2d-widget
    LangGraph 官方文档 https://langchain-ai.github.io/langgraph/
    FastAPI 官方文档 https://fastapi.tiangolo.com/
    Electron 官方文档 https://www.electronjs.org/
    本项目仓库 https://github.com/daijinru/wenko

    -END -

    如果您关注前端+AI 相关领域可以扫码进群交流

    添加小编微信进群😊

    关于奇舞团

    奇舞团是 360 集团最大的大前端团队,非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值