๐๏ธํ๋ก์ ํธ ์๊ฐ
ํ๊ตญ์ ๋ฐฉ๋ฌธํ๋ ์ธ๊ตญ์ธ์ ์ํ ์์์ ๋ฉ๋ดํ ๋ฒ์ญ์ ์ ๊ณตํ๊ณ , ์ฌ์ฉ์ ์ทจํฅ ๋ฐ ์๋ฌ์ง ์ ๋ณด๋ฅผ ์ด์ฉํด์ ์์์ ์ถ์ฒํด์ฃผ๋ ์ ํ๋ฆฌ์ผ์ด์
๐ ํ๋ก์ ํธ ๋ฌธ์
๐๏ธ ์์คํ
์ค๊ณ
โ
UseCase Diagram

โ
Sequence Diagram

โ
Architecture

๊ด๋ จ ๋ฌธ์
๐๏ธ ๊ฐ๋ฐ ๊ณผ์ ์ค๋ช
AI
Task
๋ชจ๋ธ์ ํ์ํ ๊ธฐ๋ฅ์ ํฌ๊ฒ 3๊ฐ์ง๋ก ๋๋ ์ ์์ต๋๋ค.
- ๋ฉ๋ดํ ํ
์คํธ ์ธ์ ๋ฐ ์์ ๋ฉ๋ด ์ถ์ถ
- ์ฌ์ฉ์ ์๋ฌ์ง ๋ฐ ์ทจํฅ ๊ธฐ๋ฐ ์์ ์ถ์ฒ
- ๋ค๊ตญ์ด ๋ฉ๋ด ๋ฒ์ญ
1. ๋ฉ๋ดํ ํ
์คํธ ์ธ์ ๋ฐ ์์ ๋ฉ๋ด ์ถ์ถ
์์ธํ ๋ด์ฉ
- ์ด๊ธฐ์๋ [AIHub ๋ฉ๋ด ์ด๋ฏธ์ง ๋ฐ์ดํฐ์
](https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=&topMenu=&aihubDataSe=ty&dataSetSn=71553)์ ํ์ฉํ์ฌ `TrOCR` ๋ชจ๋ธ๋ก ํ์ต์ ์งํํ์ต๋๋ค. [TrOCR ๋
ผ๋ฌธ](https://ojs.aaai.org/index.php/AAAI/article/view/26538)
- ๊ทธ๋ฌ๋ TrOCR๋ ์ผ๋ฐ์ ์ผ๋ก 1์ค ์ ๋์ ๋จ์ ๋ฌธ์ฅ ์ธ์์ ์ต์ ํ๋์ด ์์ด, ์ค์ ๋ฉ๋ดํ์ฒ๋ผ **๋ค๋จ ๊ตฌ์ฑ** ๋ฐ **๋น์ ํ ๋ฐฐ์น**๋ฅผ ๊ฐ์ง ์ด๋ฏธ์ง์ ๋ํด ํ์ต loss๊ฐ ์ค์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
- ์ดํ `NAVER CRAFT` ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๋ฉ๋ดํ์์ ํ
์คํธ ์์ญ์ ์ฌ์ ์ ๊ฒ์ถํ๊ณ ์ด๋ฅผ TrOCR์ ์
๋ ฅ์ผ๋ก ํ์ฉํด๋ณด์์ง๋ง, **์ถ๋ก ์๊ฐ์ด ์ด๋ฏธ์ง๋น ์ฝ 5๋ถ ์ด์** ์์๋์ด ์ค์ฉ์ฑ์ด ๋จ์ด์ก์ต๋๋ค.
- ์ต์ข
์ ์ผ๋ก `PaddleOCR`๋ฅผ ๋์
ํ์์ผ๋ฉฐ, ํด๋น ํ๋ ์์ํฌ๋ ๋น ๋ฅด๊ณ ์์ ์ ์ธ ํ
์คํธ ์์ญ ๊ฒ์ถ ๋ฐ ์ธ์์ ๋์์ ์ ๊ณตํ์ฌ ์ค์ ์๋น์ค ์์ค์ ์ธ์ ์ ํ๋์ ์๋๋ฅผ ํ๋ณดํ ์ ์์์ต๋๋ค.
- **LLM**์ ์ด์ฉํ์ฌ ์ธ์๋ ํ
์คํธ์์ **๋ฉ๋ด๋ช
๋ง ์ถ์ถ**ํ๋ ๋ฐฉ์๋ ์๋ํ์ง๋ง, **๋น๊ฒฐ์ ์ฑ**์ผ๋ก ์ธํด ์ถ์ถ ๊ฒฐ๊ณผ๊ฐ ์ผ๊ด๋์ง ์๊ณ ์ ํ๋๊ฐ ๋ฎ์ ์ค์ ์ฌ์ฉ์๋ ์ด๋ ค์์ด ์์์ต๋๋ค.
- ๋ฉ๋ด๋ช
์ถ์ถ์ LLM ๋์ **2๋ฒ์์ ์ฌ์ฉํ KADx ์์/์๋ฌ์ง ๋ฐ์ดํฐ์
์ ๋ฉ๋ด๋ช
๋ฆฌ์คํธ**๋ฅผ ํ์ฉํ์ฌ ์ถ์ถ๋ ํ
์คํธ๊ฐ ๋ฐ์ดํฐ์
์ ์๋ ๊ฒฝ์ฐ ๋ฉ๋ด๋ก ์ธ์ํ๋๋ก **Rule-based ๋ฐฉ์**์ผ๋ก ์ฒ๋ฆฌํ์์ต๋๋ค.
2. ์ฌ์ฉ์ ์๋ฌ์ง ๋ฐ ์ทจํฅ ๊ธฐ๋ฐ ์์ ์ถ์ฒ
์์ธํ ๋ด์ฉ
- ์ฌ์ฉ์์ ์๋ฌ์ง ์ ๋ณด ๋ฐ ์์ ์ทจํฅ์ ๊ณ ๋ คํ์ฌ, ๋ฉ๋ดํ์์ ์ธ์๋ ์์ ์ค **์์ ํ๊ณ ์ ํธ ๊ฐ๋ฅํ ๋ฉ๋ด**๋ฅผ ์ถ์ฒํฉ๋๋ค.
- ์ถ์ฒ ์๊ณ ๋ฆฌ์ฆ ๊ฐ๋ฐ์ ์ํด [KADx ์๋ฌ์ง/์์์ ๋ณด ํฌํจ ์์ ๋ฐ์ดํฐ](https://kadx.co.kr/opmk/frn/pmumkproductDetail/PMU_79c6f1a4-56dd-492e-ad67-c5acba0304d2/5)๋ฅผ ์์ง ๋ฐ ์ ์ฒ๋ฆฌํ์์ต๋๋ค.
- ๊ฐ ์์์ ๋ฉ๋ด๋ช
๊ณผ ์ฌ๋ฃ ์ ๋ณด๋ฅผ **Sentence-BERT**๋ฅผ ์ด์ฉํด ์๋ฒ ๋ฉํ ํ, ์ฌ์ฉ์์ ์ ํธ ์๋ฒ ๋ฉ ๋ฒกํฐ์์ **์ฝ์ฌ์ธ ์ ์ฌ๋**๋ฅผ ๊ณ์ฐํ์ฌ ๊ด๋ จ์ฑ ๋์ ๋ฉ๋ด๋ฅผ ์ถ์ฒํฉ๋๋ค.
- **Sentence-BERT**(**SBERT**)๋ **๋ฌธ์ฅ ์๋ฒ ๋ฉ**์ ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ฅ๋ฌ๋ ๋ชจ๋ธ๋ก, ๊ธฐ์กด์ **BERT**(Bidirectional Encoder Representations from Transformers)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋, ๋ฌธ์ฅ ๊ฐ์ ์๋ฏธ์ ์ ์ฌ๋ ๊ณ์ฐ์ ๋ ํจ์จ์ ์ผ๋ก ์ํํ ์ ์๋๋ก ํน๋ณํ ์ค๊ณ๋ ๋ชจ๋ธ์
๋๋ค.
- ์๋ฌ์ง ์ ๋ฐ ์ฑ๋ถ์ด ํฌํจ๋ ๋ฉ๋ด๋ ํํฐ๋งํ์ฌ ์ฌ์ฉ์์๊ฒ ์์ ํ ์ ํ์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
3. ๋ค๊ตญ์ด ๋ฉ๋ด ๋ฒ์ญ
์์ธํ ๋ด์ฉ
- 1๋ฒ์์ ์ฌ์ฉํ AIHub ๋ฐ์ดํฐ์
์๋ 4๊ฐ ๊ตญ์ด(ํ๊ตญ์ด, ์์ด, ์ผ๋ณธ์ด, ์ค๊ตญ์ด) ๋ณ๋ ฌ ๋ฌธ์ฅ์ด ์ผ๋ถ ์กด์ฌํ์ง๋ง, ๋ฒ์ญ ํ์ง์ด ๊ณ ๋ฅด์ง ๋ชปํด ์์ฒด ๋ฒ์ญ ๋ชจ๋ธ ํ์ต์๋ ์ ํฉํ์ง ์์์ต๋๋ค.
- ๋ํ, ๊ณต๊ฐ๋ ๊ณ ํ์ง ์์ ๋ฉ๋ด ๋ฒ์ญ ๋ฐ์ดํฐ์
์ด ์์ด ๋์์ผ๋ก **Google Translate API**๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๊ตญ์ด ๋ฒ์ญ ๊ธฐ๋ฅ์ ๊ตฌํํ์ต๋๋ค.
- ์ด ๊ธฐ๋ฅ์ ํตํด ์ธ๊ตญ์ธ ์ฌ์ฉ์๋ ์๊ตญ์ด๋ก ์์ ๋ฉ๋ด๋ฅผ ์ดํดํ ์ ์์ผ๋ฉฐ, ์์๋ช
๊ณผ ๊ฐ๋จํ ์ค๋ช
๋ฒ์ญ์ ํจ๊ป ์ ๊ณตํฉ๋๋ค.
Front
์ํคํ
์ณ ๊ทธ๋ํ

1. DIContainer๋ฅผ ์ฌ์ฉํ์ฌ ์์กด์ฑ ์ฃผ์
์ ๊ตฌํํ๊ณ ์์ผ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ์ฃผ์ ๊ตฌ์ฑ ์์์ ์ ๊ทผํ ์ ์๊ฒ ํฉ๋๋ค
์์ธํ ๋ด์ฉ
- NavigationRouter: ํน์ ํ๋ก์ฐ ๋ด์์์ ํ๋ฉด ์ด๋ ๊ด๋ฆฌ
- WindowRouter: ์ฃผ์ ์ ํ๋ฆฌ์ผ์ด์
ํ๋ฉด/ํ๋ก์ฐ ๊ฐ์ ์ ํ ๊ด๋ฆฌ
```Swift
import Foundation
typealias NavigationRoutableType = NavigationRoutable & ObservableObjectSettable
typealias WindowRoutableType = WindowRoutable & ObservableObjectSettable
final class DIContainer: ObservableObject {
var navigationRouter: NavigationRoutableType
var windowRouter: WindowRoutableType
private init(
navigationRouter: NavigationRoutableType = NavigationRouter(),
windowRouter: WindowRoutableType = WindowRouter()
) {
self.navigationRouter = navigationRouter
self.windowRouter = windowRouter
navigationRouter.setObjectWillChange(objectWillChange)
windowRouter.setObjectWillChange(objectWillChange)
}
}
extension DIContainer {
static let `default` = DIContainer()
static let stub = DIContainer()
}
```
2. ๋ค๋น๊ฒ์ด์
์์คํ
์์ธํ ๋ด์ฉ
์ฑ์ ๋ค์๊ณผ ๊ฐ์ ๋ง์ถคํ ๋ค๋น๊ฒ์ด์
์ํคํ
์ฒ๋ฅผ ๊ตฌํํ๊ณ ์์ต๋๋ค:
**1. ์๋์ฐ ๋ผ์ฐํ
- ์ฃผ์ ์ ํ๋ฆฌ์ผ์ด์
์ํ ์ฒ๋ฆฌ:**
.splash - ์ฑ ์ด๊ธฐ ๋ก๋ฉ ํ๋ฉด
.onboarding - ์ฌ์ฉ์ ๋ฑ๋ก ๋จ๊ณ
.home - ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
์ธํฐํ์ด์ค
```Swift
import Foundation
import Combine
protocol WindowRoutable {
var destination: WindowDestination { get }
func `switch`(to destination: WindowDestination)
}
class WindowRouter: WindowRoutable, ObservableObjectSettable {
var objectWillChange: ObservableObjectPublisher?
var destination: WindowDestination = .splash {
didSet {
objectWillChange?.send()
}
}
func `switch`(to destination: WindowDestination) {
self.destination = destination
}
}
```
**2. ๋ด๋น๊ฒ์ด์
๋ผ์ฐํ
- ๊ฐ ํ๋ก์ฐ ๋ด์์์ ํ๋ฉด ์ด๋ ์ฒ๋ฆฌ:**
```Swift
import Foundation
import Combine
protocol NavigationRoutable {
var destinations: [NavigationDestination] { get set }
func push(to view: NavigationDestination)
func pop()
func popToRootView()
}
class NavigationRouter: NavigationRoutable, ObservableObjectSettable {
var objectWillChange: ObservableObjectPublisher?
var destinations: [NavigationDestination] = [] {
didSet {
objectWillChange?.send()
}
}
func push(to view: NavigationDestination) {
destinations.append(view)
}
func pop() {
_ = destinations.popLast()
}
func popToRootView() {
destinations = []
}
}
```
**3. ์คํ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ผ๋ก push/pop ์ฐ์ฐ ์ฌ์ฉ**
- ๋ด๋น๊ฒ์ด์
๋ชฉ์ ์ง๋ NavigationDestination ์ด๊ฑฐํ์ ์ ์
- NavigationRoutingView๊ฐ ๋ชฉ์ ์ง๋ฅผ ๊ตฌ์ฒด์ ์ธ ๋ทฐ ์ธ์คํด์ค๋ก ๋ณํ
3. MVVM ํจํด
์์ธํ ๋ด์ฉ
๊ฐ ํ๋ฉด์ MVVM(Model-View-ViewModel) ํจํด์ ๋ฐ๋ฆ
๋๋ค:
- ๋ทฐ: UI๋ฅผ ํ์ํ๊ณ ์ฌ์ฉ์ ์
๋ ฅ์ ์บก์ฒํ๋ SwiftUI ๋ทฐ
- ๋ทฐ๋ชจ๋ธ: ์ํ ๊ด๋ฆฌ, ๋น์ฆ๋์ค ๋ก์ง, ์๋น์ค์์ ํต์ ๋ด๋น
- ๋ชจ๋ธ: ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๋ํ๋ด๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ
4. ์ฃผ์ ํ๋ก์ฐ & ํ ํญ ๊ตฌ์กฐ
์์ธํ ๋ด์ฉ
### ์ธ ๊ฐ์ ํญ์ผ๋ก ๊ตฌ์ฑ๋ ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
์ธํฐํ์ด์ค:
- **ArchivingView** - ์ฌ์ฉ์ ์ ํธ ์์์ ๊ธฐ๋ฐํ ๋ง์ง ์ถ์ฒ ๋ฆฌ์คํธ ์ ๊ณต
- **MenuImagePickerView** - ๋ฉ์ธ ๋ฉ๋ด ๋ถ์ ๊ธฐ๋ฅ
- **MyPageView** - ์ฌ์ฉ์ ํ๋กํ ๋ฐ ์ค์
### ์จ๋ณด๋ฉ ํ๋ก์ฐ
๋ค๋จ๊ณ ๋ฑ๋ก ํ๋ก์ธ์ค:
- SelectNationalityView - ๊ตญ๊ฐ ์ ํ
- SelectAllergyView - ์๋ ๋ฅด๊ธฐ ๋ฐ ๋งค์ด ์์ ์ ํธ๋ ์ง์
- SelectKoreanFoodView - ์ ํธํ๋ ํ๊ตญ ์์ ์ ํ
- EnterIdPasswordView - ๊ณ์ ์ธ์ฆ ์ ๋ณด ์์ฑ
### ๋ฉ๋ด ๋ถ์ ํ๋ก์ฐ
์ฌ์ฉ์๊ฐ ๋ฉ๋ด ํญ๋ชฉ์ ๋ถ์ํ ์ ์๋ ํต์ฌ ๊ธฐ๋ฅ:
- MenuImagePickerView - ๋ฉ๋ด ์ด๋ฏธ์ง ์
๋ก๋
- MenuAnalysisLoadingView - ๋ฉ๋ด ๋ถ์ ์ค ๋ก๋ฉ ํ๋ฉด
- MenuAnalysisResultView - ์ฌ์ฉ์ ์ ํธ๋ ๊ธฐ๋ฐ ์ถ์ฒ์ ํฌํจํ ๋ถ์ ๊ฒฐ๊ณผ ํ์
Back
1. MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค
์์ธํ ๋ด์ฉ
database ๋ช
: menu_db
DB ๊ด๋ฆฌ์ ๋ช
: admin
- users table
- id : ์ฌ์ฉ์ id
- nationality : ์ฌ์ฉ์ ๊ตญ์
- password : ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ
- username : ์ฌ์ฉ์ ์ด๋ฆ
- user_allergies table
- user_id : ์ฌ์ฉ์ id
- allergy : ์ฌ์ฉ์๊ฐ ๊ฐ์ง๊ณ ์๋ ์๋ฌ์ง
- user_favorite_foods
- user_id : ์ฌ์ฉ์ id
- food : ์ฌ์ฉ์๊ฐ ์ข์ํ๋ ํ๊ตญ ์์
- restaurants (ํ์ , ์ด๋ฏธ์ง ์ถ๊ฐ ์์ )
- id : ์๋น id
- address : ์๋น ์ฃผ์
- food_name : ์๋น ๋ํ๋ฉ๋ด ์ด๋ฆ
- restaurant_name : ์๋น ์ด๋ฆ
2. API ๋ฌธ์
์์ธํ ๋ด์ฉ
### POST /api/auth/signup
```jsx
status: 200
respose: {"success": true, "message": "ํ์๊ฐ์
์ฑ๊ณต", "data": {}}
```
### POST /api/auth/login
```jsx
status: 200
respose: { "success": true, "message": "๋ก๊ทธ์ธ ์ฑ๊ณต", "data": { "token": "string", "userId": โstringโ, "username": "string"}}
```
### POST /api/auth/logout
```jsx
status: 200
headers: {โAuthorizationโ: โBearer โ}
respose: {"success": true,"message": "๋ก๊ทธ์์ ์ฑ๊ณต: ํด๋ผ์ด์ธํธ๋ ํ ํฐ ์ญ์ ์๋ง","data": null}
```
### GET /api/user/profile
```jsx
status: 200
headers: {โAuthorizationโ: โBearer โ}
respose: {"success": true,"message": "์ฌ์ฉ์ ํ๋กํ ๋ฐํ ์ฑ๊ณต", "data": { "username": "string", "nationality":โstring"}}
```
### GET /api/restaurant/recommend
```jsx
status: 200
headers: {โAuthorizationโ: โBearer โ}
respose: {"success": true,"message": "์ฌ์ฉ์ ํ๋กํ ๋ฐํ ์ฑ๊ณต", "data": { "username": "string", "nationality":"string"}}
```
### POST /api/gallery/upload
```jsx
parameters: {โimageโ: โmultipart/form-data, fileโ}
headers: {โAuthorizationโ: โBearer โ}
status: 200
respose: {โsuccessโ: true, โmessageโ: โ์ด๋ฏธ์ง ์
๋ก๋ ์ฑ๊ณตโ, โdataโ: {โurlโ: โ/api/gallery/images/{filename}โ}}
```
### GET /api/gallery/images/{filename}
```jsx
parameters: {โfilenameโ: โstringโ}
headers: {โAuthorizationโ: Bearer โ}
status: 200
respose: ์ด๋ฏธ์ง ํ์ผ ์์ฒด (image/jpeg ๋ฑ)
```
### POST /api/analysis/analyze-image
```jsx
parameters: ์์
headers: {โAuthorizationโ: โBearer โ}
status: 200
respose: {โsuccessโ: true, โmessageโ: โAI ๋ถ์ ์์ฒญ ์ฑ๊ณต ๋ฐ ๊ฒฐ๊ณผ ์บ์ฑ ์๋ฃโ, โdataโ: โokโ}
```
### GET /api/analysis/analyze
```jsx
parameters: ์์
headers: {โAuthorizationโ: โBearer โ}
status: 200
respose: {โsuccessโ: true, โmessageโ: โ๋ถ์ ๊ฒฐ๊ณผ ์กฐํ ์ฑ๊ณตโ}
```
### GET /api/analysis/translate
```jsx
parameters: ์์
headers: {โAuthorizationโ :โBearer โ}
status: 200
respose: {โsuccessโ: true, โmessageโ: โ๋ฒ์ญ ๊ฒฐ๊ณผ ์กฐํ ์ฑ๊ณตโ}
```
</details>
# ๐งฉ ๊ธฐ๋ฅ ์ค๋ช
### โก๏ธ ํ์๊ฐ์
Flow
### 1. ์จ๋ณด๋ฉ ๋ทฐ & ๋ก๊ทธ์ธ ๋ทฐ
์ฑ์ ์ฒ์ ์คํ ์, ์ฑ์ ์ค๋ช
ํ๋ ์จ๋ณด๋ฉ ํ๋ฉด์ด ๋ํ๋๊ณ , start ๋ฒํผ์ ๋๋ฅด๊ฒ ๋๋ฉด ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๊ฒ ๋ฉ๋๋ค!
 |
 |
### โก๏ธ ํ์๊ฐ์
Flow
๋ก๊ทธ์ธ ํ๋ฉด์์ sign up ๋ฒํผ์ ๋๋ฅด๋ฉด ํ์๊ฐ์
์ผ๋ก ์ฐ๊ฒฐ๋๋ค
### 1. ๊ตญ์ & ์๋ฌ์ง ์ ํ ๋ทฐ
ํ์ฌ ๊ตญ์ ์ ๋ฏธ๊ตญ, ์ผ๋ณธ, ์ค๊ตญ์ผ๋ก ์ธ ๋๋ผ๋ฅผ ์ ํํ ์ ์์ผ๋ฉฐ, ์๋ฌ์ง๋ ์ด 25๊ฐ ์ค์์ ์ค๋ณต์ ์ผ๋ก ์ ํํ ์ ์์ต๋๋ค
 |
 |
### 2. ์ ํธํ๋ ์์ ์ ํ & ๊ฐ์ธ์ ๋ณด ์
๋ ฅ ๋ทฐ
๋ฉ๋ดํ ๋ถ์์ ํตํด์ ์ ํธํ๋ ์์ ์ถ์ฒ ๋ฐ ๋ง์ง ์ถ์ฒ ์์นด์ด๋น ๋ทฐ์์ ์ฌ์ฉํ๊ธฐ ์ํ ์ ๋ณด์ธ ์ ํธํ๋ ํ๊ตญ ์์์ ๋ฐ๋๋ค
๋ง์ง๋ง์ผ๋ก๋ username, password๋ฅผ ๋ฐ๊ณ ํ์๊ฐ์
์ ์คํํ๋ค.
 |
 |
### โก๏ธ ๋ฉ๋ด๋ถ์ Flow
### ๋ฉ๋ดํ ์
๋ก๋ & ๋ก๋ฉ ๋ทฐ & ๋ฉ๋ดํ ๋ถ์
๊ฐค๋ฌ๋ฆฌ์์ ๋ฉ๋ดํ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ ํ๊ณ ๋ถ์ํ๋ ๋์ ๋ก๋ฉ๋ทฐ๋ฅผ ๋ณด์ฌ์ค๋ค
๋ฉ๋ดํ ๋ถ์ ํ์ด์ง์์๋ ํด๋น ๋ฉ๋ดํ์์ ์ถ์ฒํ๋ ์์๊ณผ ์๋ฌ์ง์ ๊ด๋ จ๋ ๋ฉ๋ด๋ค์ ํ๋์ ๋ณด๊ธฐ ํธํ๋๋ก ๋ณด์ฌ์ค๋ค
๋ํ ๋ฉ๋ดํ ๋ฒ์ญ ์ด๋ฏธ์ง๋ฅผ ์ ๊ณตํด์ค์ผ๋ก์จ ํ์ธํ ์ ์๋๋ก ํ๋ค
 |
 |
 |
### โก๏ธ ๋ง์ง ์์นด์ด๋น & ๋ง์ดํ์ด์ง Flow
### ๋ง์ดํ์ด์ง & ๋ง์ง ์์นด์ด๋น ๋ทฐ
๋ง์ดํ์ด์ง์์ ํ์์ ๋ณด ํ์ธ, ๋ก๊ทธ์์, ํ์ํํด ๋ฑ์ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์์ผ๋ฉฐ
๋ง์ง ์์นด์ด๋น ๋ทฐ์์๋ ์์ ์ ์ ํธ์์์ ๊ธฐ๋ฐ์ผ๋ก ๋ง์ง ๋ฆฌ์คํธ๋ฅผ ์ถ์ฒํด์ฃผ๊ณ ํด๋น ๋ง์ง์ ๋๋ฅด๋ฉด ์ธํฐ๋ท์ ํตํด์ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋๋ก ์ฐ๊ฒฐํด์ค๋ค.
 |
 |
---
## ์ปดํจํฐ ๊ตฌ์ฑ / ํ์ ์กฐ๊ฑด ์๋ด (Prerequisites)
* iOS >= 16.0
* swift >= 4.2
* MySQL 8.0 (AWS RDS)
* Spring Boot 3.4.4
## ๐จ๊ธฐ์ ์คํ (Technique Used)
### Server(back-end)
</a> |
</a> |
Amazon RDS |
Springboot |
### Front-end
 |
 |
Swift |
SwiftUI |
### AI
</a> |
</a> |
</a> |
</a> |
PyTorch |
Python |
FastAPI |
PaddleOCR |
---
## ๐ฝ์ค์น ์๋ด (Installation Process)
### Swift
#### Xcode ์๋ฎฌ๋ ์ดํฐ๋ก ์คํํ๊ธฐ
```bash
git clone https://github.com/kookmin-sw/capstone-2025-21
cd App/capstone21/capstone21
Xcode๋ก ํ๋ก์ ํธ ํ์ผ ์ด๊ธฐ
์คํํ๊ธฐ
```
### ์๋ฒ ์คํ
- Git clone
```bash
# EC2๋ก ์ ์
$ ssh -i ~/capstone2025-key.pem ubuntu@
# git clone
$ git clone https://github.com/kookmin-sw/capstone-2025-21.git
# ํ๋ก์ ํธ ๋๋ ํ ๋ฆฌ๋ก ์ด๋ ํ, ๋น๋ํ JAR ํ์ผ ์
๋ก๋
```
- Build - ๋ก์ปฌ (intelliJ)์์ ์คํ
```bash
# Gradle ๋น๋
./gradlew bootJar
# ์์ฑ๋ JAR ์์น (์์)
build/libs/allergy-0.0.1-SNAPSHOT.jar
```
- EC2 ์๋ฒ์ JAR ์
๋ก๋ (SCP or FileZilla)
```bash
# 1. scp ์ฌ์ฉ
$ scp -i capstone2025-key.pem allergy-0.0.1-SNAPSHOT.jar ubuntu@:~/
# 2. ํน์ FileZilla์์ ํธ์คํธ์ IP, ์ฌ์ฉ์๋ช
, ํค ํ์ผ PEM ์ค์ ํ ์ ์ํด์ ~/ ๊ฒฝ๋ก์ ์
๋ก๋
```
- ์๋ฒ ์คํ
```bash
# EC2์ ์ ์
$ ssh -i ~/capstone2025-key.pem ubuntu@
# JAR ์คํ (๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ)
$ nohup java -jar allergy-0.0.1-SNAPSHOT.jar &
# (prod profile๋ก ์คํํ ๊ฒฝ์ฐ)
$ nohup java -jar -Dspring.profiles.active=prod.active allergy-0.0.1-SNAPSHOT.jar &
```
### AI
- Pytorch ์คํ
```bash
# Python ํจํค์ง ๊ด๋ฆฌ ๋๊ตฌ ์ต์ ํ (์ ํ)
pip install --upgrade pip
# ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
pip install torch
pip install fastapi
pip install uvicorn
pip install paddlepaddle-gpu # GPU ๋ฒ์ ์ฌ์ฉ ์. CPU ์ฌ์ฉ์ pip install paddlepaddle
pip install paddleocr
pip install sentence-transformers
pip install scikit-learn
pip install googletrans==4.0.0-rc1
```
- ์๋ฒ ์คํ
```bash
uvicorn app:app --reload
```
---
## ๐ฑํ๋ก์ ํธ ์ฌ์ฉ๋ฒ (Getting Started)
```
์์ฑ์์
```
---
## ๐ํ ์ ๋ณด (Team Information)
|
Name |
Role |
github |
 |
๋ฐ์ํ |
Leader / AI |
 |
 |
์์์ฒ |
AI |
 |
 |
๋ฅํฌ์ฌ |
Front-End (iOS) |
 |
 |
๋ฐ์ธํ |
Back-End (Spring) |
 |
 |
ํ์์ |
Back-End (Spring) |
 |
---