ai-query对接新版freesun-agent接口的分支
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

530 lines
15 KiB

'use strict';
const superagent = require('superagent');
module.exports.getBooks = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const books = await models.Book.findAll({
order: [['createdAt', 'DESC']]
});
ctx.status = 200;
ctx.body = books;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '获取书籍列表失败'
};
}
};
module.exports.createBook = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { name, requirements } = ctx.request.body;
if (!name) {
throw '书籍名称不能为空';
}
const book = await models.Book.create({
name,
requirements
});
ctx.status = 200;
ctx.body = book;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '创建书籍失败'
};
}
};
module.exports.updateBook = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { id } = ctx.params;
const { name, requirements } = ctx.request.body;
const book = await models.Book.findByPk(id);
if (!book) {
throw '书籍不存在';
}
await book.update({
name,
requirements
});
ctx.status = 200;
ctx.body = book;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '更新书籍失败'
};
}
};
module.exports.deleteBook = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { id } = ctx.params;
const book = await models.Book.findByPk(id);
if (!book) {
throw '书籍不存在';
}
await book.destroy();
ctx.status = 204;
ctx.body = {};
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '删除书籍失败'
};
}
};
module.exports.getBookChapters = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId } = ctx.params;
const chapters = await models.BookChapter.findAll({
where: { bookId },
order: [['level', 'ASC'], ['sortOrder', 'ASC'], ['createdAt', 'ASC']],
include: [{
model: models.BookChapterContent,
as: 'bookChapterContents',
separate: true,
order: [['version', 'DESC']],
limit: 1
}]
});
// 构建树状结构
const buildTree = (chapters, parentId = null) => {
return chapters
.filter(chapter => chapter.parentId === parentId)
.map(chapter => ({
...chapter.toJSON(),
children: buildTree(chapters, chapter.id),
latestContent: chapter.bookChapterContents?.[0] || null
}));
};
const treeData = buildTree(chapters);
ctx.status = 200;
ctx.body = treeData;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '获取章节列表失败'
};
}
};
module.exports.createChapter = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId } = ctx.params;
const { parentId, level, title, requirements, sortOrder = 0 } = ctx.request.body;
if (!title) {
throw '章节标题不能为空';
}
const chapter = await models.BookChapter.create({
bookId,
parentId,
level,
title,
requirements,
sortOrder
});
ctx.status = 200;
ctx.body = chapter;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '创建章节失败'
};
}
};
module.exports.updateChapter = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, id } = ctx.params;
const { title, requirements, sortOrder, parentId, level } = ctx.request.body;
const chapter = await models.BookChapter.findByPk(id);
if (!chapter) {
throw '章节不存在';
}
const updateData = {};
if (title !== undefined) updateData.title = title;
if (requirements !== undefined) updateData.requirements = requirements;
if (sortOrder !== undefined) updateData.sortOrder = sortOrder;
if (parentId !== undefined) updateData.parentId = parentId;
if (level !== undefined) updateData.level = level;
await chapter.update(updateData);
ctx.status = 200;
ctx.body = chapter;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '更新章节失败'
};
}
};
module.exports.deleteChapter = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, id } = ctx.params;
const chapter = await models.BookChapter.findByPk(id);
if (!chapter) {
throw '章节不存在';
}
await chapter.destroy();
ctx.status = 204;
ctx.body = {};
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '删除章节失败'
};
}
};
module.exports.generateChapterContent = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, id } = ctx.params;
const chapter = await models.BookChapter.findByPk(id, {
include: [{ model: models.Book, as: 'book' }]
});
if (!chapter) {
throw '章节不存在';
}
// 更新状态为生成中
await chapter.update({ generationStatus: 'generating' });
// 立即返回响应,避免前端超时
ctx.status = 200;
ctx.body = {
message: '已开始生成,请稍后查看',
status: 'generating'
};
// 异步执行生成逻辑
(async () => {
try {
// 获取书籍整体要求
const book = chapter.book;
// 获取父章节信息 (如果存在)
let topChapterName = chapter.title;
let topChapterRequirements = chapter.requirements || '';
if (chapter.parentId) {
const parentChapter = await models.BookChapter.findByPk(chapter.parentId);
if (parentChapter) {
topChapterName = parentChapter.title;
topChapterRequirements = parentChapter.requirements || '';
}
}
// 真实调用逻辑
const requestBody = {
stream: false,
detail: false,
variables: {
outline: book.requirements || '',
topChapterName: topChapterName,
topChapterRequirements: topChapterRequirements,
chapterRequirements: chapter.requirements || ''
},
messages: [{
role: 'user',
content: [{
type: 'text',
text: chapter.title
}]
}]
};
const response = await superagent
.post(`${ctx.app.fs.config.fastGpt.apiUrl}/api/v1/chat/completions`)
.send(requestBody)
.set({
'Authorization': `Bearer ${ctx.app.fs.config.fastGpt.bookWriterAppKey}`,
'Content-Type': 'application/json'
});
const data = JSON.parse(response.text);
const content = data?.choices?.[0]?.message?.content || '';
// 模拟生成延迟 (10秒)
// await new Promise(resolve => setTimeout(resolve, 10000));
// const content = `## ${chapter.title}\n\nThis is a simulated generated content for **${chapter.title}**.\n\nTime: ${new Date().toLocaleString()}\n\nRequirements: ${chapter.requirements || 'None'}`;
// 创建新内容版本
const latestContent = await models.BookChapterContent.findOne({
where: { chapterId: chapter.id },
order: [['version', 'DESC']]
});
const newVersion = latestContent ? latestContent.version + 1 : 1;
await models.BookChapterContent.create({
chapterId: chapter.id,
content: content,
version: newVersion
});
// 更新状态为成功
await chapter.update({ generationStatus: 'success' });
} catch (error) {
console.error('Generation failed:', error);
// 更新状态为失败
try {
await chapter.update({ generationStatus: 'failed' });
} catch (e) {
console.error('Update status failed:', e);
}
}
})();
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '生成章节内容失败'
};
}
};
module.exports.getChapterContent = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, chapterId } = ctx.params;
const contents = await models.BookChapterContent.findAll({
where: { chapterId },
order: [['version', 'DESC']]
});
ctx.status = 200;
ctx.body = contents;
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '获取章节内容失败'
};
}
};
module.exports.polishContent = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, chapterId } = ctx.params;
const { requirements } = ctx.request.body;
const chapter = await models.BookChapter.findByPk(chapterId, {
include: [{
model: models.BookChapterContent,
order: [['version', 'DESC']],
limit: 1
}]
});
const latestContent = chapter.bookChapterContents?.[0];
if (!chapter) {
throw '章节不存在';
}
if (!latestContent) {
throw '章节内容不存在';
}
// 更新状态为正在润色
await chapter.update({ generationStatus: 'polishing' });
// 立即返回响应,避免前端超时
ctx.status = 200;
ctx.body = {
message: '内容正在润色中',
};
// 异步执行润色
(async () => {
try {
// 真实调用逻辑
const requestBody = {
stream: false,
detail: false,
variables: {
requirements: requirements || '',
},
messages: [{
role: 'user',
content: [{
type: 'text',
text: latestContent.content || ''
}]
}]
};
const response = await superagent
.post(`${ctx.app.fs.config.fastGpt.apiUrl}/api/v1/chat/completions`)
.send(requestBody)
.set({
'Authorization': `Bearer ${ctx.app.fs.config.fastGpt.polishAppKey}`,
'Content-Type': 'application/json'
});
const data = JSON.parse(response.text);
const polishedContent = data?.choices?.[0]?.message?.content || '';
// 模拟润色延迟
// await new Promise(resolve => setTimeout(resolve, 5000));
// const polishedContent = latestContent.content;
// 创建新章节内容
await models.BookChapterContent.create({
chapterId: chapter.id,
content: polishedContent,
version: latestContent.version + 1
});
// 更新状态为成功
await chapter.update({ generationStatus: 'success' });
} catch (error) {
console.error('Polish failed:', error);
// 更新状态为失败
try {
await chapter.update({ generationStatus: 'polishFailed' });
} catch (e) {
console.error('Update status polishFailed:', e);
}
}
})();
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '润色失败'
};
}
};
module.exports.restoreChapterVersion = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, chapterId, contentId } = ctx.params;
const targetContent = await models.BookChapterContent.findByPk(contentId);
if (!targetContent) {
throw '指定版本不存在';
}
if (parseInt(targetContent.chapterId) !== parseInt(chapterId)) {
throw '版本与章节不匹配';
}
const latestContent = await models.BookChapterContent.findOne({
where: { chapterId },
order: [['version', 'DESC']]
});
const newVersion = latestContent ? latestContent.version + 1 : 1;
await models.BookChapterContent.create({
chapterId,
content: targetContent.content,
version: newVersion
});
// 同时也应该把章节状态重置为success,防止处在failed状态
await models.BookChapter.update(
{ generationStatus: 'success' },
{ where: { id: chapterId } }
);
ctx.status = 200;
ctx.body = { message: '版本回退成功' };
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '版本回退失败'
};
}
};
module.exports.saveChapterContent = async (ctx, next) => {
try {
const { models } = ctx.fs.dc;
const { bookId, chapterId } = ctx.params;
const { content } = ctx.request.body;
const chapter = await models.BookChapter.findByPk(chapterId);
if (!chapter) {
throw '章节不存在';
}
const latestContent = await models.BookChapterContent.findOne({
where: { chapterId },
order: [['version', 'DESC']]
});
const newVersion = latestContent ? latestContent.version + 1 : 1;
await models.BookChapterContent.create({
chapterId,
content,
version: newVersion
});
await chapter.update({ generationStatus: 'success' });
ctx.status = 200;
ctx.body = { message: '保存成功', version: newVersion };
} catch (error) {
ctx.logger.log(error);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : '保存章节内容失败'
};
}
};