-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschemas.py
More file actions
373 lines (274 loc) · 12.1 KB
/
schemas.py
File metadata and controls
373 lines (274 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
from datetime import datetime
from typing import Optional, List, Dict, Any, TypeVar, Generic
from pydantic import BaseModel, Field, HttpUrl
# 제네릭 타입 변수 정의
T = TypeVar("T")
# 기본 요청
class RequestBase(BaseModel):
pass
# 기본 응답
class ResponseBase(BaseModel, Generic[T]):
success: bool = Field(..., title="성공유무", description="true,false")
data: T = Field(..., title="응답 데이터")
status: str = Field(..., title="상태", description="요청 처리 상태")
message: str = Field(..., title="메시지", description="메시지입니다.")
# ============== 1단계: 네이버 키워드 추출 ==============
class RequestNaverSearch(RequestBase):
tag: str = Field(..., title="태그", description="데이터랩/스토어 태그 구분")
# 응답 데이터 모델
class NaverSearchData(BaseModel):
keyword: str = Field(..., title="키워드", description="검색에 사용된 키워드")
total_keyword: Dict[int, str] = Field(
..., title="총 키워드", description="키워드별 총 검색 결과"
)
# 최종 응답 모델
class ResponseNaverSearch(ResponseBase[NaverSearchData]):
"""네이버 키워드 검색 API 응답"""
pass
# ============== 2단계: 사다구 검색 ==============
class RequestSadaguSearch(RequestBase):
keyword: str = Field(..., title="검색 키워드", description="상품을 검색할 키워드")
# 응답 데이터 모델
class SadaguSearchData(BaseModel):
keyword: str = Field(..., title="검색 키워드", description="검색에 사용된 키워드")
search_results: List[Dict] = Field(
..., title="검색 결과", description="검색된 상품 목록"
)
# 최종 응답 모델
class ResponseSadaguSearch(ResponseBase[SadaguSearchData]):
"""사다구 상품 검색 API 응답"""
pass
# ============== 3단계: 사다구 매칭 ==============
class RequestSadaguMatch(RequestBase):
keyword: str = Field(..., title="매칭 키워드", description="상품과 매칭할 키워드")
search_results: List[Dict] = Field(
..., title="검색 결과", description="이전 단계에서 검색된 상품 목록"
)
# 응답 데이터 모델
class SadaguMatchData(BaseModel):
keyword: str = Field(..., title="매칭 키워드", description="매칭에 사용된 키워드")
matched_products: List[Dict] = Field(
..., title="매칭된 상품", description="키워드와 매칭된 상품 목록"
)
# 최종 응답 모델
class ResponseSadaguMatch(ResponseBase[SadaguMatchData]):
"""사다구 상품 매칭 API 응답"""
pass
# ============== 4단계: 사다구 유사도 ==============
class RequestSadaguSimilarity(RequestBase):
keyword: str = Field(
..., title="유사도 분석 키워드", description="유사도 분석할 키워드"
)
matched_products: List[Dict] = Field(
..., title="매칭된 상품", description="이전 단계에서 매칭된 상품 목록"
)
search_results: Optional[List[Dict]] = Field(
None,
title="검색 결과",
description="매칭 실패시 사용할 전체 검색 결과 (폴백용)",
)
# 응답 데이터 모델
class SadaguSimilarityData(BaseModel):
keyword: str = Field(
..., title="분석 키워드", description="유사도 분석에 사용된 키워드"
)
top_products: List[Dict] = Field(
default_factory=list,
title="선택된 상품들",
description="유사도 분석 결과 선택된 상위 상품 목록",
)
reason: Optional[str] = Field(
None, title="선택 이유", description="상품 선택 근거 및 점수 정보"
)
# 최종 응답 모델
class ResponseSadaguSimilarity(ResponseBase[SadaguSimilarityData]):
"""사다구 상품 유사도 분석 API 응답"""
pass
# ============== 사다구몰 크롤링 ==============
class RequestSadaguCrawl(RequestBase):
product_urls: List[HttpUrl] = Field(
..., title="상품 URL", description="크롤링할 상품 페이지의 URL"
)
# 응답 데이터 모델
class SadaguCrawlData(BaseModel):
crawled_products: List[Dict] = Field(
...,
title="크롤링된 상품들",
description="크롤링된 상품들의 상세 정보 목록 (URL 포함)",
)
success_count: int = Field(
..., title="성공 개수", description="성공적으로 크롤링된 상품 개수"
)
fail_count: int = Field(
..., title="실패 개수", description="크롤링에 실패한 상품 개수"
)
crawled_at: Optional[str] = Field(
None, title="크롤링 시간", description="크롤링 완료 시간"
)
# 최종 응답 모델
class ResponseSadaguCrawl(ResponseBase[SadaguCrawlData]):
"""사다구몰 크롤링 API 응답"""
pass
# ============== S3 업로드 ==============
class RequestS3Upload(RequestBase):
task_run_id: int = Field(..., title="Task Run ID", description="워크플로우 실행 ID")
keyword: str = Field(
..., title="검색 키워드", description="폴더명 생성용 키워드"
) # 추가
crawled_products: List[Dict] = Field(
...,
title="크롤링된 상품 데이터",
description="이전 단계에서 크롤링된 상품들의 데이터",
)
base_folder: Optional[str] = Field(
"product", title="기본 폴더", description="S3 내 기본 저장 폴더 경로"
)
# S3 업로드된 이미지 정보
class S3ImageInfo(BaseModel):
index: int = Field(..., title="이미지 순번", description="상품 내 이미지 순번")
original_url: str = Field(
..., title="원본 URL", description="크롤링된 원본 이미지 URL"
)
s3_url: str = Field(..., title="S3 URL", description="S3에서 접근 가능한 URL")
# 새로 추가: 파일 크기 정보 (이미지 선별용)
file_size_kb: Optional[float] = Field(
None, title="파일 크기(KB)", description="이미지 파일 크기"
)
file_name: Optional[str] = Field(
None, title="파일명", description="S3에 저장된 파일명"
)
# 상품별 S3 업로드 결과
class ProductS3UploadResult(BaseModel):
product_index: int = Field(..., title="상품 순번", description="크롤링 순번")
product_title: str = Field(..., title="상품 제목", description="상품명")
status: str = Field(..., title="업로드 상태", description="completed/skipped/error")
uploaded_images: List[S3ImageInfo] = Field(
default_factory=list, title="업로드 성공 이미지"
)
success_count: int = Field(
..., title="성공 개수", description="업로드 성공한 이미지 수"
)
fail_count: int = Field(
..., title="실패 개수", description="업로드 실패한 이미지 수"
)
# S3 업로드 요약 정보
class S3UploadSummary(BaseModel):
total_products: int = Field(
..., title="총 상품 수", description="처리 대상 상품 총 개수"
)
total_success_images: int = Field(
..., title="성공 이미지 수", description="업로드 성공한 이미지 총 개수"
)
total_fail_images: int = Field(
..., title="실패 이미지 수", description="업로드 실패한 이미지 총 개수"
)
# 응답 데이터 모델
class S3UploadData(BaseModel):
upload_results: List[ProductS3UploadResult] = Field(
..., title="업로드 결과", description="각 상품의 S3 업로드 결과"
)
summary: S3UploadSummary = Field(
..., title="업로드 요약", description="전체 업로드 결과 요약"
)
uploaded_at: str = Field(
..., title="업로드 완료 시간", description="S3 업로드 완료 시간"
)
# 최종 응답 모델
class ResponseS3Upload(ResponseBase[S3UploadData]):
"""S3 이미지 업로드 API 응답"""
pass
# ============== 상품 선택 (새로 추가) ==============
class RequestProductSelect(RequestBase):
task_run_id: int = Field(
..., title="Task Run ID", description="상품을 선택할 task_run_id"
)
selection_criteria: Optional[str] = Field(
None, title="선택 기준", description="특별한 선택 기준 (기본: 이미지 개수 우선)"
)
# 응답 데이터 모델
class ProductSelectData(BaseModel):
task_run_id: int = Field(..., title="Task Run ID")
selected_product: Dict = Field(
..., title="선택된 상품", description="콘텐츠 생성용으로 선택된 상품"
)
total_available_products: int = Field(
..., title="전체 상품 수", description="선택 가능했던 전체 상품 개수"
)
# 최종 응답 모델
class ResponseProductSelect(ResponseBase[ProductSelectData]):
"""상품 선택 API 응답"""
pass
# ============== 블로그 콘텐츠 생성 ==============
class RequestBlogCreate(RequestBase):
keyword: Optional[str] = Field(
None, title="키워드", description="콘텐츠 생성용 키워드"
)
translation_language: Optional[str] = Field(
None,
title="번역한 언어",
description="이미지에서 중국어를 한국어로 번역한 언어",
)
product_info: Optional[Dict] = Field(
None, title="상품 정보", description="블로그 콘텐츠에 포함할 상품 정보"
)
uploaded_images: Optional[List[Dict]] = Field(
None,
title="업로드된 이미지",
description="S3에 업로드된 이미지 목록 (크기 정보 포함)",
)
# 응답 데이터 모델
class BlogCreateData(BaseModel):
title: str = Field(..., title="블로그 제목", description="생성된 블로그 제목")
content: str = Field(..., title="블로그 내용", description="생성된 블로그 내용")
tags: List[str] = Field(
default_factory=list, title="추천 태그", description="콘텐츠에 적합한 태그 목록"
)
# 최종 응답 모델
class ResponseBlogCreate(ResponseBase[BlogCreateData]):
"""블로그 콘텐츠 생성 API 응답"""
pass
# ================== 이미지에서 텍스트 추출 및 번역 ==================
class RequestImageTextExtract(RequestBase):
keyword: Optional[str] = Field(
..., title="키워드", description="텍스트 추출용 키워드"
)
class ImageTextExtract(BaseModel):
keyword: Optional[str] = Field(
..., title="키워드", description="텍스트 추출용 키워드"
)
extraction_language: str = Field(
..., title="추출된 텍스트", description="이미지에서 추출된 텍스트"
)
translation_language: str = Field(
..., title="번역된 텍스트", description="추출된 텍스트의 번역본"
)
class ResponseImageTextExtract(ResponseBase[ImageTextExtract]):
pass
# ============== 블로그 배포 ==============
class RequestBlogPublish(RequestBase):
tag: str = Field(..., title="블로그 태그", description="블로그 플랫폼 종류")
blog_id: str = Field(..., description="블로그 아이디")
blog_pw: str = Field(..., description="블로그 비밀번호")
blog_name: Optional[str] = Field(None, description="블로그 이름")
post_title: str = Field(..., description="포스팅 제목")
post_content: str = Field(..., description="포스팅 내용")
post_tags: List[str] = Field(default_factory=list, description="포스팅 태그 목록")
# 응답 데이터 모델
class BlogPublishData(BaseModel):
tag: str = Field(..., title="블로그 태그", description="블로그 플랫폼 종류")
post_title: str = Field(..., title="포스팅 제목", description="배포된 포스팅 제목")
post_url: Optional[str] = Field(
None, title="포스팅 URL", description="배포된 포스팅 URL"
)
published_at: Optional[str] = Field(
None, title="배포 시간", description="포스팅 배포 완료 시간"
)
publish_success: bool = Field(..., title="배포 성공 여부")
# 디버깅 용 (Optional로 변경)
metadata: Optional[Dict[str, Any]] = Field(
None, description="포스팅 관련 메타데이터"
)
# 최종 응답 모델
class ResponseBlogPublish(ResponseBase[BlogPublishData]):
"""블로그 배포 API 응답"""
pass