返回 AiToEarn
draft-generation.controller.ts
根目录 / project / aitoearn-backend / apps / aitoearn-ai / src / core / draft-generation / draft-generation.controller.ts
1 import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common'
2 import { ApiTags } from '@nestjs/swagger'
3 import { GetToken, Public, TokenInfo } from '@yikart/aitoearn-auth'
4 import { ApiDoc, ParseObjectIdPipe, UserType } from '@yikart/common'
5 import { DraftGenerationMemoryService } from './draft-generation-memory.service'
6 import {
7 CreateDraftFromVideoUrlDto,
8 CreateDraftFromVideoUrlDtoSchema,
9 CreateDraftGenerationV2Dto,
10 CreateDraftGenerationV2DtoSchema,
11 CreateImageTextDraftDto,
12 CreateImageTextDraftDtoSchema,
13 ListDraftGenerationMemoryDto,
14 ListDraftGenerationMemoryDtoSchema,
15 ListDraftGenerationTasksDto,
16 ListDraftGenerationTasksDtoSchema,
17 QueryDraftGenerationTasksDto,
18 QueryDraftGenerationTasksDtoSchema,
19 RegenerateDraftGenerationMemoryDto,
20 RegenerateDraftGenerationMemoryDtoSchema,
21 } from './draft-generation.dto'
22 import { DraftGenerationService } from './draft-generation.service'
23 import {
24 CreateDraftFromVideoUrlVo,
25 CreateDraftGenerationVo,
26 DraftGenerationMemoryVo,
27 DraftGenerationPricingVo,
28 DraftGenerationStatsVo,
29 DraftGenerationTaskListVo,
30 DraftGenerationTaskVo,
31 } from './draft-generation.vo'
32
33 @ApiTags('AI/Draft-Generation')
34 @Controller('/ai/draft-generation')
35 export class DraftGenerationController {
36 constructor(
37 private readonly draftGenerationService: DraftGenerationService,
38 private readonly draftGenerationMemoryService: DraftGenerationMemoryService,
39 ) { }
40
41 @ApiDoc({
42 summary: '获取草稿生成统计',
43 description: '获取当前用户草稿生成任务的统计信息(生成中数量)',
44 response: DraftGenerationStatsVo,
45 })
46 @Get('/stats')
47 async getStats(
48 @GetToken() token: TokenInfo,
49 ): Promise<DraftGenerationStatsVo> {
50 const stats = await this.draftGenerationService.getStats(token.id, UserType.User)
51 return DraftGenerationStatsVo.create(stats)
52 }
53
54 @ApiDoc({
55 summary: '草稿生成任务分页列表',
56 description: '分页查询当前用户的草稿生成任务列表',
57 query: ListDraftGenerationTasksDtoSchema,
58 response: DraftGenerationTaskListVo,
59 })
60 @Get('/')
61 async listTasksWithPagination(
62 @GetToken() token: TokenInfo,
63 @Query() query: ListDraftGenerationTasksDto,
64 ): Promise<DraftGenerationTaskListVo> {
65 const [list, total] = await this.draftGenerationService.listTasksWithPagination(query, token.id, UserType.User)
66 return new DraftGenerationTaskListVo(list, total, query)
67 }
68
69 @ApiDoc({
70 summary: '批量查询草稿生成任务',
71 description: '根据任务 ID 列表批量查询草稿生成任务状态',
72 body: QueryDraftGenerationTasksDtoSchema,
73 response: [DraftGenerationTaskVo],
74 })
75 @Post('/query')
76 async listTasks(
77 @GetToken() token: TokenInfo,
78 @Body() body: QueryDraftGenerationTasksDto,
79 ): Promise<DraftGenerationTaskVo[]> {
80 const tasks = await this.draftGenerationService.listTasks(body, token.id, UserType.User)
81 return tasks.map(task => DraftGenerationTaskVo.create(task))
82 }
83
84 @Public()
85 @ApiDoc({
86 summary: '获取草稿生成模型价格',
87 description: '获取图片生成和视频生成模型的价格信息',
88 response: DraftGenerationPricingVo,
89 })
90 @Get('/pricing')
91 getPricing(): DraftGenerationPricingVo {
92 return this.draftGenerationService.getDraftGenerationPricing()
93 }
94
95 @ApiDoc({
96 summary: '查询草稿生成 Memory',
97 query: ListDraftGenerationMemoryDtoSchema,
98 response: [DraftGenerationMemoryVo],
99 })
100 @Get('/memory')
101 async listMemory(
102 @GetToken() token: TokenInfo,
103 @Query() query: ListDraftGenerationMemoryDto,
104 ): Promise<DraftGenerationMemoryVo[]> {
105 const memories = await this.draftGenerationMemoryService.listMemories(token.id, query.contentType)
106 return memories.map(memory => DraftGenerationMemoryVo.create(memory))
107 }
108
109 @ApiDoc({
110 summary: '删除草稿生成 Memory 条目',
111 response: DraftGenerationMemoryVo,
112 })
113 @Delete('/memory/items/:itemId')
114 async deleteMemoryItem(
115 @GetToken() token: TokenInfo,
116 @Param('itemId') itemId: string,
117 ): Promise<DraftGenerationMemoryVo> {
118 const memory = await this.draftGenerationMemoryService.deleteItem(token.id, itemId)
119 return DraftGenerationMemoryVo.create(memory)
120 }
121
122 @ApiDoc({
123 summary: '重新生成草稿生成 Memory',
124 body: RegenerateDraftGenerationMemoryDtoSchema,
125 response: DraftGenerationMemoryVo,
126 })
127 @Post('/memory/regenerate')
128 async regenerateMemory(
129 @GetToken() token: TokenInfo,
130 @Body() body: RegenerateDraftGenerationMemoryDto,
131 ): Promise<DraftGenerationMemoryVo> {
132 const memory = await this.draftGenerationMemoryService.regenerateMemory(token.id, body.contentType, body.plannerModel)
133 return DraftGenerationMemoryVo.create(memory)
134 }
135
136 @ApiDoc({
137 summary: '查询单个草稿生成任务',
138 description: '根据任务 ID 查询草稿生成任务详情',
139 response: DraftGenerationTaskVo,
140 })
141 @Get('/:id')
142 async getTask(
143 @GetToken() token: TokenInfo,
144 @Param('id', ParseObjectIdPipe) id: string,
145 ): Promise<DraftGenerationTaskVo> {
146 const task = await this.draftGenerationService.getTask(id, token.id, UserType.User)
147 return DraftGenerationTaskVo.create(task)
148 }
149
150 /**
151 * V2: 直接调用 core/ai 服务的固定管线,省去 Agent 编排开销
152 *
153 * 流程:
154 * 1. [同步] 校验模型、解析素材组、创建 AiLog、投递队列(version=v2)
155 * 2. [异步] Consumer 路由到 generateContentV2:
156 * Gemini Flash 生成 prompt+元数据 → 生成视频 → 截帧封面 → 保存素材
157 */
158 @ApiDoc({
159 summary: '生成品牌内容草稿 (V2)',
160 description: '使用固定管线直接调用 AI 服务生成 TikTok 视频内容草稿。前端直接传入 model(如 grok-imagine-video)、duration、aspectRatio。返回 taskIds 可用于查询进度。',
161 body: CreateDraftGenerationV2DtoSchema,
162 response: CreateDraftGenerationVo,
163 })
164 @Post('/v2')
165 async createDraftsV2(
166 @GetToken() token: TokenInfo,
167 @Body() body: CreateDraftGenerationV2Dto,
168 ): Promise<CreateDraftGenerationVo> {
169 const taskIds = await this.draftGenerationService.createDraftsV2(token.id, UserType.User, body)
170 return CreateDraftGenerationVo.create({ taskIds })
171 }
172
173 @ApiDoc({
174 summary: '生成图文内容草稿',
175 description: '使用 AI 生成图文内容草稿。支持选择当前服务已接入的图片模型;非 Gemini 模型收到参考图时,会优先尝试编辑能力,否则忽略参考图继续生成。返回 taskIds 可用于查询进度。',
176 body: CreateImageTextDraftDtoSchema,
177 response: CreateDraftGenerationVo,
178 })
179 @Post('/image-text')
180 async createImageTextDrafts(
181 @GetToken() token: TokenInfo,
182 @Body() body: CreateImageTextDraftDto,
183 ): Promise<CreateDraftGenerationVo> {
184 const taskIds = await this.draftGenerationService.createImageTextDrafts(token.id, UserType.User, body)
185 return CreateDraftGenerationVo.create({ taskIds })
186 }
187
188 @ApiDoc({
189 summary: '视频 URL 生成草稿文案',
190 description: '传入纯视频 URL,使用 Gemini 多模态模型分析视频内容,自动生成标题、描述、话题并保存为草稿。同步返回草稿 ID。',
191 body: CreateDraftFromVideoUrlDtoSchema,
192 response: CreateDraftFromVideoUrlVo,
193 })
194 @Post('/from-video-url')
195 async createDraftFromVideoUrl(
196 @GetToken() token: TokenInfo,
197 @Body() body: CreateDraftFromVideoUrlDto,
198 ): Promise<CreateDraftFromVideoUrlVo> {
199 const result = await this.draftGenerationService.generateDraftFromVideoUrl(token.id, UserType.User, body)
200 return CreateDraftFromVideoUrlVo.create(result)
201 }
202 }
203
203 lines TYPESCRIPT