|
@@ -1,7 +1,7 @@
|
|
|
-import { Injectable, InternalServerErrorException, Logger, OnModuleInit } from '@nestjs/common'
|
|
|
|
|
|
|
+import { HttpException, Injectable, InternalServerErrorException, Logger, OnModuleInit } from '@nestjs/common'
|
|
|
import { InjectRepository } from '@nestjs/typeorm'
|
|
import { InjectRepository } from '@nestjs/typeorm'
|
|
|
import { PaperOrder, PaperOrderStatus } from './entities/paper-order.entity'
|
|
import { PaperOrder, PaperOrderStatus } from './entities/paper-order.entity'
|
|
|
-import { Repository, Like } from 'typeorm'
|
|
|
|
|
|
|
+import { Repository, Like, Between } from 'typeorm'
|
|
|
import { PaperGenResult } from './entities/paper-gen-result.entity'
|
|
import { PaperGenResult } from './entities/paper-gen-result.entity'
|
|
|
import { Pagination, paginate } from 'nestjs-typeorm-paginate'
|
|
import { Pagination, paginate } from 'nestjs-typeorm-paginate'
|
|
|
import { PageRequest } from 'src/common/dto/page-request'
|
|
import { PageRequest } from 'src/common/dto/page-request'
|
|
@@ -14,6 +14,10 @@ import { HumanMessage } from 'langchain/schema'
|
|
|
import axios from 'axios'
|
|
import axios from 'axios'
|
|
|
import * as qs from 'qs'
|
|
import * as qs from 'qs'
|
|
|
import { load } from 'cheerio'
|
|
import { load } from 'cheerio'
|
|
|
|
|
+import { parse } from 'date-fns'
|
|
|
|
|
+import { RefSearchRecord } from './entities/ref-search-record.entity'
|
|
|
|
|
+import { MembershipService } from 'src/membership/membership.service'
|
|
|
|
|
+import { startOfDay, endOfDay } from 'date-fns'
|
|
|
|
|
|
|
|
@Injectable()
|
|
@Injectable()
|
|
|
export class PaperService implements OnModuleInit {
|
|
export class PaperService implements OnModuleInit {
|
|
@@ -21,7 +25,10 @@ export class PaperService implements OnModuleInit {
|
|
|
@InjectRepository(PaperOrder)
|
|
@InjectRepository(PaperOrder)
|
|
|
private readonly paperOrderRepository: Repository<PaperOrder>,
|
|
private readonly paperOrderRepository: Repository<PaperOrder>,
|
|
|
@InjectRepository(PaperGenResult)
|
|
@InjectRepository(PaperGenResult)
|
|
|
- private readonly paperGenResultRepository: Repository<PaperGenResult>
|
|
|
|
|
|
|
+ private readonly paperGenResultRepository: Repository<PaperGenResult>,
|
|
|
|
|
+ @InjectRepository(RefSearchRecord)
|
|
|
|
|
+ private readonly refSearchRecordRepository: Repository<RefSearchRecord>,
|
|
|
|
|
+ private readonly membershipService: MembershipService
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
async onModuleInit() {
|
|
async onModuleInit() {
|
|
@@ -122,15 +129,24 @@ export class PaperService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async searchReferences(title: string) {
|
|
|
|
|
- // const { llm } = createLLM('gpt-3.5-turbo')
|
|
|
|
|
- // const { content } = await llm.call([
|
|
|
|
|
- // new HumanMessage(
|
|
|
|
|
- // `您需要从陈述或问题中提取关键词,并返回由逗号分隔的一系列关键词。例如,如果问题是“什么是人工智能?”,则关键词可能是“人工智能,AI,人工智能,机器学习,深度学习”。\n\n问题:${title}\n关键词:`
|
|
|
|
|
- // )
|
|
|
|
|
- // ])
|
|
|
|
|
- // const keywords = content.replace(/[,,]/g, ' ')
|
|
|
|
|
- const keywords = title
|
|
|
|
|
|
|
+ async searchReferences(userId: number, title: string) {
|
|
|
|
|
+ let record = await this.refSearchRecordRepository.findOneBy({
|
|
|
|
|
+ userId,
|
|
|
|
|
+ createdAt: Between(startOfDay(new Date()), endOfDay(new Date()))
|
|
|
|
|
+ })
|
|
|
|
|
+ if (record) {
|
|
|
|
|
+ const member = await this.membershipService.getMembership(userId, false)
|
|
|
|
|
+ if (!member || member.isExpired) {
|
|
|
|
|
+ throw new InternalServerErrorException('USAGE_LIMIT_EXCEEDED')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const { llm } = createLLM('gpt-3.5-turbo')
|
|
|
|
|
+ const { content } = await llm.call([
|
|
|
|
|
+ new HumanMessage(`你要从我给你的论文标题中提取2-3个由逗号分隔的主要关键词。\n\n标题:${title}\n关键词:`)
|
|
|
|
|
+ ])
|
|
|
|
|
+ const keywords = content.replace(/,/g, ',').split(',')
|
|
|
|
|
+ // const keywords = title
|
|
|
const http = axios.create({
|
|
const http = axios.create({
|
|
|
headers: {
|
|
headers: {
|
|
|
Host: 'kns.cnki.net',
|
|
Host: 'kns.cnki.net',
|
|
@@ -151,55 +167,106 @@ export class PaperService implements OnModuleInit {
|
|
|
Cookie: 'Ecp_notFirstLogin=8TNR2E; KNS3COOKIE=1705297590.529.38190.813537|b25e41a932fd162af3b8c5cff4059fc3; Ecp_ClientId=m240115134600532586; Ecp_IpLoginFail=240115180.111.242.2; SID_sug=128008; SID_kns_new=kns25128005; Ecp_ClientIp=180.111.242.2; SID_restapi=018105; LID=WEEvREcwSlJHSldTTEYyTE5mZ3VrVmtob3VPdjBpS29QOWl1NG1pRVJqWT0=$9A4hF_YAuvQ5obgVAqNKPCYcEjKensW4IQMovwHtwkF4VYPoHbKxJw!!; Ecp_session=1; Ecp_showrealname=1; Ecp_LoginStuts={"IsAutoLogin":false,"UserName":"15077886171","ShowName":"15077886171","UserType":"jf","BUserName":"","BShowName":"","BUserType":"","r":"8TNR2E","Members":[]}; Ecp_loginuserjf=15077886171; c_m_LinID=LinID=WEEvREcwSlJHSldTTEYyTE5mZ3VrVmtob3VPdjBpS29QOWl1NG1pRVJqWT0=$9A4hF_YAuvQ5obgVAqNKPCYcEjKensW4IQMovwHtwkF4VYPoHbKxJw!!&ot=02%2F14%2F2024%2013%3A52%3A01; c_m_expire=2024-02-14%2013%3A52%3A01; dblang=both'
|
|
Cookie: 'Ecp_notFirstLogin=8TNR2E; KNS3COOKIE=1705297590.529.38190.813537|b25e41a932fd162af3b8c5cff4059fc3; Ecp_ClientId=m240115134600532586; Ecp_IpLoginFail=240115180.111.242.2; SID_sug=128008; SID_kns_new=kns25128005; Ecp_ClientIp=180.111.242.2; SID_restapi=018105; LID=WEEvREcwSlJHSldTTEYyTE5mZ3VrVmtob3VPdjBpS29QOWl1NG1pRVJqWT0=$9A4hF_YAuvQ5obgVAqNKPCYcEjKensW4IQMovwHtwkF4VYPoHbKxJw!!; Ecp_session=1; Ecp_showrealname=1; Ecp_LoginStuts={"IsAutoLogin":false,"UserName":"15077886171","ShowName":"15077886171","UserType":"jf","BUserName":"","BShowName":"","BUserType":"","r":"8TNR2E","Members":[]}; Ecp_loginuserjf=15077886171; c_m_LinID=LinID=WEEvREcwSlJHSldTTEYyTE5mZ3VrVmtob3VPdjBpS29QOWl1NG1pRVJqWT0=$9A4hF_YAuvQ5obgVAqNKPCYcEjKensW4IQMovwHtwkF4VYPoHbKxJw!!&ot=02%2F14%2F2024%2013%3A52%3A01; c_m_expire=2024-02-14%2013%3A52%3A01; dblang=both'
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
- const res = await http.post(
|
|
|
|
|
- 'https://kns.cnki.net/kns8s/brief/grid',
|
|
|
|
|
-
|
|
|
|
|
- qs.stringify({
|
|
|
|
|
- boolSearch: true,
|
|
|
|
|
- QueryJson: `{"Platform":"","Resource":"CROSSDB","Classid":"WD0FTY92","Products":"","QNode":{"QGroup":[{"Key":"Subject","Title":"","Logic":0,"Items":[{"Field":"SU","Value":"${keywords}","Operator":"TOPRANK","Logic":0}],"ChildItems":[]}]},"ExScope":1,"SearchType":2,"Rlang":"CHINESE","KuaKuCode":"YSTT4HG0,LSTPFY1C,JUP3MUPD,MPMFIG1A,EMRPGLPA,WQ0UVIAA,BLZOG7CK,PWFIRAGL,NN3FJMUV,NLBO1Z6R"}`,
|
|
|
|
|
- pageNum: 1,
|
|
|
|
|
- pageSize: 20,
|
|
|
|
|
- dstyle: 'listmode',
|
|
|
|
|
- boolSortSearch: false,
|
|
|
|
|
- productStr:
|
|
|
|
|
- 'YSTT4HG0,LSTPFY1C,RMJLXHZ3,JQIRZIYA,JUP3MUPD,1UR4K4HZ,BPBAFJ5S,R79MZMCB,MPMFIG1A,EMRPGLPA,J708GVCE,ML4DRIDX,WQ0UVIAA,NB3BWEHK,XVLO76FD,HR1YT1Z9,BLZOG7CK,PWFIRAGL,NN3FJMUV,NLBO1Z6R,',
|
|
|
|
|
- aside: `主题:${keywords}`,
|
|
|
|
|
- searchFrom: '资源范围:总库',
|
|
|
|
|
- CurPage: 1
|
|
|
|
|
- })
|
|
|
|
|
- )
|
|
|
|
|
- const $ = load(res.data)
|
|
|
|
|
- const trs = $('tr')
|
|
|
|
|
- return (
|
|
|
|
|
|
|
+
|
|
|
|
|
+ let en = []
|
|
|
|
|
+ let zh = []
|
|
|
|
|
+ for (let kw of keywords) {
|
|
|
|
|
+ const res = await http.post(
|
|
|
|
|
+ 'https://kns.cnki.net/kns8s/brief/grid',
|
|
|
|
|
+ qs.stringify({
|
|
|
|
|
+ boolSearch: true,
|
|
|
|
|
+ QueryJson: `{"Platform":"","Resource":"CROSSDB","Classid":"WD0FTY92","Products":"","QNode":{"QGroup":[{"Key":"Subject","Title":"","Logic":0,"Items":[{"Field":"SU","Value":"${kw}","Operator":"TOPRANK","Logic":0}],"ChildItems":[]}]},"ExScope":1,"SearchType":2,"Rlang":"CHINESE","KuaKuCode":"YSTT4HG0,LSTPFY1C,JUP3MUPD,MPMFIG1A,EMRPGLPA,WQ0UVIAA,BLZOG7CK,PWFIRAGL,NN3FJMUV,NLBO1Z6R"}`,
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 20,
|
|
|
|
|
+ dstyle: 'listmode',
|
|
|
|
|
+ boolSortSearch: false,
|
|
|
|
|
+ productStr:
|
|
|
|
|
+ 'YSTT4HG0,LSTPFY1C,RMJLXHZ3,JQIRZIYA,JUP3MUPD,1UR4K4HZ,BPBAFJ5S,R79MZMCB,MPMFIG1A,EMRPGLPA,J708GVCE,ML4DRIDX,WQ0UVIAA,NB3BWEHK,XVLO76FD,HR1YT1Z9,BLZOG7CK,PWFIRAGL,NN3FJMUV,NLBO1Z6R,',
|
|
|
|
|
+ aside: `主题:${kw}`,
|
|
|
|
|
+ searchFrom: '资源范围:总库',
|
|
|
|
|
+ CurPage: 1
|
|
|
|
|
+ })
|
|
|
|
|
+ )
|
|
|
|
|
+ zh = zh.concat(this.parseRefHtml(res.data))
|
|
|
|
|
+
|
|
|
|
|
+ const res1 = await http.post(
|
|
|
|
|
+ 'https://kns.cnki.net/kns8s/brief/grid',
|
|
|
|
|
+ qs.stringify({
|
|
|
|
|
+ boolSearch: true,
|
|
|
|
|
+ QueryJson: `{"Platform":"","Resource":"CROSSDB","Classid":"WD0FTY92","Products":"","QNode":{"QGroup":[{"Key":"Subject","Title":"","Logic":0,"Items":[{"Field":"SU","Value":"${kw}","Operator":"TOPRANK","Logic":0}],"ChildItems":[]},{"Key":"SCDBGroup","Title":"","Logic":0,"Items":[],"ChildItems":[{"Key":"LG","Title":"","Logic":0,"Items":[{"Key":"EN","Title":"英语","Logic":1,"Field":"LG","Operator":"DEFAULT","Value":"EN","Value2":"","Name":"LG","ExtendType":0}],"ChildItems":[]}]}]},"ExScope":1,"SearchType":6,"Rlang":"FOREIGN","KuaKuCode":"YSTT4HG0,LSTPFY1C,JUP3MUPD,MPMFIG1A,WQ0UVIAA,BLZOG7CK,EMRPGLPA,PWFIRAGL,NLBO1Z6R,NN3FJMUV","View":""}`,
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 20,
|
|
|
|
|
+ dstyle: 'listmode',
|
|
|
|
|
+ boolSortSearch: false,
|
|
|
|
|
+ productStr:
|
|
|
|
|
+ 'YSTT4HG0,LSTPFY1C,RMJLXHZ3,JQIRZIYA,JUP3MUPD,1UR4K4HZ,BPBAFJ5S,R79MZMCB,MPMFIG1A,WQ0UVIAA,NB3BWEHK,XVLO76FD,HR1YT1Z9,BLZOG7CK,EMRPGLPA,J708GVCE,ML4DRIDX,PWFIRAGL,NLBO1Z6R,NN3FJMUV,',
|
|
|
|
|
+ aside: `主题:${kw}`,
|
|
|
|
|
+ searchFrom: '资源范围:总库',
|
|
|
|
|
+ CurPage: 1
|
|
|
|
|
+ })
|
|
|
|
|
+ )
|
|
|
|
|
+ en = en.concat(this.parseRefHtml(res1.data))
|
|
|
|
|
+ }
|
|
|
|
|
+ zh = this.sortDeduplication(zh.slice(0, 20))
|
|
|
|
|
+ en = this.sortDeduplication(en.slice(0, 10))
|
|
|
|
|
+
|
|
|
|
|
+ async function getRef(arr) {
|
|
|
await Promise.all(
|
|
await Promise.all(
|
|
|
- trs.map((i, tr) => {
|
|
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
|
|
- let $$ = load(tr)
|
|
|
|
|
- const filename = $$('td.seq .cbItem').attr('value')
|
|
|
|
|
- const name = $$('td.name a').text()
|
|
|
|
|
- if (filename) {
|
|
|
|
|
- http
|
|
|
|
|
- .post(
|
|
|
|
|
- 'https://kns.cnki.net/dm8/API/GetExport',
|
|
|
|
|
- qs.stringify({
|
|
|
|
|
- filename,
|
|
|
|
|
- displaymode: 'GBTREFER,MLA,APA',
|
|
|
|
|
- uniplatform: 'NZKPT'
|
|
|
|
|
- })
|
|
|
|
|
- )
|
|
|
|
|
- .then((res) => {
|
|
|
|
|
- resolve({
|
|
|
|
|
- filename,
|
|
|
|
|
- name,
|
|
|
|
|
- reference: res.data.data
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- } else {
|
|
|
|
|
- resolve(null)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ arr.map((item) => {
|
|
|
|
|
+ return http
|
|
|
|
|
+ .post(
|
|
|
|
|
+ 'https://kns.cnki.net/dm8/API/GetExport',
|
|
|
|
|
+ qs.stringify({
|
|
|
|
|
+ filename: item.filename,
|
|
|
|
|
+ displaymode: 'GBTREFER,MLA,APA',
|
|
|
|
|
+ uniplatform: 'NZKPT'
|
|
|
|
|
+ })
|
|
|
|
|
+ )
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ item.ref = res.data.data.map((i) => i.value[0].replace(/^\[\d+\]/, ''))
|
|
|
|
|
+ })
|
|
|
})
|
|
})
|
|
|
)
|
|
)
|
|
|
- ).filter((i) => !!i)
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ await getRef(zh)
|
|
|
|
|
+ await getRef(en)
|
|
|
|
|
+ await this.refSearchRecordRepository.save({
|
|
|
|
|
+ userId,
|
|
|
|
|
+ title
|
|
|
|
|
+ })
|
|
|
|
|
+ return { zh, en }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ parseRefHtml(html: any) {
|
|
|
|
|
+ const $ = load(html)
|
|
|
|
|
+ const trs = $('tr')
|
|
|
|
|
+ const res = []
|
|
|
|
|
+ trs.each((i, tr) => {
|
|
|
|
|
+ let $$ = load(tr)
|
|
|
|
|
+ const filename = $$('td.seq .cbItem').attr('value')
|
|
|
|
|
+ if (filename) {
|
|
|
|
|
+ const name = $$('td.name a').text()
|
|
|
|
|
+ const date = $$('td.date').text()
|
|
|
|
|
+ res.push({
|
|
|
|
|
+ filename,
|
|
|
|
|
+ name,
|
|
|
|
|
+ date
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ return res
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sortDeduplication(arr: any[]) {
|
|
|
|
|
+ let res = []
|
|
|
|
|
+ arr.forEach((item) => {
|
|
|
|
|
+ if (!res.find((i) => i.filename === item.filename)) {
|
|
|
|
|
+ res.push(item)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ res.sort((a, b) => {
|
|
|
|
|
+ return parse(b.date, 'yyyy-MM-dd', new Date()).getTime() - parse(a.date, 'yyyy-MM-dd', new Date()).getTime()
|
|
|
|
|
+ })
|
|
|
|
|
+ return res
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|