👑 김찬휘 (Back-End) |
윤동균 (Back-End) |
이지수 (Back-End) |
서다경 (Front-End) |
김정원 (Front-End) |
박중원 (Front-End) |
REST API Spring Boot Domain DataBase Infra Garden GuestBook Social Login |
REST API Spring Boot DataBase Emotion Diary Comment Flower |
REST API Spring Boot UI/UX DataBase MyPage EC2 S3 Member Team |
UI/UX React Django Domain Map Music Member |
UI/UX React Design 3D Modeling Profile MyPage Diary |
UI/UX React Diary Flower Garden 3D Modeling GuestBook |
- 기획 및 설계 : 23.02.20 ~ 23.02.24
- 프로젝트 구현 : 23.02.27 ~ 23.03.31
- 버그 수정 및 산출물 정리 : 23.04.03 ~ 23.04.07
현대인들은 감정을 소비할 일이 많고 부정적인 감정을 느끼는 상황이 종종 발생합니다. 전문가들은 부정적인 감정을 전환하려면 자신의 감정을 직시하고, 그 순간의 상황과 감정을 기록하여 모니터링하는 것이 효과적이라고 합니다.
하지만 이러한 감정을 기록하는 것은 쉽지 않습니다. 사용자 본인이 어떤 기분인지 정확히 알 수 없고, 감정을 기록하기 위한 일기를 꾸준히 쓰기 어렵습니다.
저희는 이러한 문제를 해결하면서 일기를 쓰며 기분 전환도 되었으면 좋겠다는 생각에서Bloomer
를 기획하게 되었습니다.
일기 작성을 통해 내 감정을 이해하고 하루를 마무리할 수 있습니다.
일기 내용을 기반으로 감정을 분석해주고, 감정과 꽃과 음악을 추천해줍니다.
나와 같은 감정을 느끼는 사람들과 감정 공유도 진행할 수 있습니다.
상세 기술스택 및 버전
구분 | 기술스택 | 상세내용 | 버전 |
---|---|---|---|
공통 | 형상관리 | Gitlab | - |
이슈관리 | Jira | - | |
커뮤니케이션 | Mattermost, Notion | - | |
BackEnd | DB | MySQL | 8.0.21 |
JPA | - | ||
QueryDSL | - | ||
Java | OpenJDK | 11.0.16.1 | |
Spring | Spring Boot | 2.4.5 | |
Django | Django | 3.2.18 | |
IDE | IntelliJ | - | |
Build | Gradle | 7.5.1 | |
FrontEnd | HTML5 | - | |
CSS3 | - | ||
JavaScript(ES6) | - | ||
React | React | 18.2.0 | |
styled-components | 5.3.6 | ||
axios | 1.2.3 | ||
IDE | Visual Studio Code | 1.75.1 | |
Server | Server | AWS EC2 | - |
Server | AWS EC2 S3 | - | |
Server | Nginx | 1.18.0 | |
배포 | Docker | 20.10.23 | |
배포 | Jenkins | 2.378.1 | |
Test | test | Postman | 10.9.4 |
test | JUnit5 | - | |
test | Mockito | - | |
test | Jacoco | toolVersion 0.8.7 |
시스템 아키텍처 |
---|
Front-end
C:.
+---flory
| +---.vscode
| +---exec
| +---nginx
| +---public
| | +---models
| | | \---flowers
| | \---videos
| \---src
| +---assets
| | +---gltfs
| | | \---flowers
| | +---imgs
| | | +---button
| | | +---flower_bgicon
| | | +---flower_icon
| | | +---info
| | | +---login
| | | +---lotties
| | | +---profile_icon
| | | \---weather_icon
| | \---mp3
| +---components
| | +---common
| | | +---Accordion
| | | +---Avatar
| | | +---BackButton
| | | +---Button
| | | +---Chip
| | | +---CommentInput
| | | +---CreateInput
| | | +---CreateInputLine
| | | +---FloatWrapper
| | | +---Graph
| | | | +---Bar
| | | | \---Pie
| | | +---List
| | | +---Modal
| | | | +---AlertModal
| | | | \---BasicModal
| | | +---Navbar
| | | +---Post
| | | +---ProfileCard
| | | +---ScrollToTop
| | | +---ScrollToTopButton
| | | +---SettingPopover
| | | +---StyledIcons
| | | +---Tabs
| | | \---ToggleButton
| | +---Diary
| | | +---DiaryComment
| | | +---DiaryDate
| | | +---DiaryDatePicker
| | | +---DiaryFlower
| | | +---DiaryList
| | | +---DiaryListItem
| | | +---DiaryLocationModal
| | | +---DiaryMusicButton.tsx
| | | +---DiaryMusicItem
| | | +---DiaryTotalList
| | | +---DiaryWeather
| | | +---GroupItems
| | | +---GroupTag
| | | \---GroupTagWrapper
| | +---FlowerCreate
| | +---Flowers
| | +---Garden
| | | +---Beach
| | | +---Camp
| | | +---GardenCalendar
| | | +---Park
| | | \---Siba
| | +---GardenTheme
| | +---Group
| | | +---GroupSearchInput
| | | +---GroupUnJoinList
| | | \---GroupUnJoinListITem
| | +---GuestBook
| | | +---GuestBookComment
| | | \---GuestBookModel
| | +---Info
| | | +---RotatingText
| | | \---SubTitle
| | +---Main
| | | \---MainFlowerAsset
| | +---Map
| | | +---BasicMap
| | | +---CommunityMap
| | | +---MapFilterModal
| | | +---MapSearchInput
| | | +---SearchMap
| | | \---StaticMap
| | +---MyPage
| | | +---DistPanel
| | | +---GroupCreateModal
| | | +---GroupEditModal
| | | +---GroupEmotionPanel
| | | +---GroupPanel
| | | +---GroupSignUpComment
| | | \---MyPageEditModal
| | \---User
| | +---UserLoginErrorModal
| | +---UserLoginForm
| | \---UserSignupForm
| +---models
| | +---common
| | +---diary
| | +---diaryCreate
| | +---garden
| | +---Group
| | +---guestBook
| | +---map
| | +---user
| | \---weather
| +---pages
| | +---Diary
| | +---DiaryCeate
| | +---DiaryDetail
| | +---DiaryMusicSelect
| | +---DiarySelect
| | +---Garden
| | +---GardenEdit
| | +---GardenList
| | +---GardenOther
| | +---GardenTheme
| | +---GroupList
| | +---GroupSignUpList
| | +---GuestBook
| | +---GuestBookCreate
| | +---Info
| | +---Loading
| | +---Login
| | +---Main
| | +---Map
| | +---MyPage
| | +---NotFound
| | +---OauthRedirect
| | +---Setting
| | | +---ConditionsOfService
| | | +---FindPassword
| | | \---Intro
| | +---Signup
| | \---SignupMusicSelect
| +---redux
| | +---modules
| | | +---diary
| | | +---diaryCreate
| | | +---garden
| | | +---group
| | | +---guestBook
| | | +---music
| | | +---user
| | | \---weather
| | \---utils
| \---utils
\---flory-app
\---assets
Back-end
C:.
+---.gradle
| +---7.6.1
| | +---checksums
| | +---dependencies-accessors
| | +---executionHistory
| | +---fileChanges
| | +---fileHashes
| | \---vcsMetadata
| +---buildOutputCleanup
| \---vcs-1
+---build
| +---classes
| | \---java
| | +---main
| | | \---com
| | | \---exmaple
| | | \---flory
| | | +---config
| | | +---controller
| | | +---dto
| | | | +---comment
| | | | +---diary
| | | | +---emotion
| | | | +---flower
| | | | +---garden
| | | | +---guest
| | | | +---member
| | | | +---music
| | | | +---oauth
| | | | \---team
| | | +---entity
| | | +---exception
| | | | \---error
| | | +---handler
| | | +---jwt
| | | +---repository
| | | +---response
| | | +---service
| | | \---util
| | \---test
| | \---com
| | \---exmaple
| | \---flory
| | +---config
| | +---controller
| | +---repository
| | \---service
| +---generated
| | +---'querydsl'
| | | \---com
| | | \---exmaple
| | | \---flory
| | | \---entity
| | \---sources
| | +---annotationProcessor
| | | \---java
| | | +---main
| | | \---test
| | \---headers
| | \---java
| | +---main
| | \---test
| +---jacoco
| +---libs
| +---reports
| | +---jacoco
| | | \---test
| | | \---html
| | | +---com.exmaple.flory
| | | +---com.exmaple.flory.config
| | | +---com.exmaple.flory.controller
| | | +---com.exmaple.flory.dto.comment
| | | +---com.exmaple.flory.dto.diary
| | | +---com.exmaple.flory.dto.emotion
| | | +---com.exmaple.flory.dto.flower
| | | +---com.exmaple.flory.dto.garden
| | | +---com.exmaple.flory.dto.guest
| | | +---com.exmaple.flory.dto.member
| | | +---com.exmaple.flory.dto.music
| | | +---com.exmaple.flory.dto.oauth
| | | +---com.exmaple.flory.dto.team
| | | +---com.exmaple.flory.entity
| | | +---com.exmaple.flory.exception
| | | +---com.exmaple.flory.exception.error
| | | +---com.exmaple.flory.handler
| | | +---com.exmaple.flory.jwt
| | | +---com.exmaple.flory.response
| | | +---com.exmaple.flory.service
| | | +---com.exmaple.flory.util
| | | \---jacoco-resources
| | \---tests
| | \---test
| | +---classes
| | +---css
| | +---js
| | \---packages
| +---resources
| | +---main
| | \---test
| | \---img
| +---test-results
| | \---test
| | \---binary
| \---tmp
| +---bootJar
| +---compileJava
| | \---compileTransaction
| | +---annotation-output
| | +---compile-output
| | | \---com
| | | \---exmaple
| | | \---flory
| | | +---config
| | | +---controller
| | | +---dto
| | | | +---comment
| | | | +---diary
| | | | +---emotion
| | | | +---flower
| | | | +---garden
| | | | +---guest
| | | | +---member
| | | | +---music
| | | | +---oauth
| | | | \---team
| | | +---entity
| | | +---exception
| | | | \---error
| | | +---handler
| | | +---jwt
| | | +---repository
| | | +---response
| | | \---service
| | +---header-output
| | \---stash-dir
| +---compileQuerydsl
| +---compileTestJava
| | \---compileTransaction
| | +---annotation-output
| | +---compile-output
| | | \---com
| | | \---exmaple
| | | \---flory
| | | +---config
| | | +---controller
| | | +---repository
| | | \---service
| | +---header-output
| | \---stash-dir
| +---expandedArchives
| | \---org.jacoco.agent-0.8.7.jar_3a83c50b4a016f281c4e9f3500d16b55
| | +---META-INF
| | | \---maven
| | | \---org.jacoco
| | | \---org.jacoco.agent
| | \---org
| | \---jacoco
| | \---agent
| +---jacocoTestCoverageVerification
| +---jar
| \---test
+---gradle
| \---wrapper
\---src
+---main
| +---java
| | \---com
| | \---exmaple
| | \---flory
| | +---config
| | +---controller
| | +---dto
| | | +---comment
| | | +---diary
| | | +---emotion
| | | +---flower
| | | +---garden
| | | +---guest
| | | +---member
| | | +---music
| | | +---oauth
| | | \---team
| | +---entity
| | +---exception
| | | \---error
| | +---handler
| | +---jwt
| | +---repository
| | +---response
| | +---service
| | \---util
| \---resources
\---test
+---java
| \---com
| \---exmaple
| \---flory
| +---config
| +---controller
| +---handler
| +---repository
| \---service
\---resources
\---img
-
음악 추천 알고리즘은 다음과 같이 이루어집니다.
-
특정 감정에 대해 과거 유저데이터가 있다면 과거 데이터 활용합니다.
- 음악데이터는 각 음악마다 태그데이터를 가지고 있습니다.
- 과거 음악 데이터들을 태그기반으로 벡터화 시키고 모두 더합니다.
- 2에서 만든 벡터를 ''유저-태그 매트릭스''라고 합니다.
- 각 음악들은 태그를 가지고있기에 이것을 ''음악-태그 매트릭스''라고 합니다.
- 유저-태그 매트릭스와 음악-태크 매트릭스를 각각 numpy의 svd 알고리즘을 활용하여 행렬분해합니다.
- 5를 거치면 유저-잠재요인 매트릭스와 음악-잠재요인 매트릭스를 구할 수 있습니다.
- 유저-잠재요인 매트릭스와 음악 잠재요인 매트릭스의 전치행렬을 내적하면 (1,음악개수)의 행렬 나옵니다.
- 7에서 구한 리스트에서 가장 높은 N개의 음악을 추천합니다(과거 유저가 들은 음악과 특저 음악의 상관관계를 의미합니다)
-
특정 감정에 대해 과거 유저데이터가 없다면 현재 유저의 유사한 유저의 데이터 활용합니다.
- 회원가입시 음악 취향을 받아 다중선택 가능하도록 합니다.
- 선택한것은 1, 선택하지 않은 것은 0으로 바꿔 벡터로 바꾼뒤 코사인 유사도로 유사한 유저 찾습니다.
- 유사한 유저가 특정감정일 때 어떤 노래를 들었는지 확인해서 찾은 노래와 유사한 노래를 추천합니다.
- 유사한 노래는 TF-IDF방식을 활용합니다.
- 음악을 문서, 태그를 단어라고 생각하면 음악 태그기반의 유사한 음악을 찾는문제는 단어기반의 유사한 문서를 찾는 문제로 바뀝니다.
- 하나의 단어가 단일문서에서 여러번 등장하면 TF값은 증가하고, 여러문서에서 등장하면 IDF가 감소합니다.
- 이런식으로 구한 TF와 IDF를 곱해 가중치를 구하면 하나의 문서에는 여러 TF-IDF값이 들어갑니다.
- 이것을 벡터화하고 코사인유사도를 이용하면 비슷한 노래를 찾을 수 있습니다.
-
위 2가지 모두 해당되지 않으면 유저들이 가장 많이 선택한 음악이 추천됩니다.
- 유저들이 가장 많이 들었던 노래 5가지를 추천합니다.
- 유저들이 가장 많이 들었던 노래 5가지를 추천합니다.
-
-
BERT
- BERT : Bidirectional Encoder Representations for Transformers
- 자연어 처리를 위한 모델로, 기존 일방향 Decoder 방식과는 달리 양방향으로 문장을 분석합니다.
- 일방향의 Decoder는 새로운 문장에 적합한 반면, BERT는 양방향으로 분석에 초점이 맞춰져 있습니다.
-
koBERT
- 기존 BERT 모델에 한국어 학습 신경망을 추가한 koBERT 모델을 사용합니다.
- koBERT를 채택한 이유 : 한국어 자연어 처리 모델 중 가장 높은 정확도를 보이고, 감정이나 긍/부정을 분석하는 프로젝트에서 널리 활용됩니다.
-
Pre Training : BERT는 수백만개의 텍스트 데이터를 사전 학습했습니다.
- 문장을 Attention 행렬(문장에서의 단어 순서, 문장 시작과 끝 구별, 상황별 중요한 단어 및 문맥 이해, 오타 처리를 수치로 나타낸 행렬)로 변경합니다. 문장 중 단어 하나를 가린 후 그 단어를 예측하는 방식으로 학습합니다.
-
Fine Tuning : 이후 이 모델에 목적에 맞는 신경망을 추가합니다.
- 문장 + 감정 벡터 (16만개) 데이터를 학습했습니다.
- 기쁨 0, 안정 1, ….
- 모델이 완성된 후, 문장을 입력하면 각 감정과 얼마나 일치하는지 정도를 나타내는 비율이 도출됩니다.
-
모델 개선 관련
- kFold를 이용하여 교차 검증(cross-validation)으로 train 데이터로의 과적합을 방지했습니다.
- 5회에서 10회로 변경했습니다.
- 최적의 epoch을 찾고자 노력했습니다.
- 학습 데이터를 순차적으로 추가했습니다.
- 프로젝트의 url로 접근하면 해당 화면으로 접속하게 됩니다.
- PC로 접속하는 경우 로고와 Google Play Store에 접근할 수 있는 QR을 데스크탑 뷰로 볼 수 있고, 모바일 어플리케이션으로 접속하면 모바일 뷰로 화면을 볼 수 있습니다.
- 시작하기 버튼을 누르면 본격적으로 서비스 이용이 가능합니다.
- 가입된 계정이나, 구글 혹은 카카오 계정을 통해 로그인이 가능합니다.
- 회원가입 시 닉네임, 이메일, 비밀번호를 필수로 입력받습니다.
- 이메일의 경우 ID로 활용되기 때문에 반드시 중복검사를 시행해야 합니다.
- 필수 입력 정보들을 모두 입력한 후에 선호하는 음악 장르를 선택합니다.
- 회원 가입을 완료하고, 생성한 계정으로 로그인을 한 후에 서비스를 이용할 수 있습니다.
- 회원가입을 완료하면 전체적인 서비스에 대한 이용 안내 페이지로 이동합니다.
- 서비스의 기본적인 소개와 각 페이지 별로 구현된 기능, 이를 사용하는 방법에 대한 설명이 작성되어 있습니다.
- 스크롤을 통해 이용 안내에 관한 내용을 확인할 수 있고, 우측 하단 버튼을 누르면 최상단으로 이동할 수 있습니다.
- 이용 안내에 관한 내용을 모두 숙지하였다면 좌측 상단 버튼을 클릭하거나 최하단의 시작하기 버튼을 클릭하여 로그인 페이지로 이동합니다.
- 정원을 생성할 때 총 3가지 테마(공원, 캠프, 해변) 중 하나를 선택할 수 있습니다.
- 정원의 테마를 선택하면 정원 페이지로 이동하며, 정원은 360도 회전이 가능하거나 확대하여 감상할 수 있습니다.
- 네비게이션 바의 1번째 아이콘을 클릭하면 일기 내용 작성 페이지로 이동합니다.
- 일기 작성 페이지
- 상단에 있는 텍스트 박스에 일기의 내용을 작성할 수 있습니다.
- 이미지 버튼을 클릭하여 사진 첨부 기능을 사용하여 사진과 일기의 내용을 함께 업로드 할 수 있습니다.
- 전체공개, 그룹공개, 나만 보기 중 하나를 선택하여 공개 범위를 설정할 수 있습니다.
- 일기의 작성 위치나 일기와 관련된 장소를 공유할 수 있습니다.
- 지도를 이동하여 직접 지정할 수도 있고 검색을 통해 해당 위치로 이동하여 위치정보를 저장할 수 있습니다.
- 꽃 선택 페이지
- 작성완료 버튼을 누르면 입력된 내용을 기반으로 인공지능을 통한 감정 분석이 진행되고, 감정 그래프를 통해 결과를 확인할 수 있습니다.
- 분석된 감정과 유사한 꽃말을 가지고 있는 꽃들이 표시되고, 사용자가 정원에 피어내고 싶은 꽃을 선택하면 다음으로 이동합니다.
- 배경음악 선택 페이지
- 추천 알고리즘을 통해 분석된 감정과 연관된 5개의 음악 추천 리스트가 제공되고, 사용자가 취향에 맞는 음악을 선택합니다.
- 정원 편집 페이지
- 선택한 꽃을 클릭하면 원하는 위치로 이동시킬 수 있습니다. 꽃을 이동시켜 정원을 꾸민 후 완료 버튼을 누르면 자신의 정원에 감정이 담긴 꽃이 피어나게 됩니다.
- 정원에서 해당 꽃을 클릭하면 일기의 상세 내용을 볼 수 있습니다.
- 정원 페이지에서는 사용자의 이번 달 정원과 피어난 꽃들(일기들)을 확인할 수 있습니다.
- 우측 상단의 토글 버튼을 클릭하면 정원 리스트, 배경음악 음소거, 화면 캡쳐 및 저장 버튼이 표시됩니다.
- 정원 리스트
- 정원 리스트 버튼을 누르면 이전 정원 목록들과 달력을 확인할 수 있습니다.
- 보고 싶은 정원을 클릭하면 해당 정원으로 이동할 수 있고, 하단의 달력을 클릭하면 해당 기간의 일기 리스트 페이지로 이동합니다.
- 음소거 버튼을 클릭하면 해당 정원의 배경음악을 음소거할 수 있습니다.
- 화면 캡처버튼을 클릭하고 저장 버튼을 누르면 정원의 이미지를 캡처하여 저장할 수 있습니다. (웹, 모바일 모두 가능)
- 정원 리스트
- 네비게이션 바의 2번째 아이콘을 클릭하면 현재날짜 기준으로 이번 달 일기 목록을 조회할 수 있습니다.
- 상단에는 오늘 날씨와 현재 시간을 확인할 수 있고, 날짜와 시간에 따라 배경이 변화합니다.
- 좌측 상단의 DatePicker를 클릭하면 원하는 년도와 월을 선택할 수 있고, 해당 날짜의 일기 목록을 조회할 수 있습니다.
- 일기를 클릭하면 작성한 일기의 상세내용을 확인할 수 있습니다.
- 네비게이션 바의 5번째 아이콘을 클릭하면 마이페이지로 이동합니다.
- 나의 감정 분포 탭에서는 사용자의 정보와 감정 리포트를 확인할 수 있습니다.
- 상단의 프로필 편집 버튼을 클릭하여 프로필 이미지와 닉네임을 변경할 수 있습니다.
- 나의 감정 분포 메뉴에서 이번 달 작성했던 일기 개수와 실시간 누적 감정 분포로 감정 통계 그래프를 확인할 수 있습니다.
- 워드 클라우드를 통해 이번 달에 작성했던 일기들의 키워드를 확인할 수 있고, 지난주 대비 감정 분포가 어떻게 변화했는지 확인할 수 있습니다.
- 마이페이지에서 우측 상단에 버튼을 눌러 환경설정 페이지로 이동할 수 있습니다.
- 계정 탭에서는 비밀번호 변경, 로그아웃, 회원탈퇴와 같은 계정 설정 기능을 이용할 수 있습니다.
- 정보 탭에서는 서비스 이용 약관을 확인할 수 있고, 이용 문의를 통해 이메일로 문의사항을 보낼 수 있습니다.
- 마이페이지에서 그룹 목록 보기 탭을 눌러 그룹 정보를 확인할 수 있습니다.
- 그룹 생성 버튼을 클릭하여 새로운 그룹을 만들 수 있고, 그룹 둘러보기를 통해 생성된 그룹들을 조회하고 가입 신청을 할 수 있습니다.
- 네비게이션 바의 4번째 아이콘을 클릭하면 커뮤니티 페이지로 이동합니다.
- 내 주변 보기
- 내 주변보기 탭을 클릭하면 사용자의 현 위치를 기준으로 주변에 피어난 꽃들이 표시됩니다. 지도의 범위 설정 및 위치 이동을 통해 원하는 위치에 피어난 꽃들을 확인할 수 있습니다.
- 지도에 표시된 꽃들을 기준으로 일기 목록이 표시됩니다.
- 지도의 위치를 이동하면 이동한 위치 기준으로 일기 목록을 다시 조회합니다.
- 모든 감정 보기
- 모든 감정 보기 탭을 클릭하면 모든 유저의 전체공개 일기 목록을 조회할 수 있습니다.
- 그룹 감정 보기
- 그룹 감정 보기 탭을 클릭하면 사용자가 속한 그룹원들의 전체공개, 그룹공개 일기 목록을 조회할 수 있습니다.
- 필터링 버튼을 통해 보고싶은 그룹 구성원들의 일기 목록을 조회할 수 있습니다.
- 일기 상세 내용 페이지에서는 해당 일기의 상세 내용을 확인할 수 있고, 댓글을 남길 수 있습니다.
- 일기 작성자의 닉네임을 클릭하면 일기 작성자의 정원으로 이동할 수 있습니다.
- 댓글 작성자의 프로필 이미지나 닉네임을 클릭하면 댓글 작성자의 정원으로 이동할 수 있습니다.
- 정원 페이지에서 우체통을 클릭하면 방명록을 확인할 수 있습니다.
- 다른 사용자의 정원으로 이동하여 우체통을 클릭하면 해당 유저의 정원에 방명록을 남길 수 있습니다.
- 우측 상단 버튼을 클릭하여 방명록을 작성할 수 있고, 방명록의 배경 색을 선택할 수 있습니다.
- 만약 내가 이전에 작성했던 방명록을 지우고 싶다면 일기의 우측 상단에 메뉴를 눌러 삭제할 수 있습니다.
🎥 UCC 보러가기
5주차
구분 | 링크 |
---|---|
포팅 매뉴얼 | 포팅 매뉴얼 바로가기 |
시연 시나리오 | 시연 시나리오 바로가기 |
DB 덤프 데이터 | DB 덤프 데이터 |