Chanjeans commited on
Commit
9a671d7
·
verified ·
1 Parent(s): 6e0e98a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1099 -15
app.py CHANGED
@@ -1,24 +1,1108 @@
1
- from fastapi import FastAPI
 
 
 
 
 
2
  from pydantic import BaseModel
3
  from sentence_transformers import SentenceTransformer
4
 
5
- # FastAPI 애플리케이션 생성
 
 
6
  app = FastAPI()
7
 
8
- # 모델 로드
9
- model = SentenceTransformer("sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
 
 
10
 
11
- # 요청 형식 정의
12
- class TextRequest(BaseModel):
13
- text: str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # API 엔드포인트 설정
16
- @app.post("/embed")
17
- async def embed_text(request: TextRequest):
18
- embedding = model.encode(request.text).tolist()
19
- return {"embedding": embedding}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- # 기본 메시지
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  @app.get("/")
23
- async def root():
24
- return {"message": "Text Embedding API is running"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import time
4
+ import requests
5
+ import numpy as np
6
+ from fastapi import FastAPI, HTTPException
7
  from pydantic import BaseModel
8
  from sentence_transformers import SentenceTransformer
9
 
10
+ #####################################
11
+ # 1) 앱 및 모델 초기화
12
+ #####################################
13
  app = FastAPI()
14
 
15
+ # 🟢 (A) 모델 로딩
16
+ print("Loading SentenceTransformer model... (msmarco-distilbert-base-v4)")
17
+ model_bert = SentenceTransformer('sentence-transformers/msmarco-distilbert-base-v4')
18
+ print("Model loaded.")
19
 
20
+ # 🟢 (B) 예시 아이템 목록
21
+ items = [
22
+
23
+ # ========= 1~12: 운동 (헬스, 요가, 필라테스, 수영, 테니스, 골프, 클라이밍, 축구, 농구, 볼링, 배드민턴, 러닝) =========
24
+ {
25
+ "item_id": 1,
26
+ "title": "헬스 퍼스널 프로젝트",
27
+ "desc": "PT 전문 코치와 함께 근력·유산소를 체계적으로 관리 (운동, 헬스)",
28
+ "personality": "외향형, 이성형"
29
+ },
30
+ {
31
+ "item_id": 2,
32
+ "title": "빈야사 요가 in 강릉",
33
+ "desc": "강릉 바다 풍경 속에서 호흡·동작을 익히는 빈야사 요가 클래스 (운동, 요가)",
34
+ "personality": "내향형, 감정형"
35
+ },
36
+ {
37
+ "item_id": 3,
38
+ "title": "매트 필라테스 집중 워크숍",
39
+ "desc": "매트 동작 위주로 기초 코어 힘을 기르는 소그룹 훈련 (운동, 필라테스)",
40
+ "personality": "내향형, 이성형"
41
+ },
42
+ {
43
+ "item_id": 4,
44
+ "title": "오픈워터 스위밍 체험",
45
+ "desc": "바다나 호수에서 수영 실력을 시험하는 자연 친화형 이벤트 (운동, 수영)",
46
+ "personality": "외향형, 감정형"
47
+ },
48
+ {
49
+ "item_id": 5,
50
+ "title": "테니스 포핸드 마스터클래스",
51
+ "desc": "포핸드 스윙·풋워크를 집중 훈련하고 미니 게임으로 실습 (운동, 테니스)",
52
+ "personality": "외향형, 감정형"
53
+ },
54
+ {
55
+ "item_id": 6,
56
+ "title": "골프 숏게임 특화 레슨",
57
+ "desc": "어프로치·퍼팅 등 숏게임 구간을 집중적으로 연습하는 프로그램 (운동, 골프)",
58
+ "personality": "내향형, 이성형"
59
+ },
60
+ {
61
+ "item_id": 7,
62
+ "title": "아웃도어 클라이밍 교실",
63
+ "desc": "실외 바위 지형에서 암벽등반 기초와 안전 수칙을 배우는 챌린지 (운동, 클라이밍)",
64
+ "personality": "외향형, 감정형"
65
+ },
66
+ {
67
+ "item_id": 8,
68
+ "title": "풋살 드리블&패스 이벤트",
69
+ "desc": "축구 소규모 버전 풋살에서 전술·팀워크를 즐기는 주말 클래스 (운동, 축구)",
70
+ "personality": "외향형, 감정형"
71
+ },
72
+ {
73
+ "item_id": 9,
74
+ "title": "스트리트 농구 대결전",
75
+ "desc": "도심 코트에서 농구 토너먼트를 열어 실력을 겨루는 액션 (운동, 농구)",
76
+ "personality": "외향형, 이성형"
77
+ },
78
+ {
79
+ "item_id": 10,
80
+ "title": "볼링 스핀&릴리스 테크닉",
81
+ "desc": "볼링장 전문 강사와 함께 볼 스핀, 릴리스 자세를 교정 (운동, 볼링)",
82
+ "personality": "내향형, 이성형"
83
+ },
84
+ {
85
+ "item_id": 11,
86
+ "title": "배드민턴 기술 업 워크숍",
87
+ "desc": "스매시·드롭샷·푸트워크를 체계적으로 배우는 배드민턴 교실 (운동, 배드민턴)",
88
+ "personality": "외향형, 감정형"
89
+ },
90
+ {
91
+ "item_id": 12,
92
+ "title": "10K 러닝 크루 레이스",
93
+ "desc": "도심 10km 달리기에 함께 도전하며 기록 향상을 목표 (운동, 러닝)",
94
+ "personality": "내향형, 감정형"
95
+ },
96
 
97
+ # ========= 13~20: 여행 (국내여행, 해외여행, 백패킹, 캠핑, 도시여행, 맛집탐방, 문화탐방, 힐링여행) =========
98
+ {
99
+ "item_id": 13,
100
+ "title": "부산 해안 로드트립",
101
+ "desc": "차로 부산 해안 도로를 달리며 해산물과 해변 풍경 만끽 (여행, 국내여행)",
102
+ "personality": "외향형, 감정형"
103
+ },
104
+ {
105
+ "item_id": 14,
106
+ "title": "미국 서부 배낭투어",
107
+ "desc": "LA·샌프란시스코·라스베이거스 등 미국 서부 도시에 떠나는 자유여행 (여행, 해외여행)",
108
+ "personality": "외향형, 감정형"
109
+ },
110
+ {
111
+ "item_id": 15,
112
+ "title": "설악산 백패킹 트레킹",
113
+ "desc": "설악산 국립공원에서 배낭 야영하며 산세와 계곡을 체험 (여행, 백패킹)",
114
+ "personality": "내향형, 감정형"
115
+ },
116
+ {
117
+ "item_id": 16,
118
+ "title": "모닥불 캠핑 나이트",
119
+ "desc": "텐트 피칭과 모닥불 요리로 캠핑 문화를 느끼는 하룻밤 (여행, 캠핑)",
120
+ "personality": "내향형, 감정형"
121
+ },
122
+ {
123
+ "item_id": 17,
124
+ "title": "홍콩 시티 골목탐방",
125
+ "desc": "홍콩 소호·몽콕 등 골목 시장과 길거리 음식을 즐기는 도시여행 (여행, 도시여행)",
126
+ "personality": "외향형, 이성형"
127
+ },
128
+ {
129
+ "item_id": 18,
130
+ "title": "전국 맛집 로드쇼",
131
+ "desc": "블로그·SNS 추천 맛집을 직접 찾아다니며 식도락을 즐기는 투어 (여행, 맛집탐방)",
132
+ "personality": "외향형, 감정형"
133
+ },
134
+ {
135
+ "item_id": 19,
136
+ "title": "경주 역사 문화탐방",
137
+ "desc": "신라시대 유적·박물관·전통 공연을 둘러보며 문화유산을 학습 (여행, 문화탐방)",
138
+ "personality": "내향형, 이성형"
139
+ },
140
+ {
141
+ "item_id": 20,
142
+ "title": "지중해 요가 힐링 투어",
143
+ "desc": "지중해 연안 소도시에서 요가·명상으로 몸과 마음을 재충전 (여행, 힐링여행)",
144
+ "personality": "외향형, 감정형"
145
+ },
146
 
147
+ # ========= 21~30: 독서 (소설, 시, 에세이, 자기계발, 인문, 역사, 과학, 경제/경영, 철학, 예술) =========
148
+ {
149
+ "item_id": 21,
150
+ "title": "이문열 '우리들의 일그러진 영웅' 독서토론",
151
+ "desc": "한국 현대소설의 학교 폭력·권력 관계를 토론하며 생각 확장 (독서, 소설)",
152
+ "personality": "내향형, 감정형"
153
+ },
154
+ {
155
+ "item_id": 22,
156
+ "title": "김소월 시 낭독 살롱",
157
+ "desc": "'진달래꽃' 등 한국적 정서가 깃든 시를 낭송하고 감상을 교류 (독서, 시)",
158
+ "personality": "내향형, 감정형"
159
+ },
160
+ {
161
+ "item_id": 23,
162
+ "title": "공지영 '즐거운 나의 집' 에세이 톡",
163
+ "desc": "가족과 일상 이야기를 담은 에세이를 함께 읽고 공감 (독서, 에세이)",
164
+ "personality": "내향형, 감정형"
165
+ },
166
+ {
167
+ "item_id": 24,
168
+ "title": "하이 퍼포먼스 습관 만들기",
169
+ "desc": "브렌든 버처드 등 자기계발서를 기반으로 아침 루틴을 실천 (독서, 자기계발)",
170
+ "personality": "내향형, 이성형"
171
+ },
172
+ {
173
+ "item_id": 25,
174
+ "title": "장하석 '온도계의 철학' 인문 스터디",
175
+ "desc": "온도·측정의 철학적 의미를 다룬 책을 통해 사고 확장 (독서, 인문)",
176
+ "personality": "내향형, 이성형"
177
+ },
178
+ {
179
+ "item_id": 26,
180
+ "title": "유홍준 '나의 문화유산답사기' 역사 독해",
181
+ "desc": "한국 문화유산 답사기를 읽고 현장 답사 욕구를 높이는 토론 (독서, 역사)",
182
+ "personality": "내향형, 이성형"
183
+ },
184
+ {
185
+ "item_id": 27,
186
+ "title": "리처드 도킨스 '이기적 유전자' 과학 세션",
187
+ "desc": "유전학 이론을 대중적으로 풀어낸 도서를 함께 읽고 토론 (독서, 과학)",
188
+ "personality": "내향형, 이성형"
189
+ },
190
+ {
191
+ "item_id": 28,
192
+ "title": "짐 콜린스 '좋은 기업을 넘어 위대한 기업으로' 세미나",
193
+ "desc": "기업 성공 사례를 분석하며 경제·경영 통찰을 얻는 과정 (독서, 경제/경영)",
194
+ "personality": "내향형, 이성형"
195
+ },
196
+ {
197
+ "item_id": 29,
198
+ "title": "장자 '소요유' 철학 살롱",
199
+ "desc": "도가 사상을 담은 장자의 글을 읽고 자유로운 삶의 가치 논의 (독서, 철학)",
200
+ "personality": "내향형, 이성형"
201
+ },
202
+ {
203
+ "item_id": 30,
204
+ "title": "에드가 드가 '발레 수업' 예술책 토크",
205
+ "desc": "인상주의 화가 드가의 발레 시리즈와 예술서를 같이 탐독 (독서, 예술)",
206
+ "personality": "내향형, 감정형"
207
+ },
208
+
209
+ # ========= 31~40: 영화 (로맨스, 코미디, 액션, 스릴러, 공포, SF, 판타지, 드라마, 애니메이션, 다큐멘터리) =========
210
+ {
211
+ "item_id": 31,
212
+ "title": "'시간 여행자의 아내' 로맨스 스크리닝",
213
+ "desc": "시간여행을 소재로 한 사랑 이야기를 함께 보고 울고 웃는 자리 (영화, 로맨스)",
214
+ "personality": "외향형, 감정형"
215
+ },
216
+ {
217
+ "item_id": 32,
218
+ "title": "코미디 '슈퍼배드' 웃음 파티",
219
+ "desc": "'슈퍼배드' 시리즈를 감상하며 유머 코드를 분석하고 떠들썩한 웃음을 공유 (영화, 코미디)",
220
+ "personality": "외향형, 감정형"
221
+ },
222
+ {
223
+ "item_id": 33,
224
+ "title": "'킹스맨' 액션씬 관전",
225
+ "desc": "'킹스맨' 시리즈의 액션 연출·스파이 코드를 짚어보는 상영회 (영화, 액션)",
226
+ "personality": "외향형, 이성형"
227
+ },
228
+ {
229
+ "item_id": 34,
230
+ "title": "'서스펙트' 스릴러 미스터리",
231
+ "desc": "긴장감 넘치는 한국 스릴러 영화를 함께 감상하고 반전 요소 해석 (영화, 스릴러)",
232
+ "personality": "외향형, 감정형"
233
+ },
234
+ {
235
+ "item_id": 35,
236
+ "title": "'에일리언' 공포 SF 밤샘",
237
+ "desc": "'에일리언' 시리즈를 몰아보며 외계 생명체 공포와 SF 설정을 토론 (영화, 공포)",
238
+ "personality": "내향형, 감정형"
239
+ },
240
+ {
241
+ "item_id": 36,
242
+ "title": "'그래비티' SF 토크",
243
+ "desc": "우주 공간 조난 스토리를 그린 '그래비티'의 과학·연출을 분석 (영화, SF)",
244
+ "personality": "외향형, 감정형"
245
+ },
246
+ {
247
+ "item_id": 37,
248
+ "title": "'해리 포터' 판타지 앤딩",
249
+ "desc": "호그와트 마법 세계관을 연속 상영하고 팬심을 나누는 스팟 (영화, 판타지)",
250
+ "personality": "외향형, 감정형"
251
+ },
252
+ {
253
+ "item_id": 38,
254
+ "title": "'인생은 아름다워' 드라마 감동",
255
+ "desc": "전쟁 속 가족사랑을 그린 이탈리아 명작으로 희망 메시지 나눔 (영화, 드라마)",
256
+ "personality": "외향형, 감정형"
257
+ },
258
+ {
259
+ "item_id": 39,
260
+ "title": "'너의 이름은' 애니메이션 스페셜",
261
+ "desc": "신카이 마코토 감독의 빛나는 작화·청춘 판타지를 감상 (영화, 애니메이션)",
262
+ "personality": "외향형, 감정형"
263
+ },
264
+ {
265
+ "item_id": 40,
266
+ "title": "'마이클 무어' 다큐 포럼",
267
+ "desc": "'화씨 9/11' 등 사회·정치적 메시지가 담긴 다큐를 보고 토론 (영화, 다큐멘터리)",
268
+ "personality": "외향형, 이성형"
269
+ },
270
+
271
+ # ========= 41~50: 게임 (RPG, FPS, 액션, 전략, 시뮬레이션, 스포츠, 퍼즐, 음악/리듬, 카드, MMORPG) =========
272
+ {
273
+ "item_id": 41,
274
+ "title": "'젤다의 전설: 야생의 숨결' RPG 탐험",
275
+ "desc": "오픈월드 명작 '젤다' 시리즈를 탐험하며 퍼즐·전투 방식을 공유 (게임, RPG)",
276
+ "personality": "내향형, 감정형"
277
+ },
278
+ {
279
+ "item_id": 42,
280
+ "title": "'콜 오브 듀티' FPS 워존 배틀",
281
+ "desc": "밀리터리 FPS에서 팀 단위 전술을 실행하고 승리를 노리는 대전 (게임, FPS)",
282
+ "personality": "외향형, 이성형"
283
+ },
284
+ {
285
+ "item_id": 43,
286
+ "title": "'갓 오브 워' 액션 앤 레이지",
287
+ "desc": "크레토스의 여정·스킬 콤보를 파고들며 액션게임의 재미 체험 (게임, 액션)",
288
+ "personality": "외향형, 감정형"
289
+ },
290
+ {
291
+ "item_id": 44,
292
+ "title": "'문명6' 전략 빌드 세션",
293
+ "desc": "턴제 전략 '문명6'에서 문명별 특성과 승리 조건을 분석 (게임, 전략)",
294
+ "personality": "내향형, 이성형"
295
+ },
296
+ {
297
+ "item_id": 45,
298
+ "title": "'플래닛 코스터' 시뮬레이션 제작소",
299
+ "desc": "놀이공원 경영 게임에서 놀이기구 배치·경영을 디자인 (게임, 시뮬레이션)",
300
+ "personality": "내향형, 감정형"
301
+ },
302
+ {
303
+ "item_id": 46,
304
+ "title": "'NBA 2K' 스포츠 매치",
305
+ "desc": "농구게임 'NBA 2K'로 온라인·오프라인 토너먼트를 개최 (게임, 스포츠)",
306
+ "personality": "외향형, 감정형"
307
+ },
308
+ {
309
+ "item_id": 47,
310
+ "title": "'폴가이즈' 퍼즐 액션 배틀",
311
+ "desc": "귀엽고 혼란스러운 장애물 코스로 다수 인원이 경쟁 (게임, 퍼즐)",
312
+ "personality": "외향형, 이성형"
313
+ },
314
+ {
315
+ "item_id": 48,
316
+ "title": "'비트세이버' 리듬 VR 체험",
317
+ "desc": "VR 기기를 착용해 박자에 맞춰 블록을 베는 리듬 대결 (게임, 음악/리듬)",
318
+ "personality": "내향형, 감정형"
319
+ },
320
+ {
321
+ "item_id": 49,
322
+ "title": "'매직: 더 개더링' 카드 덱실험",
323
+ "desc": "TCG의 원조격인 ‘매직’에서 덱 빌드와 대전 전략을 연구 (게임, 카드)",
324
+ "personality": "내향형, 이성형"
325
+ },
326
+ {
327
+ "item_id": 50,
328
+ "title": "'월드 오브 워크래프트' MMORPG 길드레이드",
329
+ "desc": "아제로스에서 길드원이 힘을 합쳐 레이드를 진행 (게임, MMORPG)",
330
+ "personality": "외향형, 이성형"
331
+ },
332
+
333
+ # ========= 51~60: 공예 (뜨개질, 자수, 도자기, 가죽공예, 목공예, 비즈공예, 캔들/디퓨저, 페이퍼크래프트, 마크라메, 레진아트) =========
334
+ {
335
+ "item_id": 51,
336
+ "title": "코바늘 뜨개질 애착인형 DIY",
337
+ "desc": "코바늘 기법으로 인형이나 소품을 만드는 초급자 대상 워크숍 (공예, 뜨개질)",
338
+ "personality": "내향형, 감정형"
339
+ },
340
+ {
341
+ "item_id": 52,
342
+ "title": "일본 자수 '사시코' 교실",
343
+ "desc": "사시코 기법으로 앞치마·티매트를 장식하는 레슨 (공예, 자수)",
344
+ "personality": "내향형, 이성형"
345
+ },
346
+ {
347
+ "item_id": 53,
348
+ "title": "도자기 핸드페인팅 체험",
349
+ "desc": "빚은 도자기에 직접 그림·문양을 그려 소성까지 경험 (공예, 도자기)",
350
+ "personality": "내향형, 이성형"
351
+ },
352
+ {
353
+ "item_id": 54,
354
+ "title": "가죽 파우치 제작 스튜디오",
355
+ "desc": "가죽 재단·바느질·마감까지 소형 파우치를 만드는 실습 (공예, 가죽공예)",
356
+ "personality": "내향형, 이성형"
357
+ },
358
+ {
359
+ "item_id": 55,
360
+ "title": "목공예 숟가락 만들기 워크숍",
361
+ "desc": "나무를 깎고 다듬어 주방용 숟가락을 만드는 기초 체험 (공예, 목공예)",
362
+ "personality": "내향형, 이성형"
363
+ },
364
+ {
365
+ "item_id": 56,
366
+ "title": "비즈공예 액세서리 디자인",
367
+ "desc": "비즈 구슬로 팔찌·목걸이를 만들고 색감 패턴을 익히는 클래스 (공예, 비즈공예)",
368
+ "personality": "내향형, 감정형"
369
+ },
370
+ {
371
+ "item_id": 57,
372
+ "title": "젤 캔들 & 디퓨저 아틀리에",
373
+ "desc": "투명 젤 왁스로 캔들과 디퓨저를 창작하며 향기를 디자인 (공예, 캔들/디퓨저)",
374
+ "personality": "내향형, 이성형"
375
+ },
376
+ {
377
+ "item_id": 58,
378
+ "title": "페이퍼크래프트 동물 피규어",
379
+ "desc": "종이로 입체 동물 모형을 만들고 채색·디테일 작업 (공예, 페이퍼크래프트)",
380
+ "personality": "내향형, 이성형"
381
+ },
382
+ {
383
+ "item_id": 59,
384
+ "title": "마크라메 해먹 의자 만들기",
385
+ "desc": "매듭 기법을 이용해 해먹 의자·월행잉 등 인테리어 소품 제작 (공예, 마크라메)",
386
+ "personality": "내향형, 이성형"
387
+ },
388
+ {
389
+ "item_id": 60,
390
+ "title": "레진아트 트레이 공방",
391
+ "desc": "레진과 색소·글리터로 컵받침이나 작은 트레이를 만드는 작업 (공예, 레진아트)",
392
+ "personality": "내향형, 이성형"
393
+ },
394
+
395
+ # ========== 61~71: 추가 11개 자유 항목 (임의 분야) ==========
396
+ {
397
+ "item_id": 61,
398
+ "title": "보드게임 '카탄' 챌린지",
399
+ "desc": "전략 보드게임 '카탄' 대회로 무역·개척 전술을 겨루는 이벤트 (기타, 보드게임)",
400
+ "personality": "외향형, 이성형"
401
+ },
402
+ {
403
+ "item_id": 62,
404
+ "title": "스페인어 기초 회화 교실",
405
+ "desc": "hola! 간단한 문장·회화를 배워 여행·일상에서 활용 (기타, 언어학습)",
406
+ "personality": "내향형, 감정형"
407
+ },
408
+ {
409
+ "item_id": 63,
410
+ "title": "홈브루잉 커피 실습",
411
+ "desc": "원두 고르기부터 핸드드립·에스프레소 추출까지 커피 제작 전과정 체험 (기타, 요리/음료)",
412
+ "personality": "내향형, 이성형"
413
+ },
414
+ {
415
+ "item_id": 64,
416
+ "title": "K-POP 댄스 커버 스튜디오",
417
+ "desc": "최신 아이돌 안무를 함께 연습·촬영해보는 퍼포먼스 프로젝트 (기타, 댄스)",
418
+ "personality": "외향형, 감정형"
419
+ },
420
+ {
421
+ "item_id": 65,
422
+ "title": "플라워 레슨 & 꽃다발 디자인",
423
+ "desc": "생화를 활용해 부케·꽃다발을 직접 만드는 교실 (기타, 플라워)",
424
+ "personality": "내향형, 감정형"
425
+ },
426
+ {
427
+ "item_id": 66,
428
+ "title": "드론 항공촬영 워크숍",
429
+ "desc": "드론 조종법·촬영 기법·영상 편집을 배우고 실습 (기타, 드론)",
430
+ "personality": "외향형, 이성형"
431
+ },
432
+ {
433
+ "item_id": 67,
434
+ "title": "비건 베이커리 클래스",
435
+ "desc": "달걀·버터 없이 쿠키·빵을 만드는 레시피와 노하우 학습 (기타, 요리/베이킹)",
436
+ "personality": "내향형, 이성형"
437
+ },
438
+ {
439
+ "item_id": 68,
440
+ "title": "애견 행동교정 & 트릭 클래스",
441
+ "desc": "반려견 기본 행동교정·산책 요령·간단한 재주를 훈련 (기타, 반려동물)",
442
+ "personality": "외향형, 감정형"
443
+ },
444
+ {
445
+ "item_id": 69,
446
+ "title": "영화 시나리오 작법 워크숍",
447
+ "desc": "시놉시스·캐릭터 구성을 배우고 단편 시나리오를 써보는 활동 (기타, 글쓰기)",
448
+ "personality": "내향형, 이성형"
449
+ },
450
+ {
451
+ "item_id": 70,
452
+ "title": "홈칵테일 믹솔로지 이벤트",
453
+ "desc": "칵테일 재료·비율을 익혀 집에서 간단히 만들 수 있는 레시피 실습 (기타, 요리/음료)",
454
+ "personality": "외향형, 감정형"
455
+ },
456
+ {
457
+ "item_id": 71,
458
+ "title": "유튜브 브이로그 크리에이팅",
459
+ "desc": "영상 기획·촬영·편집 노하우를 배우고 브이로그를 완성 (기타, 영상콘텐츠)",
460
+ "personality": "내향형, 이성형"
461
+ },
462
+
463
+ # ==== (운동 - 12개 대응, item_id 73~84) ====================================
464
+ {"item_id": 73, "title": "크로스핏 열정단", "desc": "고강도 크로스핏 운동으로 체력을 단련하는 열정적 모임 (온동, 헬스장)", "personality": "외향형, 감정형"},
465
+ {"item_id": 74, "title": "명상 요가 서클", "desc": "몸의 이완과 마음의 평화를 함께 추구하는 명상 요가 모임 (운동, 요가)", "personality": "외향형, 감정형"},
466
+ {"item_id": 75, "title": "코어 트레이닝 팸", "desc": "필라테스로 코어 근력과 유연성을 키우는 그룹 (운동, 필라테스)", "personality": "외향형, 감정형"},
467
+ {"item_id": 76, "title": "파도타기 워터팀", "desc": "수영과 워터 스포츠를 함께 즐기며 체력을 키우는 모임 (운동, 수영)", "personality": "외향형, 감정형"},
468
+ {"item_id": 77, "title": "라켓 드림클럽", "desc": "테니스를 비롯한 라켓 스포츠를 같이 배우고 즐기는 동호회 (운동, 테니스)", "personality": "외향형, 감정형"},
469
+ {"item_id": 78, "title": "필드 골프 리더스", "desc": "골프 스윙 기술과 필드 매너를 함께 익히는 라운딩 팀 (운동, 골프)", "personality": "외향형, 감정형"},
470
+ {"item_id": 79, "title": "슬링 텀블러즈", "desc": "암벽등반과 슬링 트레이닝으로 색다른 운동을 체험하는 그룹 (운동, 클라이밍)", "personality": "외향형, 감정형"},
471
+ {"item_id": 80, "title": "스포츠 골든리그", "desc": "주중·주말에 축구 경기를 주기적으로 여는 커뮤니티 (운동, 축구)", "personality": "외향형, 감정형"},
472
+ {"item_id": 81, "title": "하프코트 슈터스", "desc": "농구 코트에서 함께 뛰고 실력을 배양하는 팀 (운동, 농구)", "personality": "외향형, 감정형"},
473
+ {"item_id": 82, "title": "스트라이크 러버스", "desc": "볼링 점수를 올리기 위해 함께 연구하고 즐기는 동아리 (운동, 볼링)", "personality": "외향형, 감정형"},
474
+ {"item_id": 83, "title": "스매싱 배드민턴", "desc": "배드민턴 스매시 기술과 경기를 함께 연습하는 학습 모임 (운동, 배드민턴)", "personality": "외향형, 감정형"},
475
+ {"item_id": 84, "title": "나이트 러너스", "desc": "야간 러닝을 통해 도시를 누비며 체력을 기르는 크루 (운동, 러닝)", "personality": "외향형, 감정형"},
476
+
477
+ # ==== (여행 - 8개 대응, item_id 85~92) =====================================
478
+ {"item_id": 85, "title": "오지여행 탐험대", "desc": "국내 숨겨진 오지를 찾아 떠나며 모험심을 기르는 모임 (여행, 국내여행)", "personality": "외향형, 감정형"},
479
+ {"item_id": 86, "title": "글로벌 백팩 트립", "desc": "해외 배낭여행 루트를 함께 계획하고 실행하는 동호회 (여행, 해외여행)", "personality": "외향형, 감정형"},
480
+ {"item_id": 87, "title": "필드 캠핑 어드벤처", "desc": "백패킹과 캠핑을 결합해 자연에서 살아보는 체험 모임 (여행, 백패킹)", "personality": "외향형, 감정형"},
481
+ {"item_id": 88, "title": "패밀리 캠핑 잼", "desc": "가족 단위로 캠핑하며 자연 속 소통을 즐기는 그룹 (여행, 캠핑)", "personality": "외향형, 감정형"},
482
+ {"item_id": 89, "title": "골목길 투어 클럽", "desc": "도시 골목길과 역사적 공간을 함께 탐방하는 여행 서클 (여행, 도시여행)", "personality": "외향형, 감정형"},
483
+ {"item_id": 90, "title": "미식헌터 크루", "desc": "전국 맛집을 조사하고 직접 시식 투어를 떠나는 모임 (여행, 맛집탐방)", "personality": "외향형, 감정형"},
484
+ {"item_id": 91, "title": "문화유산 탐방기획사", "desc": "전통 문화유산과 축제를 기획·탐방하는 여행 동아리 (여행, 문화탐방)", "personality": "외향형, 감정형"},
485
+ {"item_id": 92, "title": "숲속 힐링 트래블", "desc": "자연 속에서 치유와 재충전을 목적으로 여행하는 그룹 (여행, 힐링여행)", "personality": "외향형, 감정형"},
486
+
487
+ # ==== (독서 - 10개 대응, item_id 93~102) ==================================
488
+ {"item_id": 93, "title": "문학 리뷰 서클", "desc": "소설과 문학작품을 읽고 비평하는 책동아리 (독서, 소설)", "personality": "내향형, 감정형"},
489
+ {"item_id": 94, "title": "시인 꿈나무 모임", "desc": "서로의 시를 낭독하고 공유하는 창작 시클럽 (독서, 시)", "personality": "내향형, 감정형"},
490
+ {"item_id": 95, "title": "마음글쓰기 에세이회", "desc": "에세이로 일상과 감정을 표현하며 소통하는 글모임 (독서, 에세이)", "personality": "내향형, 이성형"},
491
+ {"item_id": 96, "title": "실천형 자기계발단", "desc": "자기계발서를 읽고 즉시 실천 계획을 세우는 스터디 (독서, 자기계발)", "personality": "내향형, 이성형"},
492
+ {"item_id": 97, "title": "깊이읽기 인문소사이어티", "desc": "인문학 텍스트를 심층 토론하며 사고력을 확장하는 그룹 (독서, 인문)", "personality": "내향형, 이성형"},
493
+ {"item_id": 98, "title": "역사공부 디스커션", "desc": "시대별 역사적 사건을 공부하고 자유롭게 논의하는 모임 (독서, 역사)", "personality": "내향형, 이성형"},
494
+ {"item_id": 99, "title": "과학탐구 북클럽", "desc": "최신 과학 서적을 중심으로 아이디어를 나누는 독서회 (독서, 과학)", "personality": "내향형, 이성형"},
495
+ {"item_id": 100, "title": "경영전략 독해팀", "desc": "경제/경영 관련 서적을 함께 분석하고 사례를 연구하는 그룹 (독서, 경제/경영)", "personality": "내향형, 이성형"},
496
+ {"item_id": 101, "title": "철학강독 세미나", "desc": "철학 원전을 읽고 핵심 개념을 토론하는 학술 모임 (독서, 철학)", "personality": "내향형, 이성형"},
497
+ {"item_id": 102, "title": "아트북 인사이트회", "desc": "예술 관련 서적을 통해 예술사와 작품 세계를 탐구하는 모임 (독서, 예술)", "personality": "내향형, 감정형"},
498
+
499
+ # ==== (영화 - 10개 대응, item_id 103~112) =================================
500
+ {"item_id": 103, "title": "낭만 영화 애호가들", "desc": "감성적인 로맨스 영화를 좋아하는 사람들의 모임 (영화, 로맨스)", "personality": "외향형, 감정형"},
501
+ {"item_id": 104, "title": "폭소 코미디 페스티벌", "desc": "웃음을 주제로 코미디 영화를 함께 보는 소모임 (영화, 코미디)", "personality": "외향형, 감정형, 이성형"},
502
+ {"item_id": 105, "title": "액션매니아즈", "desc": "박진감 넘치는 액션 영화의 매력을 해부하는 그룹 (영화, 액션)", "personality": "외향형, 감정형"},
503
+ {"item_id": 106, "title": "서스펜스 시네마분석단", "desc": "스릴러 영화 속 긴장감과 스토리를 분석하는 모임 (영화, 스릴러)", "personality": "외향형, 감정형"},
504
+ {"item_id": 107, "title": "호러매틱 스터디", "desc": "공포영화의 분위기와 연출을 집중 탐구하는 팀 (영화, 공포)", "personality": "외향형, 감정형"},
505
+ {"item_id": 108, "title": "SF 월드 디스커버리", "desc": "공상과학 영화를 보고 미래 기술과 세계관을 토론하는 모임 (영화, SF)", "personality": "외향형, 감정형"},
506
+ {"item_id": 109, "title": "판타지 이매지네이션", "desc": "환상적인 판타지 영화를 감상하며 아이디어를 공유하는 서클 (영화, 판타지)", "personality": "외향형, 감정형"},
507
+ {"item_id": 110, "title": "휴먼드라마 인사이트", "desc": "감동적인 드라마 장르 영화를 함께 보고 교훈을 찾는 모임 (영화, 드라마)", "personality": "외향형, 감정형"},
508
+ {"item_id": 111, "title": "애니 애호회", "desc": "다양한 애니메이션 영화를 정기 상영하며 감상하는 팬클럽 (영화, 애니메이션)", "personality": "외향형, 감정형"},
509
+ {"item_id": 112, "title": "다큐 리뷰 포럼", "desc": "다큐멘터리 영화를 보고 사회·환경 문제를 논의하는 모임 (영화, 다큐멘터리)", "personality": "외향형, 이성형"},
510
+
511
+ # ==== (게임 - 10개 대응, item_id 113~122) =================================
512
+ {"item_id": 113, "title": "RPG 모험단", "desc": "판타지 세계에서 함께 파티를 이뤄 모험하는 RPG 팀 (게임, RPG)", "personality": "외향형, 이성형"},
513
+ {"item_id": 114, "title": "FPS 고인물 클랜", "desc": "고난도 슈팅 기술을 연습하며 대회에도 나가는 FPS 동호회 (게임, FPS)", "personality": "외향형, 이성형"},
514
+ {"item_id": 115, "title": "액션코어 전략팀", "desc": "액션 게임의 숨겨진 테크닉과 콤보를 연구하는 그룹 (게임, 액션)", "personality": "외향형, 이성형"},
515
+ {"item_id": 116, "title": "전략모드 시뮬클럽", "desc": "전략 시뮬레이션 장르를 심도 있게 플레이·분석하는 동호회 (게임, 전략)", "personality": "외향형, 이성형"},
516
+ {"item_id": 117, "title": "시뮬레이션 마니아들", "desc": "도시건설, 경영 시뮬레이션 등 다양한 시뮬 게임을 즐기는 모임 (게임, 시뮬레이션)", "personality": "외향형, 이성형, 감정형"},
517
+ {"item_id": 118, "title": "스포츠게이머 챌린지", "desc": "축구·농구 등 스포츠게임 리그를 운영하는 커뮤니티 (게임, 스포츠)", "personality": "외향형, 이성형"},
518
+ {"item_id": 119, "title": "퍼즐 브레인홀릭", "desc": "퍼��·두뇌게임을 함께 풀며 아이디어를 공유하는 팀 (게임, 퍼즐)", "personality": "외향형, 이성형"},
519
+ {"item_id": 120, "title": "리듬게임 오케스트라", "desc": "음악/리듬게임에서 합주하는 느낌으로 협력 플레이하는 모임 (게임, 음악/리듬)", "personality": "외향형, 이성형"},
520
+ {"item_id": 121, "title": "카드플레이 매니아", "desc": "포커·TCG 등 카드 기반 게임을 심도 있게 즐기는 동아리 (게임, 카드)", "personality": "외향형, 이성형"},
521
+ {"item_id": 122, "title": "MMORPG 연합길드", "desc": "대규모 온라인 RPG에서 길드원들과 함께 도전하는 팀 (게임, MMORPG)", "personality": "외향형, 이성형"},
522
+
523
+ # ==== (공예 - 10개 대응, item_id 123~132) =================================
524
+ {"item_id": 123, "title": "니트디자인 스터디오", "desc": "뜨개질로 패션 소품과 의류를 창작하는 워크숍 (공예, 뜨개질)", "personality": "내향형, 이성형"},
525
+ {"item_id": 124, "title": "자수 디테일연구회", "desc": "섬세한 자수 기법을 연구하며 작품을 완성하는 모임 (공예, 자수)", "personality": "내향형, 이성형"},
526
+ {"item_id": 125, "title": "도예 공예단", "desc": "도자기 공예로 식기·인테리어 소품을 제작해보는 그룹 (공예, 도자기)", "personality": "내향형, 이성형"},
527
+ {"item_id": 126, "title": "가죽공예 스킬랩", "desc": "가죽 재단부터 바느질까지 실습하고 디자인을 공유하는 모임 (공예, 가죽공예)", "personality": "내향형, 이성형"},
528
+ {"item_id": 127, "title": "목공 마스터스", "desc": "목재를 활용해 가구·장식품을 제작하며 기술을 배우는 모임 (공예, 목공예)", "personality": "내향형, 이성형"},
529
+ {"item_id": 128, "title": "비즈 디자인 팩토리", "desc": "비즈공예로 액세서리·장신구를 창작하는 교실 (공예, 비즈공예)", "personality": "내향형, 이성형"},
530
+ {"item_id": 129, "title": "캔들/디퓨저 크리에이티브", "desc": "향초와 디퓨저를 예술적으로 표현해보는 창작 스튜디오 (공예, 캔들/디퓨저)", "personality": "내향형, 이성형"},
531
+ {"item_id": 130, "title": "페이퍼아트 디자인랩", "desc": "종이 공예로 독특한 작품과 미니어처를 만드는 연구회 (공예, 페이퍼크래프트)", "personality": "내향형, 이성형"},
532
+ {"item_id": 131, "title": "마크라메 공예실", "desc": "마크라메 매듭 기법을 다양하게 시도해보는 작업실 (공예, 마크라메)", "personality": "내향형, 이성형"},
533
+ {"item_id": 132, "title": "레진아트 크리에이터즈", "desc": "레진을 활용해 장식품·소품을 디자인하고 공유하는 모임 (공예, 레진아트)", "personality": "내향형, 이성형"},
534
+ # ===== [133~144] 운동 (12개)
535
+ {
536
+ "item_id": 133,
537
+ "title": "나이키 헬스 피트니스 챌린지",
538
+ "desc": "헬스장에서 나이키 프로그램을 통해 웨이트 및 유산소를 마스터 (운동, 헬스)",
539
+ "personality": "외향형, 감정형"
540
+ },
541
+ {
542
+ "item_id": 134,
543
+ "title": "아쉬탕가 요가 클래스 in 발리",
544
+ "desc": "발리 자연 속에서 명상·아사나 요가를 심도 있게 체험 (운동, 요가)",
545
+ "personality": "내향형, 감정형"
546
+ },
547
+ {
548
+ "item_id": 135,
549
+ "title": "리포머 필라테스 스튜디오",
550
+ "desc": "기구 필라테스로 자세 교정과 코어 강화에 집중 (운동, 필라테스)",
551
+ "personality": "내향형, 이성형"
552
+ },
553
+ {
554
+ "item_id": 136,
555
+ "title": "아쿠아 스위밍 프로젝트",
556
+ "desc": "실내 수영장에서 영법·호흡법을 익히고 오픈워터 도전 (운동, 수영)",
557
+ "personality": "외향형, 감정형"
558
+ },
559
+ {
560
+ "item_id": 137,
561
+ "title": "윔블던 테니스 레슨",
562
+ "desc": "프로 코치와 함께 랠리·발리를 집중 훈련, 미니 매치 진행 (운동, 테니스)",
563
+ "personality": "외향형, 이성형"
564
+ },
565
+ {
566
+ "item_id": 138,
567
+ "title": "스크린 골프 라운딩",
568
+ "desc": "필드 대신 스크린 골프로 스윙 교정하고 퍼팅 실력을 키움 (운동, 골프)",
569
+ "personality": "내향형, 이성형"
570
+ },
571
+ {
572
+ "item_id": 139,
573
+ "title": "실내 클라이밍 챌린지",
574
+ "desc": "암벽등반 센터에서 다양한 코스를 공략하며 근지구력 향상 (운동, 클라이밍)",
575
+ "personality": "외향형, 감정형"
576
+ },
577
+ {
578
+ "item_id": 140,
579
+ "title": "풋볼 매치데이 이벤트",
580
+ "desc": "축구 팬들이 모여 포메이션 짜고 미니 경기를 즐기는 일정 (운동, 축구)",
581
+ "personality": "외향형, 감정형"
582
+ },
583
+ {
584
+ "item_id": 141,
585
+ "title": "NBA 농구 액션타임",
586
+ "desc": "코트에서 드리블·슛을 연습하고 3:3 스크리미지를 진행 (운동, 농구)",
587
+ "personality": "외향형, 감정형"
588
+ },
589
+ {
590
+ "item_id": 142,
591
+ "title": "락볼링 스트라이크 파티",
592
+ "desc": "볼링장에서 음악과 함께 스트라이크 확률을 높이는 교류전 (운동, 볼링)",
593
+ "personality": "내향형, 감정형"
594
+ },
595
+ {
596
+ "item_id": 143,
597
+ "title": "셔틀콕 배드민턴 교실",
598
+ "desc": "배드민턴 스매시·푸트워크 집중 연습 후 미니 토너먼트 (운동, 배드민턴)",
599
+ "personality": "외향형, 감정형"
600
+ },
601
+ {
602
+ "item_id": 144,
603
+ "title": "하프마라톤 러닝 레이스",
604
+ "desc": "도심 10km·21km 레이스에 도전하며 기록 향상을 목표 (운동, 러닝)",
605
+ "personality": "내향형, 감정형"
606
+ },
607
+
608
+ # ===== [145~152] 여행 (8개)
609
+ {
610
+ "item_id": 145,
611
+ "title": "강원도 로드트립",
612
+ "desc": "차로 강원도 해안·산골 명소를 돌아보며 자연을 만끽 (여행, 국내여행)",
613
+ "personality": "내향형, 감정형"
614
+ },
615
+ {
616
+ "item_id": 146,
617
+ "title": "유럽 배낭 자유여행",
618
+ "desc": "파리·로마·바르셀로나를 포함해 유럽 도시들을 여행 (여행, 해외여행)",
619
+ "personality": "외향형, 감정형"
620
+ },
621
+ {
622
+ "item_id": 147,
623
+ "title": "지리산 백패킹 트레일",
624
+ "desc": "배낭 하나로 지리산 둘레길을 걸으며 자연 속 야영 (여행, 백패킹)",
625
+ "personality": "내향형, 감정형"
626
+ },
627
+ {
628
+ "item_id": 148,
629
+ "title": "캠핑 파이어나이트",
630
+ "desc": "텐트 치고 모닥불을 즐기며 가족·친구와 소통하는 프로그램 (여행, 캠핑)",
631
+ "personality": "외향형, 감정형"
632
+ },
633
+ {
634
+ "item_id": 149,
635
+ "title": "서울 골목투어",
636
+ "desc": "익선동·을지로 등 오래된 골목길 카페·맛집을 탐방 (여행, 도시여행)",
637
+ "personality": "외향형, 감정형"
638
+ },
639
+ {
640
+ "item_id": 150,
641
+ "title": "전주 한옥마을 미식 탐방",
642
+ "desc": "전주의 비빔밥·막걸리·한정식을 둘러보는 식도락 여행 (여행, 맛집탐방)",
643
+ "personality": "외향형, 감정형"
644
+ },
645
+ {
646
+ "item_id": 151,
647
+ "title": "경복궁 문화탐방",
648
+ "desc": "왕궁·전통 공연·박물관을 돌며 한국 역사를 배우는 코스 (여행, 문화탐방)",
649
+ "personality": "내향형, 이성형"
650
+ },
651
+ {
652
+ "item_id": 152,
653
+ "title": "제주 오름 힐링투어",
654
+ "desc": "제주 오름·용암동굴을 걸으며 자연 속에서 재충전 (여행, 힐링여행)",
655
+ "personality": "내향형, 감정형"
656
+ },
657
+
658
+ # ===== [153~162] 독서 (10개)
659
+ {
660
+ "item_id": 153,
661
+ "title": "무라카미 '1Q84' 북클럽",
662
+ "desc": "하루키 장편소설을 함께 읽고 상징·메타포를 토론 (독서, 소설)",
663
+ "personality": "내향형, 감정형"
664
+ },
665
+ {
666
+ "item_id": 154,
667
+ "title": "윤동주 시 낭독회",
668
+ "desc": "‘하늘과 바람과 별과 시’ 등 윤동주 시를 낭송하며 문학적 감성을 공유 (독서, 시)",
669
+ "personality": "내향형, 감정형"
670
+ },
671
+ {
672
+ "item_id": 155,
673
+ "title": "김영하 '여행의 이유' 에세이 살롱",
674
+ "desc": "여행과 삶의 관계를 에세이로 탐구하고 느낀 점을 나누는 시간 (독서, 에세이)",
675
+ "personality": "내향형, 감정형"
676
+ },
677
+ {
678
+ "item_id": 156,
679
+ "title": "스티븐 코비 '성공하는 사람들의 7가지 습관'",
680
+ "desc": "자기계발서를 함께 읽고 실천 전략을 세우는 성장 프로젝트 (독서, 자기계발)",
681
+ "personality": "내향형, 이성형"
682
+ },
683
+ {
684
+ "item_id": 157,
685
+ "title": "인문학 토크: '총, 균, 쇠' & '사피엔스'",
686
+ "desc": "문명의 발전 과정을 다룬 명저를 비교·분석하는 심층 독서 (독서, 인문)",
687
+ "personality": "내향형, 이성형"
688
+ },
689
+ {
690
+ "item_id": 158,
691
+ "title": "유발 하라리 '사피엔스' 역사 세션",
692
+ "desc": "인류 역사를 조망하는 '사피엔스'를 읽고 현재 사회와 연결 (독서, 역사)",
693
+ "personality": "내향형, 이성형"
694
+ },
695
+ {
696
+ "item_id": 159,
697
+ "title": "칼 세이건 '코스모스' 과학 독서모임",
698
+ "desc": "우주와 과학적 사고를 확장해보는 '코스모스' 함께 읽기 (독서, 과학)",
699
+ "personality": "내향형, 이성형"
700
+ },
701
+ {
702
+ "item_id": 160,
703
+ "title": "애덤 스미스 '국부론' 경제포럼",
704
+ "desc": "고전 경제학을 토대로 시장경제 원리를 이해하는 세미나 (독서, 경제/경영)",
705
+ "personality": "내향형, 이성형"
706
+ },
707
+ {
708
+ "item_id": 161,
709
+ "title": "니체 '차라투스트라는 이렇게 말했다' 철학 토론",
710
+ "desc": "니체 철학을 깊이 있게 탐독하고 현대적 의미를 해석 (독서, 철학)",
711
+ "personality": "내향형, 이성형"
712
+ },
713
+ {
714
+ "item_id": 162,
715
+ "title": "빈센트 반 고흐 예술책 리뷰",
716
+ "desc": "화가 반 고흐의 작품 세계를 미술서적으로 접하고 교감 (독서, 예술)",
717
+ "personality": "내향형, 감정형"
718
+ },
719
+
720
+ # ===== [163~172] 영화 (10개)
721
+ {
722
+ "item_id": 163,
723
+ "title": "'러브 액츄얼리' 로맨스 상영회",
724
+ "desc": "여러 커플의 사랑 이야기를 담은 '러브 액츄얼리'를 감상 후 토론 (영화, 로맨스)",
725
+ "personality": "외향형, 감정형"
726
+ },
727
+ {
728
+ "item_id": 164,
729
+ "title": "코미디 '미스터 빈' 특별전",
730
+ "desc": "로완 앳킨슨의 바디 코미디를 감상하며 웃음 포인트를 분석 (영화, 코미디)",
731
+ "personality": "외향형, 감정형"
732
+ },
733
+ {
734
+ "item_id": 165,
735
+ "title": "'매드 맥스: 분노의 도로' 액션 토크",
736
+ "desc": "포스트 아포칼립스 배경의 질주 액션을 해부하는 상영회 (영화, 액션)",
737
+ "personality": "외향형, 감정형"
738
+ },
739
+ {
740
+ "item_id": 166,
741
+ "title": "스릴러 '겟 아웃' 심리분석",
742
+ "desc": "조던 필의 '겟 아웃'을 통해 공포와 사회적 메시지를 살피는 이벤트 (영화, 스릴러)",
743
+ "personality": "외향형, 감정형"
744
+ },
745
+ {
746
+ "item_id": 167,
747
+ "title": "공포 '컨저링' 오싹 체험",
748
+ "desc": "심령현상을 다룬 공포영화 '컨저링'으로 사운드·분위기 연출을 탐구 (영화, 공포)",
749
+ "personality": "외향형, 감정형"
750
+ },
751
+ {
752
+ "item_id": 168,
753
+ "title": "'인터스텔라' SF 디스커션",
754
+ "desc": "크리스토퍼 놀란의 우주·중력 이론을 담은 영화를 보고 과학적 설정 토론 (영화, SF)",
755
+ "personality": "외향형, 감정형"
756
+ },
757
+ {
758
+ "item_id": 169,
759
+ "title": "'반지의 제왕' 판타지 데이",
760
+ "desc": "톨킨 세계관을 기반으로 한 대서사시를 연속 상영·분석 (영화, 판타지)",
761
+ "personality": "외향형, 감정형"
762
+ },
763
+ {
764
+ "item_id": 170,
765
+ "title": "'쇼생크 탈출' 드라마 감동",
766
+ "desc": "인생영화 '쇼생크 탈출'을 보고 희망·인내의 메시지를 토론 (영화, 드라마)",
767
+ "personality": "외향형, 감정형"
768
+ },
769
+ {
770
+ "item_id": 171,
771
+ "title": "지브리 애니메이션 스페셜",
772
+ "desc": "'센과 치히로' 등 지브리 작품을 상영하며 판타지·동심을 느끼는 감상회 (영화, 애니메이션)",
773
+ "personality": "외향형, 감정형"
774
+ },
775
+ {
776
+ "item_id": 172,
777
+ "title": "다큐 '지구(Earth)' 환경 포럼",
778
+ "desc": "BBC 제작 다큐멘터리 '지구'를 보고 자연·환경 이슈를 논의 (영화, 다큐멘터리)",
779
+ "personality": "외향형, 이성형"
780
+ },
781
+
782
+ # ===== [173~182] 게임 (10개)
783
+ {
784
+ "item_id": 173,
785
+ "title": "'엘든 링' RPG 도전",
786
+ "desc": "프롬소프트웨어의 ‘엘든 링’에서 난이도 극복 전략과 빌드 연구 (게임, RPG)",
787
+ "personality": "외향형, 이성형"
788
+ },
789
+ {
790
+ "item_id": 174,
791
+ "title": "'오버워치2' FPS 팀플",
792
+ "desc": "‘오버워치2’에서 역할 분담·전술 플레이를 협력하는 대전 (게임, FPS)",
793
+ "personality": "외향형, 이성형"
794
+ },
795
+ {
796
+ "item_id": 175,
797
+ "title": "'데빌 메이 크라이' 액션 콤보 연구",
798
+ "desc": "콤보 액션의 정수 ‘데메크’ 시리즈를 플레이하며 기술을 익힘 (게임, 액션)",
799
+ "personality": "외향형, 이성형"
800
+ },
801
+ {
802
+ "item_id": 176,
803
+ "title": "'스타크래프트' 전략 빌드토론",
804
+ "desc": "테란·저그·프로토스 종족별 빌드 오더·리플레이 분석 (게임, 전략)",
805
+ "personality": "내향형, 이성형"
806
+ },
807
+ {
808
+ "item_id": 177,
809
+ "title": "'심시티' 시뮬레이션 건설",
810
+ "desc": "도시건설 게임 ‘심시티’로 자신만의 도시를 디자인하고 운영 (게임, 시뮬레이션)",
811
+ "personality": "내향형, 감정형"
812
+ },
813
+ {
814
+ "item_id": 178,
815
+ "title": "'피파23' 스포츠 대전",
816
+ "desc": "축구게임 ‘피파23’에서 오프라인 리그전을 열고 순위를 집계 (게임, 스포츠)",
817
+ "personality": "외향형, 이성형"
818
+ },
819
+ {
820
+ "item_id": 179,
821
+ "title": "'테트리스99' 퍼즐 배틀로얄",
822
+ "desc": "닌텐도 스위치 ‘테트리스99’로 다수 인원이 동시에 ���쟁 (게임, 퍼즐)",
823
+ "personality": "외향형, 이성형"
824
+ },
825
+ {
826
+ "item_id": 180,
827
+ "title": "'DJMAX 리스펙트 V' 리듬 페스티벌",
828
+ "desc": "국산 리듬게임 DJMAX로 콤보와 노트 패턴에 도전 (게임, 음악/리듬)",
829
+ "personality": "외향형, 이성형"
830
+ },
831
+ {
832
+ "item_id": 181,
833
+ "title": "'하스스톤' 카드 덱실험실",
834
+ "desc": "블리자드 TCG ‘하스스톤’에서 전략적 덱 구성과 토너먼트 플레이 (게임, 카드)",
835
+ "personality": "외향형, 이성형"
836
+ },
837
+ {
838
+ "item_id": 182,
839
+ "title": "'로스트아크' MMORPG 레이드",
840
+ "desc": "대규모 온라인 RPG ‘로스트아크’에서 길드원과 협동해 레이드를 공략 (게임, MMORPG)",
841
+ "personality": "외향형, 이성형"
842
+ },
843
+
844
+ # ===== [183~192] 공예 (10개)
845
+ {
846
+ "item_id": 183,
847
+ "title": "니트 코바늘 인형 만들기",
848
+ "desc": "뜨개질 기법으로 귀여운 인형이나 소품을 제작하는 워크숍 (공예, 뜨개질)",
849
+ "personality": "내향형, 이성형"
850
+ },
851
+ {
852
+ "item_id": 184,
853
+ "title": "프랑스자수 브로치 교실",
854
+ "desc": "세심한 자수로 브로치·미니 파우치를 장식하는 공예 클래스 (공예, 자수)",
855
+ "personality": "내향형, 감정형"
856
+ },
857
+ {
858
+ "item_id": 185,
859
+ "title": "도예 핸드빌딩 체험",
860
+ "desc": "흙을 손으로 빚어 머그·접시를 만드는 도자기 공예 (공예, 도자기)",
861
+ "personality": "내향형, 이성형"
862
+ },
863
+ {
864
+ "item_id": 186,
865
+ "title": "가죽공예 카드지갑 제작",
866
+ "desc": "가죽 재단·바느질·엣지 마감 실습으로 카드지갑을 완성 (공예, 가죽공예)",
867
+ "personality": "내향형, 이성형"
868
+ },
869
+ {
870
+ "item_id": 187,
871
+ "title": "나무도마 목공 교실",
872
+ "desc": "원목을 가공·샌딩하여 주방용 나무도마를 제작하는 기초 체험 (공예, 목공예)",
873
+ "personality": "내향형, 이성형"
874
+ },
875
+ {
876
+ "item_id": 188,
877
+ "title": "비즈공예 액세서리 디자인",
878
+ "desc": "비즈 구슬로 팔찌·목걸이를 만들고 색채 감각을 익히는 클래스 (공예, 비즈공예)",
879
+ "personality": "내향형, 감정형"
880
+ },
881
+ {
882
+ "item_id": 189,
883
+ "title": "소이 캔들 & 디퓨저 만들기",
884
+ "desc": "천연 소이왁스로 향초, 디퓨저를 제작해 감성 분위기를 조성 (공예, 캔들/디퓨저)",
885
+ "personality": "내향형, 이성형"
886
+ },
887
+ {
888
+ "item_id": 190,
889
+ "title": "페이퍼크래프트 3D 미니어처",
890
+ "desc": "종이 공예로 입체 구조물을 제작하고 채색·디테일을 살리는 교실 (공예, 페이퍼크래프트)",
891
+ "personality": "내향형, 이성형"
892
+ },
893
+ {
894
+ "item_id": 191,
895
+ "title": "마크라메 인테리어 월행잉",
896
+ "desc": "매듭 기법을 응용해 벽걸이·화분홀더 등 인테리어 소품을 만드는 실습 (공예, 마크라메)",
897
+ "personality": "내향형, 이성형"
898
+ },
899
+ {
900
+ "item_id": 192,
901
+ "title": "레진아트 키링 & 액세서리",
902
+ "desc": "투명 레진에 색소·글리터를 활용해 키링·반지를 만드는 창작 (공예, 레진아트)",
903
+ "personality": "내향형, 이성형"
904
+ }
905
+
906
+ ]
907
+
908
+
909
+
910
+
911
+ #####################################
912
+ # 2) 아이템 임베딩 로직
913
+ #####################################
914
+ def make_item_embedding_dict(items, model):
915
+ item_embedding_dict = {}
916
+ for item in items:
917
+ text = f"{item['title']} {item['desc']}"
918
+ emb = model.encode(text, convert_to_numpy=True)
919
+ item_embedding_dict[item['item_id']] = emb
920
+ return item_embedding_dict
921
+
922
+ item_embedding_dict = make_item_embedding_dict(items, model_bert)
923
+
924
+
925
+ #####################################
926
+ # 3) 사용자 프로필 -> 문장화
927
+ #####################################
928
+ def make_user_profile_text(user_profile: dict) -> str:
929
+ ext = user_profile.get("extroversion", "")
930
+ ft = user_profile.get("feeling_thinking", "")
931
+ hobby = user_profile.get("hobby", "")
932
+ detail = user_profile.get("detail_hobby", "")
933
+
934
+ if hobby == "여행":
935
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. "
936
+ f"여행을 정말 좋아하며, 특히 {detail}을 즐깁니다. "
937
+ "다양한 문화와 맛집을 직접 체험하고 싶어합니다.")
938
+ elif hobby == "운동":
939
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. "
940
+ f"운동에 열정을 가지고 있으며, 특히 {detail}을 즐깁니다. "
941
+ "건강과 체력을 증진시키고자 꾸준히 활동합니다.")
942
+ elif hobby == "독서":
943
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니��. "
944
+ f"독서를 사랑하며, 특히 {detail}에 깊은 관심을 가지고 있습니다. "
945
+ "새로운 지식과 다양한 관점을 배우고자 합니다.")
946
+ elif hobby == "영화":
947
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. "
948
+ f"영화를 감상하는 것을 좋아하며, 특히 {detail} 장르에 큰 흥미를 느낍니다. "
949
+ "감동과 재미를 동시에 경험하고 싶어합니다.")
950
+ elif hobby == "게임":
951
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. "
952
+ f"게임을 즐기며, 특히 {detail} 게임에 많은 관심을 가지고 있습니다. "
953
+ "전략적 사고와 도전을 통해 성취감을 느끼고자 합니다.")
954
+ elif hobby == "공예":
955
+ return (f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. "
956
+ f"공예 활동에 열정을 가지고 있으며, 특히 {detail}을 즐깁니다. "
957
+ "창의적인 아이디어를 실현하며 섬세한 작업을 즐깁니다.")
958
+ else:
959
+ return f"저는 {ext}이며 {ft}한 성향을 가진 사람입니다. 다양한 취미를 즐기고 있습니다."
960
+
961
+
962
+ #####################################
963
+ # 4) 사용자 임베딩 + 추천 로직
964
+ #####################################
965
+ def get_user_embedding(user_profile: dict):
966
+ user_text = make_user_profile_text(user_profile)
967
+ return model_bert.encode(user_text, convert_to_numpy=True)
968
+
969
+ def extract_hobby(desc):
970
+ match = re.search(r"\((.*?)\)", desc)
971
+ return match.group(1) if match else ""
972
+
973
+ def cosine_similarity(vec1, vec2):
974
+ norm1 = np.linalg.norm(vec1)
975
+ norm2 = np.linalg.norm(vec2)
976
+ if norm1 == 0 or norm2 == 0:
977
+ return 0
978
+ return np.dot(vec1, vec2) / (norm1 * norm2)
979
+
980
+ def recommend_content_based(user_profile, top_n=5):
981
+ user_emb = get_user_embedding(user_profile)
982
+ scored = []
983
+
984
+ user_hobby = user_profile.get("hobby", "")
985
+ user_detail_hobby = user_profile.get("detail_hobby", "")
986
+ user_extroversion = user_profile.get("extroversion", "")
987
+ user_feeling_thinking = user_profile.get("feeling_thinking", "")
988
+
989
+ for item in items:
990
+ item_id = item["item_id"]
991
+ item_emb = item_embedding_dict[item_id]
992
+ sim = cosine_similarity(user_emb, item_emb)
993
+
994
+ # 가중치
995
+ weight = 1.0
996
+
997
+ # (1) 취미
998
+ desc_hobby = extract_hobby(item["desc"]) # 예: (운동, 헬스)
999
+ if user_hobby and user_hobby in desc_hobby:
1000
+ weight *= 1.05
1001
+ if user_detail_hobby and user_detail_hobby in desc_hobby:
1002
+ weight *= 1.2
1003
+
1004
+ # (2) 성향
1005
+ personality_match_count = sum(trait in item["personality"] for trait in [user_extroversion, user_feeling_thinking])
1006
+ if personality_match_count == 1:
1007
+ weight *= 1.15
1008
+ elif personality_match_count == 2:
1009
+ weight *= 1.3
1010
+
1011
+ final_score = sim * weight
1012
+ scored.append((item, final_score))
1013
+
1014
+ scored.sort(key=lambda x: x[1], reverse=True)
1015
+ return scored[:top_n]
1016
+
1017
+
1018
+ #####################################
1019
+ # 5) 챗봇 로직
1020
+ #####################################
1021
+ HF_API_KEY = os.environ.get("HF_API_KEY", "YOUR_HF_API_KEY")
1022
+ API_URL = "https://api-inference.huggingface.co/models/Chanjeans/tfchatbot_2"
1023
+ HEADERS = {"Authorization": f"Bearer {HF_API_KEY}"}
1024
+
1025
+ def chat_response(user_input, mode="emotion", max_retries=5):
1026
+ if mode not in ["emotion", "rational"]:
1027
+ raise HTTPException(status_code=400, detail="mode는 'emotion' 또는 'rational'이어야 합니다.")
1028
+
1029
+ prompt = f"<{mode}><usr>{user_input}</usr><sys>"
1030
+ payload = {
1031
+ "inputs": prompt,
1032
+ "parameters": {
1033
+ "max_new_tokens": 128,
1034
+ "temperature": 0.7,
1035
+ "top_p": 0.9,
1036
+ "top_k": 50,
1037
+ "repetition_penalty": 1.2,
1038
+ "do_sample": True
1039
+ },
1040
+ "options": {"wait_for_model": True}
1041
+ }
1042
+
1043
+ for attempt in range(max_retries):
1044
+ response = requests.post(API_URL, headers=HEADERS, json=payload)
1045
+ if response.status_code == 200:
1046
+ try:
1047
+ result = response.json()
1048
+ if isinstance(result, list) and "generated_text" in result[0]:
1049
+ generated_text = result[0]["generated_text"]
1050
+ return generated_text.replace(prompt, "").strip()
1051
+ else:
1052
+ return "응답 형식이 예상과 다릅니다."
1053
+ except Exception as e:
1054
+ return f"JSON 파싱 오류: {e}"
1055
+
1056
+ elif response.status_code == 503:
1057
+ # 모델 로딩 중
1058
+ error_info = response.json()
1059
+ estimated_time = error_info.get("estimated_time", 15)
1060
+ time.sleep(min(estimated_time, 15))
1061
+ else:
1062
+ return f"API Error: {response.status_code}, {response.text}"
1063
+
1064
+ return "🚨 모델 로딩이 너무 오래 걸립니다. 잠시 후 다시 시도하세요."
1065
+
1066
+
1067
+ #####################################
1068
+ # 6) FastAPI Endpoint
1069
+ #####################################
1070
+
1071
+ # (1) 메인 페이지
1072
  @app.get("/")
1073
+ def home():
1074
+ return {"message": "안녕하세요! 추천 & 챗봇 FastAPI 서버입니다."}
1075
+
1076
+ # (2) 추천 Endpoint
1077
+ class UserProfile(BaseModel):
1078
+ extroversion: str
1079
+ feeling_thinking: str
1080
+ hobby: str
1081
+ detail_hobby: str
1082
+
1083
+ @app.post("/recommend")
1084
+ def recommend_api(profile: UserProfile):
1085
+ # "솔루션 제공" 로직과 동일
1086
+ top_items = recommend_content_based(profile.dict(), top_n=5)
1087
+ results = []
1088
+ for (item, score) in top_items:
1089
+ results.append({
1090
+ "item_id": item["item_id"],
1091
+ "title": item["title"],
1092
+ "desc": item["desc"],
1093
+ "personality": item["personality"],
1094
+ "score": round(score, 4)
1095
+ })
1096
+ return {"recommendations": results}
1097
+
1098
+ # (3) 챗봇 Endpoint
1099
+ class ChatRequest(BaseModel):
1100
+ user_input: str
1101
+ mode: str = "emotion"
1102
+
1103
+ @app.post("/chat")
1104
+ def chat_api(req: ChatRequest):
1105
+ user_text = req.user_input
1106
+ mode = req.mode
1107
+ reply = chat_response(user_text, mode=mode)
1108
+ return {"response": reply}