Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/contents/contents.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export class TestController {
async autoCategorize(
@Body() autoCategorizeBody: AutoCategorizeBodyDto,
): Promise<AutoCategorizeOutput> {
return this.categoryService.autoCategorize(autoCategorizeBody);
return this.categoryService.autoCategorizeForTest(autoCategorizeBody);
}
}

Expand Down Expand Up @@ -459,4 +459,19 @@ export class CategoryController {
): Promise<LoadFrequentCategoriesOutput> {
return this.categoryService.loadFrequentCategories(user);
}

@ApiOperation({
summary: '아티클 카테고리 자동 지정',
description:
'아티클에 적절한 카테고리를 유저의 카테고리 목록에서 찾는 메서드',
})
@ApiBearerAuth('Authorization')
@UseGuards(JwtAuthGuard)
@Get('auto-categorize')
async autoCategorize(
@AuthUser() user: User,
@Query('link') link: string,
): Promise<AutoCategorizeOutput> {
return this.categoryService.autoCategorize(user, link);
}
}
73 changes: 72 additions & 1 deletion src/contents/contents.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ export class CategoryService {
// check if category exists in user's categories(check if category name is duplicated in same level too)
const category = userInDb.categories?.find(
(category) =>
category.slug === categorySlug && category.parentId === parentId,
category.slug === categorySlug &&
(category.parentId === parentId || (!parentId && !category.parentId)),
);

// if category doesn't exist, create it
Expand Down Expand Up @@ -806,6 +807,76 @@ export class CategoryService {
}

async autoCategorize(
user: User,
link: string,
): Promise<AutoCategorizeOutput> {
try {
const userInDb = await this.userRepository.findOneWithCategories(user.id);
if (!userInDb) {
throw new NotFoundException('User not found');
}

if (!userInDb.categories) {
throw new NotFoundException('Categories not found');
}
const categories: string[] = [];
userInDb.categories.forEach((category) => {
if (!category.parentId) {
categories.push(category.name);
}
});
const { title, siteName, description } =
await this.contentUtil.getLinkInfo(link);

const content = await this.contentUtil.getLinkContent(link);

let questionLines = [
"You are now auto categorizing machine. You can only answer a single category name or None. Here is the article's information:",
];

if (title) {
questionLines.push(`The title is "${title.trim()}"`);
}

if (content) {
const contentLength = content.length / 2;
questionLines.push(
`The opening 150 characters of the article read, "${content
.replace(/\s/g, '')
.slice(contentLength - 150, contentLength + 150)
.trim()}"`,
);
}

if (description) {
questionLines.push(`The description is ${description.trim()}"`);
}

if (siteName) {
questionLines.push(`The site's name is "${siteName.trim()}"`);
}

// Add the category options to the end of the list
questionLines.push(
`Please tell me the most appropriate category among the following. If none are suitable, return None. Here is Category options: [${categories.join(
', ',
)}]`,
);

// Join all lines together into a single string
const question = questionLines.join(' ');

const response = await this.openaiService.createChatCompletion({
question,
});

return { category: response.choices[0].message?.content || 'None' };
} catch (e) {
throw e;
}
}

async autoCategorizeForTest(
autoCategorizeBody: AutoCategorizeBodyDto,
): Promise<AutoCategorizeOutput> {
try {
Expand Down