马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

View File

@@ -0,0 +1,274 @@
---
description:
globs:
alwaysApply: false
---
一、统一前置约定
1. Base URL
AppConfig.apiBaseUrl 内部已拼接 “/api/v1/” 前缀,所有请求 path 必须以 “/” 开头,禁止再次写 /api/v1/**。
示例:`post('/ai-chat/sessions/create')` ✅ `post('/api/v1/ai-chat/sessions/create')` ❌
2. HTTP 方法
• 除个别 GET-SSE小说导入进度所有接口一律使用 POST。
• 请求体、响应体统一 JSONSSE 数据位于 data 字段内,亦是 JSON。
3. 必备请求头
Authorization: Bearer {token}
X-User-Id: {userId}
Content-Type: application/json Multipart 上传除外)
SSE 额外头:
Accept: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
4. novelId 隔离
所有 AI 聊天 / 记忆模式 / 剧情推演及小说相关接口均需 novelId。前端省略将直接 4XX。旧版不带 novelId 方法已 @Deprecated。
────────────────────────────────────────
二、非流式(普通 HTTP调用规范
1. 调用方式
await apiClient.post('/路径', data: {…});
Options 可选;大部分接口已经在 ApiClient 二次封装,优先调用对应 repository 方法。
2. 超时
connect 30s / send 30s / receive 5min已在 ApiClient 配置)
3. 错误处理
后端统一错误 JSON`{ "code": -1, "message": "错误描述", "error": "可选详情" }`
ApiClient 已将 401 拦截并自动调用 AuthService.logout()。其它错误统一抛 ApiException(statusCode,msg)。
────────────────────────────────────────
三、SSE 流式请求规范
1. 前端封装
使用 SseClient().streamEvents<T>(…) 或 ApiClient.postStream + _processStream。
2. 通用请求头与 Options
见「统一请求头」,并在 Dio Options 中声明 responseType: ResponseType.stream。
3. 事件格式(后端 ServerSentEvent
id: {uuid} ❘ 可选
event: {eventName}
data: {JSON 字符串或 [DONE]}
\n\n 分隔多条记录
4. 事件名称白名单
chat-message AI 聊天普通/流式块
chat-error AI 聊天错误
chat-message-memory 记忆模式聊天
outline-chunk 剧情推演
message 通用 AI
complete 通用 AI 结束data 为 {"data":"[DONE]"}
5. 结束判定
• 收到一条 data: [DONE] → 正常结束
• 收到 event: complete → 正常结束
• 服务器主动关闭连接 → onDone
• 本地 5 分钟未收包 → ApiClient 内置心跳超时会自动 addError & close
6. 前端过滤范式(示例 chat_repository_impl
.streamEvents(...).where((event)=>
event.sessionId == currentSession && event.content != 'heartbeat');
────────────────────────────────────────
四、路径与 DTO 命名
1. 路径
POST /{模块}/{动作} 例:/novels/create
POST /{模块}/{资源}/{动作} 例:/ai-chat/messages/stream
SSE 路径保持同 POST 规则,仅响应类型不同。
2. 请求 DTO/VO
• {Action}{Resource}Dto / Request / Response
• SessionCreateDto, ImportPreviewRequest …
• 流式请求的 DTO 放 body不走 query。
────────────────────────────────────────
五、文件上传 & 导入
1. Multipart FormData 字段
file 文件
userId (备用)
2. 三步导入
/upload-preview → 返回 previewSessionId
/preview → 返回章节解析预览
/confirm → 返回 jobId
进度监听 GET /novels/import/{jobId}/status SSE event: data = ImportStatus JSON
3. 长连接心跳
ApiClient.connectToLongRunningSSE 已内建 15s 心跳日志2min 静默 → 本地进度提醒5min → 超时断线。
────────────────────────────────────────
六、特殊模块注意
1. AI 聊天
• 创建会话 /ai-chat/sessions/create
• 流式发消息 /ai-chat/messages/stream Body 必含 userId、novelId、sessionId、content
• metadata 可携带 aiConfig详见 extractAIConfigFromMetadata
• 事件过滤status==streaming 可用于打字机效果,最终完整消息 id 不以 temp_chunk_ 开头。
2. 记忆模式
• 路径加 -with-memoryevent 名改为 chat-message-memory / chat-error-memory。
• 需要 memoryConfig 字段。
3. 剧情推演
• POST /novels/{novelId}/next-outlines/generate-stream
• event: outline-chunk
• 如遇 code+message 错误 JSON解析器需 throw ApiException。
4. Universal AI多功能 AI
• 非流式 /ai/universal/request
• 流式 /ai/universal/stream event: message / complete
• 预估费用 /ai/universal/estimate-cost
• 预览提示 /ai/universal/preview
────────────────────────────────────────
七、客户端实现要点Dart 侧)
1. ApiClient 已封装常用 CRUD优先通过各 Repository避免重复实现。
2. 401 在拦截器中自动登出,无需额外判断。
3. 日志等级AppConfig.logLevel生产默认 info调试可设 warning 输出请求/响应体。
4. 模型 & 配置缓存
ChatRepositoryImpl 内部维护 novelId→sessionId→UniversalAIRequest 缓存,注意同步 & 清理。
5. 批量场景上传
统一使用 /novels/upsert-chapter-scenes-batch数据结构符合 ChapterScenesDto。
────────────────────────────────────────
八、测试 Checklist提交前自检
☐ 请求 path 无 “/api/v1” 重复
☐ 必填头 Authorization / X-User-Id 已附加
☐ POST body 为 JSONSSE 请求 Accept:text/event-stream
☐ novelId 已在 body 或 path 中提供
☐ 错误码 & message 正确解析401 能触发登出
☐ SSE 解析:支持 event/data/id多行合并识别 [DONE]/complete
☐ 心跳或空行已过滤,打字机流块保留
☐ 长连接超时重连(最多 3 次)逻辑正常
☐ 文件上传 Multipart/form-data字段 file / userId
☐ 日志在 debug 模式下可输出请求体 & 响应体
后端约束
一、通用约束
1. 路径前缀
所有 Controller 均挂载在 “/api/v1/**”,切勿在内部拼接重复前缀。
2. 返回类型
• 非流式Mono<T> / Flux<T> ↔ HTTP 200|201。
• 流式 Flux<ServerSentEvent<…>> ↔ Content-Type text/event-stream。
3. DTO & 命名
• 输入 DTOSessionCreateDto / ImportPreviewRequest / PaginatedScenesRequestDto …
• 输出 DTONovelWithScenesDto / ChaptersForPreloadDto …
• 统一放在 web.dto 包;禁止 Controller 直接暴露实体 Entity。
4. 参数校验
• 使用 jakarta.validation @Valid并在 DTO 字段加 @NotBlank @NotNull。
• Controller 若自行拼 Map<String,String>,在进入 Service 前必须手动判空并抛 ResponseStatusException 400。
5. 身份认证
• 使用 @CurrentUser 解析出 userId如为空必须回退表单 userId仍为空则返回 401。
• 鉴权逻辑统一在 Service 层做二次校验session 属主、novel 属主等)。
• jwt配置 SecurityConfig需要增加新端点
6. novelId 隔离
• AIChatService / NovelService 等新接口必须带 novelId 版本,旧方法保留 @Deprecated 标记。
• Controller 在调用旧 Service 时,先 getSession(userId, novelId, sessionId) 校验归属。
7. 错误响应规范
```json
{ "code": -1, "message": "错误描述", "error": "可选堆栈/详情" }
```
• Controller 捕获异常后统一封装,避免直接返回 500 HTML。
• SSE 端点 onErrorResume 时应推送 chat-error / outline-error 之类事件,或者 data: {"code":-1,"message":"xxx"}。
────────────────────────────────────────
二、SSE 端点实现要求
1. 标准包装
```java
ServerSentEvent.<T>builder()
.id(UUID.randomUUID().toString())
.event("chat-message") // 见事件白名单
.data(payload) // payload 为对象,框架自动 JSON 序列化
.retry(Duration.ofSeconds(10))
.build();
```
2. 事件名称
chat-message | chat-error | chat-message-memory | outline-chunk | message | complete
其它请先在前后端约定后再扩展。
3. 结束规则
• 业务方最后 concat 一个 complete / data:[DONE] 信号,或正常 close。
• 服务器不得无限保持空闲长连接;无事件 2-3min 应考虑心跳注释 “:heartbeat”。
4. 流速控制
使用 `.delayElements(Duration.ofMillis(50))` 或下游 buffer避免单秒百条刷屏。
5. 订阅日志
`doOnSubscribe` 记录连接;`doOnCancel` / `doOnError` 记录关闭与异常,方便排障。
────────────────────────────────────────
三、模块专项
1. AI 聊天 (AIChatController)
• createSession / getSession / listSessions / update / delete / count 全量支持 novelId。
• streamMessage() 必须先 extractAIConfigFromMetadata() → UniversalAIRequestDto如无配置降级旧接口。
• 错误时返回 chat-error 事件data 为 AIChatMessagerole=system, status=ERROR
2. 记忆模式
• routes 加后缀 -with-memory事件名 chat-message-memory / chat-error-memory。
• ChatMemoryConfigDto 转 domainService 侧负责窗口剪裁。
3. Novel 管理 (NovelController)
• get-with-paginated-scenes 等分页接口必须校验 chaptersLimit 1-10。
• load-more-scenes direction 仅允许 up/down/center非法值 400。
• 细粒度增删改add-act-fine / delete-scene-fine 等)只处理局部,无需回整本 DTO前端自动拉取最新结构。
• /import 流程upload-preview → preview → confirm每步严格校验必要字段并返回友好错误。
4. Next-Outline (剧情推演)
• generate-stream / regenerate-option 均推 outline-chunk。
• Service 内部 chunk.size 建议 ≤ 5KB过大前端解析慢。
5. Universal AI
• /stream 结尾必须 concat 完成事件 `event:complete data:{"data":"[DONE]"}`。
• /estimate-cost 返回 {success, estimatedCost, errorMessage},不可抛异常给前端。
────────────────────────────────────────
四、性能 & 稳定性
1. I/O 超时
• WebClient/DQL 调 OpenAI 等第三方应限 2min大任务另行异步处理并用 SSE 推进度。
2. 压力保护
• 单 userId 并发流连接 ≤ 10可在 Service 层做计数。
• 若超额返回 429 JSON 并在 SSE 推送 error 事件。
3. 日志
• slf4j 级别info 记录业务流程 & 关键IDdebug 打开 JSON 细节error 打印堆栈。
• 不得在生产输出完整 prompt / apiKey。
────────────────────────────────────────
五、代码质量守则
1. Controller 只做参数检查 + 日志 + 调 Service禁止业务逻辑堆叠。
2. Service 返回 Mono.error 时务必带语义化 message前端直接展示。
3. DTO 层禁止 Lombok @Data使用 @Getter/@Setter 或 record避免 JSON 循环引用。
4. 所有 Mono/Flux 链路结尾必须 `onErrorResume` 友好处理,不能把 Reactor 异常原样抛给客户。
5. 不得在 SSE 控制器里使用 `share()` 导致多次订阅;一个请求一个冷流或 Service 级共享 hot 流。
────────────────────────────────────────
六、提交前检查清单(后端)
☐ 路径不含重复 /api/v1
☐ DTO 字段 @NotBlank 检验通过,全局异常处理返回统一结构
☐ novelId 校验正确,跨用户/跨小说数据隔离
☐ SSE 事件名符合白名单,结尾发送 complete 或 [DONE]
☐ 日志不输出敏感信息(apiKey, prompt)
☐ 新增接口在 Controller + Service + DTO 均写单元测试