Files
JianSu-Naming/step4.md
王鹏 be1f5722ab feat: 完成见素起名小程序核心功能
- 实现 AI 起名功能(Kimi API 接入)
- 添加用户收藏功能(MySQL 数据库)
- 实现海报生成与分享
- 添加音效和触觉反馈
- 配置生产环境部署(WAR 包 + Nginx)
- 支持多种起名模式(经典、诗词、自然、现代)
- 实现分批加载优化体验
2026-04-17 15:34:51 +08:00

3.9 KiB
Raw Blame History

采用异步并行生成Asynchronous Parallel Generation是目前平衡“高响应速度”与“AI 生成质量”最立竿见影的方案。

其核心思路是将原来“一个请求等五个名字”的线性过程,拆分为“多个并发请求同时生成名字”。


1. 后端重构:MiniMaxService.java

我们需要利用 Java 的 CompletableFuture 来并发调用 AI 接口。

@Service
public class MiniMaxService {

    // 模拟原有的单次生成逻辑
    private NameCard callAiToGenerateSingleName(String keyword, String mode, String surname) {
        // 这里是原有的 MiniMax API 调用逻辑,但只要求它返回 1 个名字
        // ... 
    }

    public List<NameCard> generateNamesAsync(String keyword, String mode, String surname) {
        int count = 5; // 我们需要生成 5 个名字
        List<CompletableFuture<NameCard>> futures = new ArrayList<>();

        for (int i = 0; i < count; i++) {
            // 为每个名字开启一个异步线程
            CompletableFuture<NameCard> future = CompletableFuture.supplyAsync(() -> {
                return callAiToGenerateSingleName(keyword, mode, surname);
            });
            futures.add(future);
        }

        // 等待所有线程完成(或部分完成即可返回,提升容错)
        return futures.stream()
                .map(CompletableFuture::join) // 合并结果
                .collect(Collectors.toList());
    }
}

为什么这样做更快?

  • 线性模式AI 生成 5 个名字的时间 = $T1 + T2 + T3 + T4 + T5$(通常需要 8-12 秒)。
  • 并行模式:总耗时 = $max(T1, T2, T3, T4, T5)$(通常只需 2-3 秒)。

2. 前端感知优化:伪流式展示

虽然后端并行生成了结果,但如果我们等 5 个全部完成再返回,前端仍有空窗期。我们可以配合前端做一个“分批次渲染”。

修改 index.jsfetchNames 逻辑:

我们可以将请求拆分为两拨:一拨追求“极速响应”(先拿 2 个名字),二拨追求“完整体验”(再拿 3 个)。

fetchNames(keyword, mode, surname) {
  // 1. 发起第一波请求:先取 2 个名字,让用户立刻有卡片可以翻
  this.requestNamingApi(keyword, mode, surname, 2).then(firstBatch => {
    this.setData({
      nameList: firstBatch,
      currentIndex: 0
    });
    
    // 2. 第一波成功后,静默发起第二波请求:补齐剩下的名字
    this.requestNamingApi(keyword, mode, surname, 3).then(secondBatch => {
      this.setData({
        nameList: [...this.data.nameList, ...secondBatch]
      });
    });
  });
}

3. 仪式感补偿Loading 文案池

为了让异步加载的 1-2 秒不尴尬,在 home.js 跳转到 index.js 时,利用一个动态的文案池来分散用户注意力。

index.wxml 中添加:

<view wx:if="{{nameList.length === 0}}" class="loading-container">
  <view class="ink-blob"></view>
  <text class="loading-text">{{loadingQuote}}</text>
</view>

index.js 中添加文案轮换:

const quotes = [
  "正在翻阅《古今集成》...",
  "字里行间,寻觅归处...",
  "笔墨将就,意境自生...",
  "正在感悟山川意向..."
];

// 在 onLoad 中开启定时器
this.loadingTimer = setInterval(() => {
  this.setData({
    loadingQuote: quotes[Math.floor(Math.random() * quotes.length)]
  });
}, 2000);

🛠️ 实施建议

  1. 后端线程池:在使用 CompletableFuture 时,务必自定义一个 Executor(线程池),不要使用默认的 ForkJoinPool,防止在高并发下把后端拖垮。
  2. 音律分析延迟:如果 ToneAnalysisService 依然很慢,可以先返回名字和出处,音律评分字段标记为“计算中”,待卡片翻转时再动态获取。

这套“并行生成 + 分批返回”的方案,能将用户的体感等待时间从 10 秒以上直接压缩到 2 秒左右。