返回 AiToEarn
service.ts
1 /*
2 * @Author: nevin
3 * @Date: 2025-01-24 17:10:35
4 * @LastEditors: nevin
5 * @Description: interactionRecord InteractionRecord
6 */
7 import { Inject, Injectable } from '../core/decorators';
8 import PQueue from 'p-queue';
9 import { AccountModel } from '../../db/models/account';
10 import platController from '../plat';
11 import { toolsApi } from '../api/tools';
12 import { AutoRunService } from '../autoRun/service';
13 import { AutoRunModel } from '../../db/models/autoRun';
14 import { sysNotice } from '../../global/notice';
15 import { FindOptionsWhere, Repository } from 'typeorm';
16 import { AppDataSource } from '../../db';
17 import { getUserInfo } from '../user/comment';
18 import { AutoRunRecordStatus } from '../../db/models/autoRunRecord';
19 import { sleep } from '../../util/time';
20 import { InteractionRecordModel } from '../../db/models/interactionRecord';
21 import { AutorWorksInteractionScheduleEvent } from '../../../commont/types/interaction';
22 import { WorkData } from '../plat/plat.type';
23 import { AutoInteractionCache } from './cacheData';
24 import { backPageData, CorrectQuery } from '../../global/table';
25 import { PlatType } from '../../../commont/AccountEnum';
26 import { AccountService } from '../account/service';
27 import { UserService } from '../user/service';
28 // import { ReplyController } from '../reply/controller';
29
30
31 @Injectable()
32 export class InteractionService {
33 interactionQueue: PQueue;
34 private interactionRecordRepository: Repository<InteractionRecordModel>;
35
36 constructor() {
37 this.interactionQueue = new PQueue({ concurrency: 1 });
38 this.interactionRecordRepository = AppDataSource.getRepository(
39 InteractionRecordModel,
40 );
41 }
42
43 @Inject(AutoRunService)
44 private readonly autoRunService!: AutoRunService;
45
46 // 创建互动记录
47 async createInteractionRecord(
48 userId: string,
49 account: AccountModel,
50 works: {
51 worksId: string;
52 worksTitle?: string;
53 worksCover?: string;
54 },
55 commentRemark: string,
56 commentContent: string,
57 isLike: 0 | 1,
58 isCollect: 0 | 1,
59 ) {
60 return await this.interactionRecordRepository.save({
61 userId,
62 accountId: account.id,
63 type: account.type,
64 worksId: works.worksId,
65 worksTitle: works.worksTitle,
66 worksCover: works.worksCover,
67 commentRemark,
68 commentContent,
69 isLike: isLike,
70 isCollect: isCollect,
71 });
72 }
73
74 // 获互动记录
75 async getInteractionRecord(
76 userId: string,
77 account: AccountModel,
78 worksId: string,
79 ) {
80 return await this.interactionRecordRepository.findOne({
81 where: {
82 userId,
83 accountId: account.id,
84 type: account.type,
85 worksId: worksId + '',
86 },
87 });
88 }
89
90 // 获取互动记录列表
91 async getInteractionRecordList(
92 userId: string,
93 page: CorrectQuery,
94 query: {
95 accountId?: number;
96 type?: PlatType;
97 },
98 ) {
99 const filter: FindOptionsWhere<InteractionRecordModel> = {
100 userId,
101 ...(query.accountId && { accountId: query.accountId }),
102 ...(query.type && { type: query.type }),
103 };
104
105 const [list, totalCount] =
106 await this.interactionRecordRepository.findAndCount({
107 where: filter,
108 order: {
109 createTime: 'DESC',
110 },
111 });
112
113 return backPageData(list, totalCount, page);
114 }
115
116 /**
117 * 自动AI评论截流:作品评论,收藏,点赞
118 * 规则:评论作品,已经评论不评论
119 */
120 async autorInteraction(
121 account: AccountModel,
122 worksList: WorkData[],
123 option: {
124 commentContent?: string; // 评论内容
125 taskId?: string; // 任务ID
126 platform?: string; // 平台ID
127 likeProb?: any; // 点赞概率
128 collectProb?: any; // 收藏概率
129 commentProb?: any; // 评论概率
130 commentType: any; // 评论类型
131 },
132 scheduleEvent: (data: {
133 tag: AutorWorksInteractionScheduleEvent;
134 status: -1 | 0 | 1; // -1 错误 0 进行中 1 完成
135 data?: any; // 数据
136 error?: any;
137 }) => void,
138 ) {
139 const commentContentList = option.commentContent
140 ? option.commentContent.split(',')
141 : [];
142 console.log('------ commentContentList ----', commentContentList);
143 // return;
144
145 const userInfo = getUserInfo();
146
147 // 设置缓存
148 const cacheData = new AutoInteractionCache({
149 title: '互动任务',
150 });
151
152 try {
153 console.log(
154 '------ 开始执行互动任务,作品数量:',
155 worksList.length,
156 worksList[0],
157 );
158 scheduleEvent({
159 tag: AutorWorksInteractionScheduleEvent.Start,
160 status: 0,
161 });
162
163 // 1. 循环AI回复评论
164 let i = 0;
165 for (const works of worksList) {
166 // console.log('------ 开始处理作品:', works);
167 // 等待
168 if (i > 0) await sleep(10 * 1000);
169 i++;
170 const oldRecord = await this.getInteractionRecord(
171 userInfo.id,
172 account,
173 works.dataId,
174 );
175 if (oldRecord) continue;
176
177 // console.log('option.commentContent', option);
178 let thisCommentContent = '';
179 if (option.commentType && option.commentType == 'ai') {
180 const aiRes = await toolsApi.aiRecoverReview({
181 content: (works.desc || '') + (works.title || ''),
182 });
183
184 // AI接口错误
185 if (!aiRes) {
186 scheduleEvent({
187 tag: AutorWorksInteractionScheduleEvent.Error,
188 status: -1,
189 error: '未获得AI产出内容',
190 });
191 cacheData.delete();
192 return false;
193 }
194
195 thisCommentContent = aiRes;
196 }
197
198 if (option.commentType && option.commentType == 'copy') {
199 const commentList = await platController.getCommentList(
200 account,
201 {
202 dataId: works.dataId,
203 option: {
204 xsec_token: works.data?.xsec_token || '',
205 },
206 },
207 '0',
208 );
209
210 // console.log('------ commentList', commentList);
211
212 const randomIndex = Math.floor(
213 Math.random() * commentList.list.length,
214 );
215 thisCommentContent = commentList.list[randomIndex].content;
216
217 // option.commentContent = aiRes;
218 }
219
220 console.log('------ option.commentType', option.commentType);
221 if (option.commentType && option.commentType == 'custom') {
222 // let commentContentList = option.commentContent.split(',');
223 console.log('------ commentContentList', commentContentList);
224 const randomIndex = Math.floor(
225 Math.random() * commentContentList.length,
226 );
227 console.log('------ randomIndex', randomIndex);
228 thisCommentContent = commentContentList[randomIndex];
229 }
230 console.log('------ option.commentContent', thisCommentContent);
231 // return;
232
233 scheduleEvent({
234 tag: AutorWorksInteractionScheduleEvent.ReplyCommentStart,
235 data: {
236 aiContent: thisCommentContent,
237 },
238 status: 0,
239 });
240
241 // ----- 1-评论作品 -----
242 console.log(
243 '------ 开始评论作品:',
244 works.dataId,
245 thisCommentContent,
246 works.author?.id,
247 );
248
249 // 判断是否执行评论
250 const shouldComment =
251 option.commentProb === 0
252 ? false
253 : !option.commentProb || Math.random() * 100 < option.commentProb;
254 let commentWorksRes: any = {};
255
256 if (shouldComment) {
257 // if (option.commentContent.includes(',')) {
258 // const randomIndex = Math.floor(
259 // Math.random() * option.commentContent.split(',').length,
260 // );
261 // option.commentContent =
262 // option.commentContent.split(',')[randomIndex];
263 // }
264
265 console.log('------ option.commentContent', thisCommentContent);
266
267 commentWorksRes = await platController.createCommentByOther(
268 account,
269 works.dataId,
270 thisCommentContent,
271 works.author?.id,
272 );
273 console.log('------ 评论作品结果:', commentWorksRes);
274
275 // 错误处理
276 if (!commentWorksRes) {
277 scheduleEvent({
278 tag: AutorWorksInteractionScheduleEvent.ReplyCommentEnd,
279 status: -1,
280 error: '回复评论失败',
281 });
282 continue;
283 }
284
285 scheduleEvent({
286 tag: AutorWorksInteractionScheduleEvent.ReplyCommentEnd,
287 status: 0,
288 });
289 }
290
291 // ----- 2-点赞作品 -----
292 let isLike: 0 | 1 = 0;
293 // 判断是否执行点赞
294 const randomLike = Math.random() * 100;
295 console.log(
296 '判断是否执行点赞',
297 '概率:',
298 option.likeProb,
299 '随机值:',
300 randomLike,
301 );
302 const shouldLike =
303 option.likeProb === 0
304 ? false
305 : !option.likeProb || randomLike < option.likeProb;
306
307 console.log('------ shouldLike', shouldLike);
308
309 if (shouldLike) {
310 try {
311 console.log('------ 开始点赞作品:', works.dataId, works.author?.id);
312 const isLikeRes = await platController.dianzanDyOther(
313 account,
314 works.dataId,
315 {
316 authid: works.author?.id,
317 },
318 );
319 isLike = isLikeRes ? 1 : 0;
320 console.log('------ 点赞结果:', isLikeRes);
321 } catch (error) {
322 scheduleEvent({
323 tag: AutorWorksInteractionScheduleEvent.Error,
324 status: 0,
325 error,
326 data: {
327 isLike,
328 },
329 });
330 }
331 }
332
333 // ----- 3-收藏作品 -----
334 let isCollect: 0 | 1 = 0;
335
336 // 判断是否执行收藏
337 const randomCollect = Math.random() * 100;
338 console.log(
339 '判断是否执行收藏',
340 '概率:',
341 option.collectProb,
342 '随机值:',
343 randomCollect,
344 );
345 const shouldCollect =
346 (option.collectProb === 0
347 ? false
348 : !option.collectProb || randomCollect < option.collectProb) &&
349 option.platform != 'KWAI';
350
351 if (shouldCollect) {
352 try {
353 const isCollectRes = await platController.shoucangDyOther(
354 account,
355 works.dataId,
356 );
357 isCollect = isCollectRes ? 1 : 0;
358 } catch (error) {
359 scheduleEvent({
360 tag: AutorWorksInteractionScheduleEvent.Error,
361 status: 0,
362 error,
363 data: {
364 isLike,
365 },
366 });
367 }
368 }
369
370 let commentRemark = '';
371 if (commentWorksRes.data) {
372 if (commentWorksRes.data?.msg) {
373 commentRemark = commentWorksRes.data.msg;
374 } else {
375 commentRemark = commentWorksRes.data.toast;
376 }
377 } else {
378 commentRemark = '评论完成';
379 }
380
381 // 创建互动记录
382 this.createInteractionRecord(
383 userInfo.id,
384 account,
385 {
386 worksId: works.dataId,
387 worksTitle: works.title,
388 worksCover: works.coverUrl,
389 },
390 commentRemark,
391 thisCommentContent,
392 isLike,
393 isCollect, // 收藏状态设为0
394 );
395 console.log('------ 作品处理完成:', works.dataId);
396 }
397
398 console.log('------ 所有作品处理完成');
399 scheduleEvent({
400 tag: AutorWorksInteractionScheduleEvent.ReplyCommentEnd,
401 status: 1,
402 });
403
404 return true;
405 } catch (error) {
406 console.error('------ 任务执行出错:', error);
407 scheduleEvent({
408 tag: AutorWorksInteractionScheduleEvent.Error,
409 status: -1,
410 error,
411 });
412 return false;
413 }
414
415 // 清除缓存
416 cacheData.delete();
417 }
418
419 /**
420 * 添加作品回复评论的任务到队列
421 * @param account
422 * @param dataId
423 */
424 async addReplyQueue(
425 account: AccountModel,
426 worksList: WorkData[],
427 option: {
428 commentContent: string; // 评论内容
429 },
430 autoRun: AutoRunModel,
431 ): Promise<{
432 status: 0 | 1;
433 message?: string;
434 }> {
435 // 查看缓存,有的就不执行
436 if (AutoInteractionCache.getInfo()) {
437 sysNotice('请勿重复执行', `有正在执行的任务,任务ID:${autoRun.id}`);
438
439 return {
440 status: 0,
441 message: '有正在执行的任务,请勿重复执行',
442 };
443 }
444
445 // 创建任务执行记录
446 const recordData = await this.autoRunService.createAutoRunRecord(autoRun);
447
448 // 添加到队列
449 this.interactionQueue.add(() => {
450 this.autorInteraction(
451 account,
452 worksList,
453 option as any,
454 (e: {
455 tag: AutorWorksInteractionScheduleEvent;
456 status: -1 | 0 | 1;
457 error?: any;
458 }) => {
459 if (e.tag === AutorWorksInteractionScheduleEvent.Start) {
460 sysNotice('自动互动任务执行开始', `任务ID:${autoRun.id}`);
461 }
462
463 if (e.tag === AutorWorksInteractionScheduleEvent.End) {
464 sysNotice('自动互动任务执行结束', `任务ID:${autoRun.id}`);
465 this.autoRunService.updateAutoRunRecordStatus(
466 recordData.id,
467 AutoRunRecordStatus.SUCCESS,
468 );
469 }
470
471 if (e.tag === AutorWorksInteractionScheduleEvent.Error) {
472 sysNotice('自动互动回复任务-错误!!!', `任务ID:${autoRun.id}`);
473 this.autoRunService.updateAutoRunRecordStatus(
474 recordData.id,
475 AutoRunRecordStatus.FAIL,
476 );
477 }
478 },
479 );
480 });
481
482 return {
483 status: 1,
484 };
485 }
486
487 // 自动互动
488 @Inject(UserService)
489 private readonly userService!: UserService;
490 @Inject(AccountService)
491 private readonly accountService!: AccountService;
492
493 // 获取自动互动列表
494 async getAutorInteractionList(account: any, worksList: any, option: any) {
495 console.log('------ server option.commentContent ----', option.commentContent);
496 return await this.autorInteraction(
497 account,
498 worksList,
499 {
500 commentContent: option.commentContent || null,
501 platform: option.accountType, // 平台
502 likeProb: 999, // 点赞概率
503 collectProb: 999, // 收藏概率
504 commentProb: 999, // 评论概率
505 commentType: option.commentContent?'custom' : 'ai', // 评论类型
506 },
507 (e: {
508 tag: AutorWorksInteractionScheduleEvent;
509 status: -1 | 0 | 1;
510 error?: any;
511 }) => {
512 console.log('------ e', e);
513 },
514 );
515 }
516 }
517
517 lines TYPESCRIPT