ai-content.controller.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. "use strict";
  2. /**
  3. * AI内容生成控制器
  4. */
  5. var __importDefault = (this && this.__importDefault) || function (mod) {
  6. return (mod && mod.__esModule) ? mod : { "default": mod };
  7. };
  8. Object.defineProperty(exports, "__esModule", { value: true });
  9. const router_1 = __importDefault(require("@koa/router"));
  10. const ai_content_service_1 = require("./ai-content.service");
  11. const learning_path_service_1 = require("./learning-path.service");
  12. const router = new router_1.default();
  13. // ============ 学习路径 API ============
  14. // 创建学习路径任务
  15. router.post('/learning-path/create', async (ctx) => {
  16. const { topic, mode } = ctx.request.body;
  17. if (!topic || topic.trim().length === 0) {
  18. ctx.status = 400;
  19. ctx.body = { code: 400, message: '请输入学习主题' };
  20. return;
  21. }
  22. // 验证模式
  23. const generationMode = mode === 'multi-agent' ? 'multi-agent' : 'progressive';
  24. // 获取用户ID(如果有)
  25. const token = ctx.request.headers.authorization?.replace('Bearer ', '');
  26. let userId = null;
  27. if (token) {
  28. try {
  29. const jwt = require('jsonwebtoken');
  30. const decoded = jwt.verify(token, 'my-jwt-secret-key-2024');
  31. userId = decoded.userId || decoded.id || null;
  32. }
  33. catch (e) { }
  34. }
  35. const task = await (0, learning_path_service_1.createLearningPath)(userId, topic, generationMode);
  36. ctx.body = { code: 0, message: 'success', data: task };
  37. });
  38. // 获取用户的学习任务列表(要放在 /:id 前面,否则 /list 会被匹配为 id=list)
  39. router.get('/learning-path/list', async (ctx) => {
  40. const token = ctx.request.headers.authorization?.replace('Bearer ', '');
  41. let userId = null;
  42. if (token) {
  43. try {
  44. const jwt = require('jsonwebtoken');
  45. const decoded = jwt.verify(token, 'my-jwt-secret-key-2024');
  46. userId = decoded.userId || decoded.id || null;
  47. }
  48. catch (e) { }
  49. }
  50. const tasks = await (0, learning_path_service_1.getUserTasks)(userId);
  51. ctx.body = { code: 0, message: 'success', data: tasks };
  52. });
  53. // 获取学习路径详情(要放在 /list 后面)
  54. router.get('/learning-path/:id', async (ctx) => {
  55. const id = parseInt(ctx.params.id);
  56. if (isNaN(id)) {
  57. ctx.status = 400;
  58. ctx.body = { code: 400, message: '无效的任务ID' };
  59. return;
  60. }
  61. const task = await (0, learning_path_service_1.getLearningPathDetail)(id);
  62. if (!task) {
  63. ctx.status = 404;
  64. ctx.body = { code: 404, message: '任务不存在' };
  65. return;
  66. }
  67. ctx.body = { code: 0, message: 'success', data: task };
  68. });
  69. // 获取渐进模式待确认状态
  70. router.get('/learning-path/:id/pending', async (ctx) => {
  71. const id = parseInt(ctx.params.id);
  72. if (isNaN(id)) {
  73. ctx.status = 400;
  74. ctx.body = { code: 400, message: '无效的任务ID' };
  75. return;
  76. }
  77. const pending = await (0, learning_path_service_1.getPendingConfirmation)(id);
  78. if (!pending) {
  79. ctx.status = 404;
  80. ctx.body = { code: 404, message: '任务不存在' };
  81. return;
  82. }
  83. ctx.body = { code: 0, message: 'success', data: pending };
  84. });
  85. // 确认并继续生成(渐进模式)
  86. router.post('/learning-path/:id/confirm', async (ctx) => {
  87. const id = parseInt(ctx.params.id);
  88. if (isNaN(id)) {
  89. ctx.status = 400;
  90. ctx.body = { code: 400, message: '无效的任务ID' };
  91. return;
  92. }
  93. const { step, confirmedIds, modifiedItems } = ctx.request.body;
  94. if (!step || !confirmedIds) {
  95. ctx.status = 400;
  96. ctx.body = { code: 400, message: '缺少必要参数' };
  97. return;
  98. }
  99. try {
  100. const result = await (0, learning_path_service_1.confirmAndContinue)(id, step, confirmedIds, modifiedItems);
  101. ctx.body = { code: 0, message: 'success', data: result };
  102. }
  103. catch (e) {
  104. ctx.status = 500;
  105. ctx.body = { code: 500, message: e.message };
  106. }
  107. });
  108. // 重新生成节点(渐进模式)
  109. router.post('/learning-path/:id/regenerate', async (ctx) => {
  110. const id = parseInt(ctx.params.id);
  111. if (isNaN(id)) {
  112. ctx.status = 400;
  113. ctx.body = { code: 400, message: '无效的任务ID' };
  114. return;
  115. }
  116. const { type, nodeId, instruction } = ctx.request.body;
  117. if (!type || !nodeId) {
  118. ctx.status = 400;
  119. ctx.body = { code: 400, message: '缺少必要参数' };
  120. return;
  121. }
  122. try {
  123. const result = await (0, learning_path_service_1.regenerateNode)(id, type, nodeId, instruction);
  124. ctx.body = { code: 0, message: 'success', data: result };
  125. }
  126. catch (e) {
  127. ctx.status = 500;
  128. ctx.body = { code: 500, message: e.message };
  129. }
  130. });
  131. // 获取多Agent模式状态
  132. router.get('/learning-path/:id/status', async (ctx) => {
  133. const id = parseInt(ctx.params.id);
  134. if (isNaN(id)) {
  135. ctx.status = 400;
  136. ctx.body = { code: 400, message: '无效的任务ID' };
  137. return;
  138. }
  139. const status = await (0, learning_path_service_1.getAgentStatus)(id);
  140. if (!status) {
  141. ctx.status = 404;
  142. ctx.body = { code: 404, message: '任务不存在' };
  143. return;
  144. }
  145. ctx.body = { code: 0, message: 'success', data: status };
  146. });
  147. // ============ 原有的 API ============
  148. // 智能意图识别
  149. router.get('/intent/recognize', async (ctx) => {
  150. const { input } = ctx.query;
  151. const result = await ai_content_service_1.aiContentService.recognizeIntent(input);
  152. ctx.body = { code: 0, message: 'success', data: result };
  153. });
  154. // 获取内容类型列表
  155. router.get('/content-types', async (ctx) => {
  156. const result = ai_content_service_1.aiContentService.getContentTypes();
  157. ctx.body = { code: 0, message: 'success', data: result };
  158. });
  159. // 获取所有内容类型(扁平)
  160. router.get('/content-types/all', async (ctx) => {
  161. const result = ai_content_service_1.aiContentService.getAllContentTypes();
  162. ctx.body = { code: 0, message: 'success', data: result };
  163. });
  164. // ============ 异步生成任务 API ============
  165. // 创建异步生成任务
  166. router.post('/generate-async', async (ctx) => {
  167. const { prompt, targetLength } = ctx.request.body;
  168. if (!prompt || prompt.trim().length === 0) {
  169. ctx.status = 400;
  170. ctx.body = { code: 400, message: '请输入内容描述' };
  171. return;
  172. }
  173. const taskId = `gen-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  174. const length = targetLength || 2000;
  175. // 创建任务记录
  176. ai_content_service_1.generateTasks.set(taskId, {
  177. id: taskId,
  178. status: 'generating',
  179. progress: 0,
  180. message: '正在创建生成任务...',
  181. createdAt: new Date(),
  182. });
  183. // 异步执行生成,不阻塞响应
  184. ai_content_service_1.aiContentService.generateContentAsync(taskId, prompt, length).catch(error => {
  185. console.error('❌ 异步内容生成失败:', error);
  186. const task = ai_content_service_1.generateTasks.get(taskId);
  187. if (task) {
  188. task.status = 'failed';
  189. task.error = error.message;
  190. task.message = '生成失败: ' + error.message;
  191. }
  192. });
  193. ctx.body = {
  194. code: 0,
  195. message: '任务已创建',
  196. data: { taskId, status: 'generating' }
  197. };
  198. });
  199. // 获取任务状态
  200. router.get('/task/:taskId', async (ctx) => {
  201. const { taskId } = ctx.params;
  202. const task = ai_content_service_1.generateTasks.get(taskId);
  203. if (!task) {
  204. ctx.status = 404;
  205. ctx.body = { code: 404, message: '任务不存在' };
  206. return;
  207. }
  208. ctx.body = {
  209. code: 0,
  210. message: 'success',
  211. data: {
  212. taskId: task.id,
  213. status: task.status,
  214. progress: task.progress,
  215. message: task.message,
  216. result: task.result,
  217. error: task.error,
  218. }
  219. };
  220. });
  221. // 统一内容生成接口(同步版本,保留兼容)
  222. router.post('/generate', async (ctx) => {
  223. const { prompt, targetLength } = ctx.request.body;
  224. const result = await ai_content_service_1.aiContentService.generateContent(prompt, targetLength || 2000);
  225. ctx.body = { code: 0, message: 'success', data: result };
  226. });
  227. // 获取行业列表
  228. router.get('/industries', async (ctx) => {
  229. const result = ai_content_service_1.aiContentService.getIndustries();
  230. ctx.body = { code: 0, message: 'success', data: result };
  231. });
  232. // 行业适配
  233. router.post('/adapt', async (ctx) => {
  234. const { content, industry } = ctx.request.body;
  235. const result = await ai_content_service_1.aiContentService.adaptContent(content, industry);
  236. ctx.body = { code: 0, message: 'success', data: result };
  237. });
  238. // 内容规划
  239. router.post('/plan', async (ctx) => {
  240. const { type, theme, targetLength } = ctx.request.body;
  241. const result = await ai_content_service_1.aiContentService.planContent(type, theme, targetLength);
  242. ctx.body = { code: 0, message: 'success', data: result };
  243. });
  244. // 生成大纲
  245. router.post('/outline/generate', async (ctx) => {
  246. const { type, theme, chapters } = ctx.request.body;
  247. const result = await ai_content_service_1.aiContentService.generateOutline(type, theme, chapters);
  248. ctx.body = { code: 0, message: 'success', data: result };
  249. });
  250. // 生成角色设定
  251. router.post('/characters/generate', async (ctx) => {
  252. const { type, genre } = ctx.request.body;
  253. const result = await ai_content_service_1.aiContentService.generateCharacters(type, genre);
  254. ctx.body = { code: 0, message: 'success', data: result };
  255. });
  256. // 分步生成内容
  257. router.post('/chunk/generate', async (ctx) => {
  258. const { outlineId, chapterIndex, chapterTitle, previousContent } = ctx.request.body;
  259. const result = await ai_content_service_1.aiContentService.generateChunk(outlineId, chapterIndex, chapterTitle, previousContent);
  260. ctx.body = { code: 0, message: 'success', data: result };
  261. });
  262. // 流式生成章节内容(SSE)
  263. router.post('/chunk/stream', async (ctx) => {
  264. const { outlineId, chapterIndex, chapterTitle, previousContent } = ctx.request.body;
  265. ctx.set('Content-Type', 'text/event-stream');
  266. ctx.set('Cache-Control', 'no-cache');
  267. ctx.set('Connection', 'keep-alive');
  268. ctx.set('X-Accel-Buffering', 'no');
  269. try {
  270. for await (const chunk of ai_content_service_1.aiContentService.streamGenerateChunk(outlineId, chapterIndex, chapterTitle, previousContent)) {
  271. ctx.write(`data: ${JSON.stringify(chunk)}\n\n`);
  272. }
  273. }
  274. catch (error) {
  275. ctx.write(`data: ${JSON.stringify({ type: 'error', message: error.message })}\n\n`);
  276. }
  277. ctx.end();
  278. });
  279. // 流式生成(模拟SSE)
  280. router.get('/stream/generate', async (ctx) => {
  281. const { outlineId } = ctx.query;
  282. ctx.set('Content-Type', 'text/event-stream');
  283. ctx.set('Cache-Control', 'no-cache');
  284. ctx.set('Connection', 'keep-alive');
  285. for await (const chunk of ai_content_service_1.aiContentService.streamGenerate(outlineId)) {
  286. ctx.write(`data: ${JSON.stringify(chunk)}\n\n`);
  287. if (chunk.type === 'done')
  288. break;
  289. }
  290. ctx.end();
  291. });
  292. // 创建生成任务
  293. router.post('/task/create', async (ctx) => {
  294. const { type, title } = ctx.request.body;
  295. const result = ai_content_service_1.aiContentService.createTask(type, title);
  296. ctx.body = { code: 0, message: 'success', data: result };
  297. });
  298. // 获取任务列表
  299. router.get('/tasks', async (ctx) => {
  300. const result = ai_content_service_1.aiContentService.getTasks();
  301. ctx.body = { code: 0, message: 'success', data: result };
  302. });
  303. // 章节连贯性检查
  304. router.post('/coherence/check', async (ctx) => {
  305. const { chapter1, chapter2 } = ctx.request.body;
  306. const result = await ai_content_service_1.aiContentService.checkCoherence(chapter1, chapter2);
  307. ctx.body = { code: 0, message: 'success', data: result };
  308. });
  309. // 生成衔接段
  310. router.post('/continuity/generate', async (ctx) => {
  311. const { previousChapter, nextTopic } = ctx.request.body;
  312. const result = await ai_content_service_1.aiContentService.generateContinuity(previousChapter, nextTopic);
  313. ctx.body = { code: 0, message: 'success', data: result };
  314. });
  315. // 敏感词检测
  316. router.post('/sensitive/check', async (ctx) => {
  317. const { text } = ctx.request.body;
  318. const result = await ai_content_service_1.aiContentService.checkSensitive(text);
  319. ctx.body = { code: 0, message: 'success', data: result };
  320. });
  321. // 质量评分
  322. router.post('/quality/score', async (ctx) => {
  323. const { text } = ctx.request.body;
  324. const result = await ai_content_service_1.aiContentService.scoreQuality(text);
  325. ctx.body = { code: 0, message: 'success', data: result };
  326. });
  327. // 内容优化
  328. router.post('/optimize', async (ctx) => {
  329. const { text, target } = ctx.request.body;
  330. const result = await ai_content_service_1.aiContentService.optimizeContent(text, target);
  331. ctx.body = { code: 0, message: 'success', data: result };
  332. });
  333. // 获取支持的语言
  334. router.get('/languages', async (ctx) => {
  335. const result = ai_content_service_1.aiContentService.getLanguages();
  336. ctx.body = { code: 0, message: 'success', data: result };
  337. });
  338. // 翻译并生成
  339. router.post('/translate/generate', async (ctx) => {
  340. const { text, targetLang, voiceStyle } = ctx.request.body;
  341. const result = await ai_content_service_1.aiContentService.translateAndGenerate(text, targetLang, voiceStyle);
  342. ctx.body = { code: 0, message: 'success', data: result };
  343. });
  344. // 智能匹配BGM
  345. router.post('/bgm/match', async (ctx) => {
  346. const { contentType, mood, genre } = ctx.request.body;
  347. const result = await ai_content_service_1.aiContentService.matchBGM(contentType, mood, genre);
  348. ctx.body = { code: 0, message: 'success', data: result };
  349. });
  350. // 获取音效列表
  351. router.get('/sounds', async (ctx) => {
  352. const result = ai_content_service_1.aiContentService.getSounds();
  353. ctx.body = { code: 0, message: 'success', data: result };
  354. });
  355. // 情感调节
  356. router.post('/emotion/adjust', async (ctx) => {
  357. const { text, targetEmotion } = ctx.request.body;
  358. const result = await ai_content_service_1.aiContentService.adjustEmotion(text, targetEmotion);
  359. ctx.body = { code: 0, message: 'success', data: result };
  360. });
  361. // 获取情感选项
  362. router.get('/emotions', async (ctx) => {
  363. const result = ai_content_service_1.aiContentService.getEmotions();
  364. ctx.body = { code: 0, message: 'success', data: result };
  365. });
  366. // 多角色对话生成
  367. router.post('/dialogue/generate', async (ctx) => {
  368. const { characters, scenario } = ctx.request.body;
  369. const result = await ai_content_service_1.aiContentService.generateDialogue(characters, scenario);
  370. ctx.body = { code: 0, message: 'success', data: result };
  371. });
  372. // SEO优化
  373. router.post('/seo/optimize', async (ctx) => {
  374. const { title, content, platform } = ctx.request.body;
  375. const result = await ai_content_service_1.aiContentService.optimizeSEO(title, content, platform);
  376. ctx.body = { code: 0, message: 'success', data: result };
  377. });
  378. // 合规检查
  379. router.post('/compliance/check', async (ctx) => {
  380. const { text, industry } = ctx.request.body;
  381. const result = await ai_content_service_1.aiContentService.checkCompliance(text, industry);
  382. ctx.body = { code: 0, message: 'success', data: result };
  383. });
  384. // 内容分析报告
  385. router.get('/analytics/:contentId', async (ctx) => {
  386. const { contentId } = ctx.params;
  387. const result = await ai_content_service_1.aiContentService.generateAnalytics(contentId);
  388. ctx.body = { code: 0, message: 'success', data: result };
  389. });
  390. // 智能续写
  391. router.post('/continue', async (ctx) => {
  392. const { text, direction } = ctx.request.body;
  393. const result = await ai_content_service_1.aiContentService.continueContent(text, direction);
  394. ctx.body = { code: 0, message: 'success', data: result };
  395. });
  396. exports.default = router;