|
|
@@ -1,89 +1,50 @@
|
|
|
import { WritableStreamBuffer } from 'stream-buffers'
|
|
|
import { createLLM } from './llm'
|
|
|
-import { createFlow } from './flow'
|
|
|
-import { createER } from './er'
|
|
|
-import { createTable } from './table'
|
|
|
import { uploadDoc } from './upload'
|
|
|
-import { createArch } from './arch'
|
|
|
-import { createAbstract } from './abstract'
|
|
|
-import { createUseCase } from './useCase'
|
|
|
import { genChapters } from './chapter'
|
|
|
import { Logger } from '@nestjs/common'
|
|
|
import { HumanMessage, SystemMessage } from 'langchain/schema'
|
|
|
+import * as NumberToChinese from '@siakhooi/number-to-chinese-words'
|
|
|
+import { createAbstract } from './abstract'
|
|
|
|
|
|
-export async function genGeneralPaper(major: string, title: string, desc: string) {
|
|
|
- const tools = createLLM()
|
|
|
- const { llm, usage, conversation } = tools
|
|
|
- const pRetry = (await eval("import('p-retry')")).default
|
|
|
-
|
|
|
- const chapters = await genChapters(tools, major, title, desc)
|
|
|
- Logger.log(JSON.stringify(chapters, null, 4))
|
|
|
-
|
|
|
- let paper = new WritableStreamBuffer()
|
|
|
- const startTime = Date.now()
|
|
|
-
|
|
|
- paper.write(`${await createAbstract(tools, title, desc)}\n\n`)
|
|
|
-
|
|
|
- const { chain, memory } = conversation(`你是一个擅长写${major}专业毕业论文的专家,你的任务是帮我完成我的论文。
|
|
|
-你要根据我的要求,帮我完成我的论文
|
|
|
-我的论文标题是: ${title}
|
|
|
-主要论述: ${desc}
|
|
|
-现在我们已经为论文拟好了一个大纲:
|
|
|
-${chapters.map((i) => `- ${i.chapterName}\n ${i.chapterDesc}`).join('\n')}
|
|
|
-
|
|
|
-现在我们来一步一步的编写这篇论文
|
|
|
-请严格按照markdown格式返回内容。
|
|
|
-请注意,你只需要输出能够直接出现在论文中的内容,不需要输出你对该内容的总结或者介绍等其他文字`)
|
|
|
-
|
|
|
- for (let i = 0; i < chapters.length; i++) {
|
|
|
- let response
|
|
|
- if (chapters[i].sections && chapters[i].sections.length) {
|
|
|
- for (let j = 0; j < chapters[i].sections.length; j++) {
|
|
|
- let input = ''
|
|
|
- if (j == 0) {
|
|
|
- input = `现在我们来编写第${i + 1}章: ${chapters[i].chapterName}, 本章主要内容是${
|
|
|
- chapters[i].chapterDesc
|
|
|
- }
|
|
|
-我们分为多个小节编写:
|
|
|
-${chapters[i].sections.map((e) => `- ${e.sectionName}\n ${e.sectionDesc}`).join('\n')}
|
|
|
-
|
|
|
-对于每个小节,你需要用三段格式对该小节展开详细论述`
|
|
|
- }
|
|
|
- input += `\n现在我们开始编写第${j + 1}小节${chapters[i].sections[j].sectionName}的内容:`
|
|
|
-
|
|
|
- const { response } = await chain.call({ input })
|
|
|
- paper.write('\n\n' + response)
|
|
|
- }
|
|
|
+function chapters2md(chapters, sub = []) {
|
|
|
+ let md = ''
|
|
|
+ const list: any[] = []
|
|
|
+ function _update(_data: any, level: number) {
|
|
|
+ _data.forEach((e: any) => {
|
|
|
+ list.push({
|
|
|
+ title: e.title,
|
|
|
+ level
|
|
|
+ })
|
|
|
+ if (e.children) _update(e.children, level + 1)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ _update(chapters, 0)
|
|
|
+ const levels = [0, 0, 0, 0]
|
|
|
+ for (const child of list) {
|
|
|
+ const level = child.level
|
|
|
+ levels[level] = levels[level] + 1
|
|
|
+ for (let i = level + 1; i < levels.length; i++) {
|
|
|
+ levels[i] = 0
|
|
|
+ }
|
|
|
+ let title
|
|
|
+ if (level === 0 && !sub.length) {
|
|
|
+ title = ''
|
|
|
} else {
|
|
|
- const { response } = (
|
|
|
- await chain.call({
|
|
|
- input: `现在我们来编写第${i + 1}章: ${chapters[i].chapterName}, 本章主要内容是${
|
|
|
- chapters[i].chapterDesc
|
|
|
- }
|
|
|
-开始:`
|
|
|
- })
|
|
|
- ).response
|
|
|
- paper.write('\n\n' + response)
|
|
|
+ title = levels.slice(0, level + 1).join('.') + ' '
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- const content = paper.getContentsAsString('utf8')
|
|
|
- const duration = (Date.now() - startTime) / 1000
|
|
|
- const fileUrl = await uploadDoc(title, content)
|
|
|
- return {
|
|
|
- content,
|
|
|
- duration,
|
|
|
- tokenUsage: usage,
|
|
|
- fileUrl
|
|
|
+ md += `${' '.repeat(level)}- ${title}${child.title}\n`
|
|
|
}
|
|
|
+ return md
|
|
|
}
|
|
|
|
|
|
-export async function genGeneralPaper1(major: string, title: string, desc: string) {
|
|
|
+export async function genGeneralPaper1(major: string, title: string, desc: string, chapters) {
|
|
|
const tools = createLLM('gpt-3.5-turbo')
|
|
|
const { llm, usage, conversation } = tools
|
|
|
const pRetry = (await eval("import('p-retry')")).default
|
|
|
|
|
|
- const chapters = await genChapters(tools, major, title, desc)
|
|
|
+ chapters = chapters || (await genChapters(tools, major, title, desc))
|
|
|
Logger.log(JSON.stringify(chapters, null, 4))
|
|
|
|
|
|
let paper = new WritableStreamBuffer()
|
|
|
@@ -92,30 +53,52 @@ export async function genGeneralPaper1(major: string, title: string, desc: strin
|
|
|
paper.write(`${await createAbstract(tools, title, desc)}\n\n`)
|
|
|
|
|
|
for (let i = 0; i < chapters.length; i++) {
|
|
|
+ const chapter = chapters[i]
|
|
|
const sysPrompt = `你是一个擅长写${major}专业毕业论文的专家。
|
|
|
你的任务是写一篇标题为"${title}"的论文。
|
|
|
-以下是论文的大纲:
|
|
|
-${chapters.map((i, index) => `${index + 1}. ${i.chapterName}\n ${i.chapterDesc}`).join('\n')}
|
|
|
+全文按照以下章节组织:
|
|
|
+${chapters2md(chapters)}
|
|
|
|
|
|
-你要根据大纲分章节帮我生成文章。
|
|
|
你的语气应正式,内容应适合和吸引一般读者。
|
|
|
你要严格按照markdown格式返回内容。
|
|
|
-你只需要输出能够直接出现在论文中的内容,不需要输出你对该内容的总结或者介绍等其他文字,不需要出现介绍下一章或其他承上启下的文字。`
|
|
|
- let prompt = `第${i + 1}章是:${chapters[i].chapterName},本章主要内容是${chapters[i].chapterDesc}`
|
|
|
- if (chapters[i].sections && chapters[i].sections.length) {
|
|
|
- prompt += `\n本章分为多个小节,每小节的主要论述内容应采用五段式结构进行论述,论述内容应尽量详细且逻辑清晰。
|
|
|
-以下是各小节的简介:
|
|
|
-${chapters[i].sections.map((e) => `- ${e.sectionName}\n ${e.sectionDesc}`).join('\n')}
|
|
|
-
|
|
|
-请按照此结构一次性完成本章内容`
|
|
|
- }
|
|
|
- prompt += `\n
|
|
|
-第${i + 1}章:# ${chapters[i].chapterName}:`
|
|
|
- const { content } = await llm.call([new SystemMessage(sysPrompt), new HumanMessage(prompt)])
|
|
|
- if (!content.trim().split('\n')[0].includes(chapters[i].chapterName)) {
|
|
|
- paper.write(`\n\n# ${chapters[i].chapterName}`)
|
|
|
+不要擅作主张输出你对该内容的总结或者介绍等其他文字,不需要出现介绍下一章或其他承上启下的文字。
|
|
|
+你要严格遵守我的指令,按照我的指定的章节和小节完成论文的写作。
|
|
|
+请直接开始写作,不要对内容作任何解释。`
|
|
|
+ paper.write('\n\n# ' + chapter.title)
|
|
|
+ if (chapter.children && chapter.children.length) {
|
|
|
+ // for (let j = 0; j < chapter.children.length; j++) {
|
|
|
+ // const section = chapter.children[j]
|
|
|
+ // paper.write(`\n\n## ${i + 1}.${j + 1} ${section.title}`)
|
|
|
+ // let prompt = `第${i + 1}章: # ${chapter.title}`
|
|
|
+ // prompt += `\n## ${i + 1}.${j + 1} ${section.title} (请注意只需要编写这一小节的内容):`
|
|
|
+ // const { content } = await llm.call([new SystemMessage(sysPrompt), new HumanMessage(prompt)])
|
|
|
+ // paper.write('\n\n' + content)
|
|
|
+ // }
|
|
|
+
|
|
|
+ paper.write(
|
|
|
+ '\n\n' +
|
|
|
+ (
|
|
|
+ await Promise.all(
|
|
|
+ chapter.children.map(async (section, j) => {
|
|
|
+ let prompt = `第${i + 1}章: # ${chapter.title}`
|
|
|
+ prompt += `\n## ${i + 1}.${j + 1} ${section.title} (请注意只需要编写这一小节的内容):`
|
|
|
+ const { content } = await llm.call([
|
|
|
+ new SystemMessage(sysPrompt),
|
|
|
+ new HumanMessage(prompt)
|
|
|
+ ])
|
|
|
+ return `## ${i + 1}.${j + 1} ${section.title}\n\n` + content
|
|
|
+ })
|
|
|
+ )
|
|
|
+ ).join('\n\n')
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ let prompt = `第${i + 1}章: # ${chapter.title}`
|
|
|
+ const { content } = await llm.call([new SystemMessage(sysPrompt), new HumanMessage(prompt)])
|
|
|
+ // if (!content.trim().split('\n')[0].includes(chapter.title)) {
|
|
|
+ // paper.write(`\n\n# ${chapter.title}`)
|
|
|
+ // }
|
|
|
+ paper.write('\n\n' + content)
|
|
|
}
|
|
|
- paper.write('\n\n' + content)
|
|
|
}
|
|
|
|
|
|
let content = paper.getContentsAsString('utf8').split('\n')
|