diff --git a/backend/README.md b/backend/README.md index c980ab8..bfa4faa 100644 --- a/backend/README.md +++ b/backend/README.md @@ -2,6 +2,12 @@ - nest.js 기반으로 구성한 웹 API 백엔드 서버입니다. - 웹 API 백엔드 서버는 프로젝트 내 필요한 API 기능들을 제공합니다. +## 구조도 +### 스크래핑 모듈 구조도 +![이미지](./server/docs/img/crawling_module.png) +[링크](https://github.com/blaxsior/lambda-deploy-test) +### 서버 구조도 +![이미지](./server/docs/img/server.png) ## 사용법 API 서버는 docker 기반으로 동작하므로, 먼저 docker을 설치하세요. - 실행: ``docker-compose -f docker-compose.dev.yml up`` @@ -193,8 +199,8 @@ NewsSource는 뉴스를 수집할 언론사를 의미합니다. 뉴스 스크래 erDiagram Comment { str contents - number sympathyCount - number antipathyCount + int sympathyCount + int antipathyCount date date "※댓글 작성일" } @@ -205,21 +211,21 @@ erDiagram } AnalysisComment { - number id PK + int id PK date createdAt "※댓글 작성일" str content - number sympathy - number antipathy + int sympathy + int antipathy string link string emotion - number keyword_id FK + int keyword_id FK } ArticleContent { - number id PK + int id PK string content - number score - number comment_id FK + float score + int comment_id FK } Keyword { @@ -232,26 +238,26 @@ erDiagram } KeywordHistory { - number id PK + int id PK string description string action date createdAt "auto" - number keyword_id FK + int keyword_id FK } Admin { - number id PK + int id PK string login_id UK string password string name date createdAt } TokenInfo { - number id PK + int id PK string refresh_key "nullable" } NewsSource { - number id PK - number media_id + int id PK + int media_id string media_name date createdAt } diff --git a/backend/server/docs/ERD.md b/backend/server/docs/ERD.md index f6dcb60..532785a 100644 --- a/backend/server/docs/ERD.md +++ b/backend/server/docs/ERD.md @@ -4,8 +4,8 @@ erDiagram Comment { str contents - number sympathyCount - number antipathyCount + int sympathyCount + int antipathyCount date date "※댓글 작성일" } @@ -16,21 +16,21 @@ erDiagram } AnalysisComment { - number id PK + int id PK date createdAt "※댓글 작성일" str content - number sympathy - number antipathy + int sympathy + int antipathy string link string emotion - number keyword_id FK + int keyword_id FK } ArticleContent { - number id PK + int id PK string content - number score - number comment_id FK + float score + int comment_id FK } Keyword { @@ -43,26 +43,26 @@ erDiagram } KeywordHistory { - number id PK + int id PK string description string action date createdAt "auto" - number keyword_id FK + int keyword_id FK } Admin { - number id PK + int id PK string login_id UK string password string name date createdAt } TokenInfo { - number id PK + int id PK string refresh_key "nullable" } NewsSource { - number id PK - number media_id + int id PK + int media_id string media_name date createdAt } diff --git a/backend/server/docs/img/crawling_module.png b/backend/server/docs/img/crawling_module.png new file mode 100644 index 0000000..b46e39b Binary files /dev/null and b/backend/server/docs/img/crawling_module.png differ diff --git a/backend/server/docs/img/server.png b/backend/server/docs/img/server.png new file mode 100644 index 0000000..02cb028 Binary files /dev/null and b/backend/server/docs/img/server.png differ diff --git a/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts b/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts index 06fd33d..6450f6c 100644 --- a/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts +++ b/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts @@ -36,6 +36,7 @@ describe('AnalysisCommentController', () => { content: '', createdAt: new Date(), emotion: '', + big_emotion: '', keyword_id: 0, link: '', news_sentences: [], diff --git a/backend/server/src/analysis-comment/analysis-comment.service.ts b/backend/server/src/analysis-comment/analysis-comment.service.ts index a78754d..e02ebec 100644 --- a/backend/server/src/analysis-comment/analysis-comment.service.ts +++ b/backend/server/src/analysis-comment/analysis-comment.service.ts @@ -4,7 +4,7 @@ import { Between, DataSource, FindOperator, Repository } from 'typeorm'; import { AnalysisComment } from './entity/analysis-comment.entity'; import { CreateCommentReqDto } from './dtos/create-comment.dto'; import { ArticleContent } from './entity/article-content.entity'; -import { GetCommentsQueriesReqDto } from './dtos/get-comments-query.dto'; +import { CommentsQueriesReqDto } from './dtos/get-comments-query.dto'; @Injectable() export class AnalysisCommentService { @@ -23,6 +23,7 @@ export class AnalysisCommentService { comment.sympathy = dtos.sympathy; comment.antipathy = dtos.antipathy; comment.emotion = dtos.emotion; + comment.big_emotion = dtos.big_emotion; comment.link = dtos.link; comment.keyword_id = dtos.keyword_id; @@ -92,7 +93,7 @@ export class AnalysisCommentService { head_id, from, to, - }: GetCommentsQueriesReqDto) { + }: CommentsQueriesReqDto) { if (!search) return []; const qb = this.comment_repo.createQueryBuilder(); @@ -103,6 +104,7 @@ export class AnalysisCommentService { 'sympathy', 'antipathy', 'emotion', + 'big_emotion', 'link', ]).where(`keyword_id IN (SELECT id FROM keyword WHERE name = :name)`, { name: search, @@ -131,7 +133,16 @@ export class AnalysisCommentService { const qb = this.dataSource .createQueryBuilder() - .select(['id', 'content', 'sympathy', 'antipathy', 'emotion']) + .select([ + 'id', + 'createdAt', + 'content', + 'sympathy', + 'antipathy', + 'emotion', + 'big_emotion', + 'link', + ]) .from((subQuery) => { subQuery .select('*') @@ -148,6 +159,11 @@ export class AnalysisCommentService { return subQuery; }, 'temp') .where('ranking = 1'); - return await qb.getRawMany(); + const data = await qb.getRawMany(); + return data.map((it) => { + const comment = new AnalysisComment(); + Object.assign(comment, it); + return comment; + }); } } diff --git a/backend/server/src/analysis-comment/dtos/create-comment.dto.ts b/backend/server/src/analysis-comment/dtos/create-comment.dto.ts index bbdf7d2..9104bab 100644 --- a/backend/server/src/analysis-comment/dtos/create-comment.dto.ts +++ b/backend/server/src/analysis-comment/dtos/create-comment.dto.ts @@ -42,11 +42,18 @@ export class CreateCommentReqDto { /** * 댓글의 대표 감정 - * @example happiness + * @example 행복 */ @IsString() emotion: string; + /** + * 댓글의 감정 대분류 + * @example 행복 + */ + @IsString() + big_emotion: string; + /** * 대응되는 키워드의 id 값 * @example 1 diff --git a/backend/server/src/analysis-comment/dtos/get-comments-query.dto.ts b/backend/server/src/analysis-comment/dtos/get-comments-query.dto.ts index 192aed5..3479610 100644 --- a/backend/server/src/analysis-comment/dtos/get-comments-query.dto.ts +++ b/backend/server/src/analysis-comment/dtos/get-comments-query.dto.ts @@ -2,7 +2,7 @@ import { IsString, IsNumber, IsOptional, IsDateString } from 'class-validator'; /** * 댓글 검색에 사용되는 쿼리 목록 */ -export class GetCommentsQueriesReqDto { +export class CommentsQueriesReqDto { /** * 검색어 * @example 윤석열 diff --git a/backend/server/src/analysis-comment/entity/analysis-comment.entity.ts b/backend/server/src/analysis-comment/entity/analysis-comment.entity.ts index 495424c..3d689d3 100644 --- a/backend/server/src/analysis-comment/entity/analysis-comment.entity.ts +++ b/backend/server/src/analysis-comment/entity/analysis-comment.entity.ts @@ -41,18 +41,24 @@ export class AnalysisComment { @Column() link: string; /** - * 댓글에 할당된 감정 + * 댓글에 할당된 감정(기쁨, 슬픔, 당황, 분노 등) */ @Column() emotion: string; + /** + * 댓글에 할당된 감정 대분류(긍정 / 부정 / 중립) + */ + @Column() + big_emotion: string; + @Column() keyword_id: number; @OneToMany(() => ArticleContent, (content) => content.comment) - news_sentences: ArticleContent[]; + news_sentences?: ArticleContent[]; @JoinColumn({ name: 'keyword_id' }) @ManyToOne(() => Keyword, (keyword) => keyword.comments) - keyword: Keyword; + keyword?: Keyword; } diff --git a/backend/server/src/analysis-comment/entity/article-content.entity.ts b/backend/server/src/analysis-comment/entity/article-content.entity.ts index f027247..17a544e 100644 --- a/backend/server/src/analysis-comment/entity/article-content.entity.ts +++ b/backend/server/src/analysis-comment/entity/article-content.entity.ts @@ -22,7 +22,7 @@ export class ArticleContent { /** * 댓글과 문장 사이의 연관도 점수(-1 ~ 1 사이) */ - @Column() + @Column({ type: 'float' }) score: number; /** diff --git a/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts b/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts index 2ce6c66..2734a41 100644 --- a/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts +++ b/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts @@ -27,17 +27,14 @@ export class KeywordWithTopCommentsReqQueryDto { @IsOptional() to?: string; } - export class OutCommentDto - implements - Omit< - AnalysisComment, - 'link' | 'keyword_id' | 'news_sentences' | 'keyword' | 'createdAt' - > + implements Omit { @Expose() id: number; @Expose() + createdAt: Date; + @Expose() content: string; @Expose() sympathy: number; @@ -45,12 +42,16 @@ export class OutCommentDto antipathy: number; @Expose() emotion: string; + @Expose() + big_emotion: string; + @Expose() + link: string; } export class KeywordWithTopCommentsResDto { @Expose() keyword: OutKeywordDto; - @Expose() + @Expose({ toClassOnly: false, toPlainOnly: false }) comments: OutCommentDto[]; } diff --git a/backend/server/src/search/search.controller.ts b/backend/server/src/search/search.controller.ts index f5758e4..aea5723 100644 --- a/backend/server/src/search/search.controller.ts +++ b/backend/server/src/search/search.controller.ts @@ -25,7 +25,7 @@ export class SearchController { description: '중요한 키워드 목록을 반환한다.', type: () => PopularKeywordsResDto, }) - // @Serialize(PopularKeywordsResDto) + @Serialize(PopularKeywordsResDto) @Get('popular-keywords') async getPopularKeywords( @Query() dto: PopularKeywordsReqQueryDto, @@ -46,7 +46,7 @@ export class SearchController { status: 200, type: () => KeywordWithTopCommentsResDto, }) - @Serialize(KeywordWithTopCommentsResDto) + // @Serialize(KeywordWithTopCommentsResDto) @Get('keyword-search-result') async getKeywordWithTopComments( @Query() dto: KeywordWithTopCommentsReqQueryDto, diff --git a/backend/server/src/search/search.service.ts b/backend/server/src/search/search.service.ts index f37755b..3239024 100644 --- a/backend/server/src/search/search.service.ts +++ b/backend/server/src/search/search.service.ts @@ -73,8 +73,8 @@ export class SearchService { id, true, ); - if (!commentWithSentences) - throw new NotFoundException(`there is no comment id: ${id}`); + // if (!commentWithSentences) + // throw new NotFoundException(`there is no comment id: ${id}`); return commentWithSentences; }