Files
JianSu-Naming/step4.md

111 lines
3.9 KiB
Markdown
Raw Normal View History

采用**异步并行生成**Asynchronous Parallel Generation是目前平衡“高响应速度”与“AI 生成质量”最立竿见影的方案。
其核心思路是将原来“一个请求等五个名字”的线性过程,拆分为“多个并发请求同时生成名字”。
---
## 1. 后端重构:`MiniMaxService.java`
我们需要利用 Java 的 `CompletableFuture` 来并发调用 AI 接口。
```java
@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.js` 的 `fetchNames` 逻辑:
我们可以将请求拆分为两拨:一拨追求“极速响应”(先拿 2 个名字),二拨追求“完整体验”(再拿 3 个)。
```javascript
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` 中添加:
```html
<view wx:if="{{nameList.length === 0}}" class="loading-container">
<view class="ink-blob"></view>
<text class="loading-text">{{loadingQuote}}</text>
</view>
```
### 在 `index.js` 中添加文案轮换:
```javascript
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 秒左右。**