이미지 업로드 때 task_id 생성으로 변경, 가사 생성시 task_id 받아오는 것으로 변경
parent
f81d158f0f
commit
c6d9edbb42
|
|
@ -179,11 +179,11 @@ IMAGES_JSON_EXAMPLE = """[
|
|||
|
||||
|
||||
@router.post(
|
||||
"/image/upload/server/{task_id}",
|
||||
"/image/upload/server",
|
||||
include_in_schema=False,
|
||||
summary="이미지 업로드 (로컬 서버)",
|
||||
description="""
|
||||
task_id에 연결된 이미지를 로컬 서버(media 폴더)에 업로드합니다.
|
||||
이미지를 로컬 서버(media 폴더)에 업로드하고 새로운 task_id를 생성합니다.
|
||||
|
||||
## 요청 방식
|
||||
multipart/form-data 형식으로 전송합니다.
|
||||
|
|
@ -258,6 +258,10 @@ print(response.json())
|
|||
## 저장 경로
|
||||
- 바이너리 파일: /media/image/{날짜}/{uuid7}/{파일명}
|
||||
- URL 이미지: 외부 URL 그대로 Image 테이블에 저장
|
||||
|
||||
## 반환 정보
|
||||
- **task_id**: 새로 생성된 작업 고유 식별자
|
||||
- **image_urls**: Image 테이블에 저장된 현재 task_id의 이미지 URL 목록
|
||||
""",
|
||||
response_model=ImageUploadResponse,
|
||||
responses={
|
||||
|
|
@ -267,7 +271,6 @@ print(response.json())
|
|||
tags=["image"],
|
||||
)
|
||||
async def upload_images(
|
||||
task_id: str,
|
||||
images_json: Optional[str] = Form(
|
||||
default=None,
|
||||
description="외부 이미지 URL 목록 (JSON 문자열)",
|
||||
|
|
@ -279,6 +282,9 @@ async def upload_images(
|
|||
session: AsyncSession = Depends(get_session),
|
||||
) -> ImageUploadResponse:
|
||||
"""이미지 업로드 (URL + 바이너리 파일)"""
|
||||
# task_id 생성
|
||||
task_id = await generate_task_id()
|
||||
|
||||
# 1. 진입 검증: images_json 또는 files 중 하나는 반드시 있어야 함
|
||||
has_images_json = images_json is not None and images_json.strip() != ""
|
||||
has_files = files is not None and len(files) > 0
|
||||
|
|
@ -405,6 +411,9 @@ async def upload_images(
|
|||
saved_count = len(result_images)
|
||||
await session.commit()
|
||||
|
||||
# Image 테이블에서 현재 task_id의 이미지 URL 목록 조회
|
||||
image_urls = [img.img_url for img in result_images]
|
||||
|
||||
return ImageUploadResponse(
|
||||
task_id=task_id,
|
||||
total_count=len(result_images),
|
||||
|
|
@ -412,14 +421,15 @@ async def upload_images(
|
|||
file_count=len(valid_files),
|
||||
saved_count=saved_count,
|
||||
images=result_images,
|
||||
image_urls=image_urls,
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/image/upload/blob/{task_id}",
|
||||
"/image/upload/blob",
|
||||
summary="이미지 업로드 (Azure Blob Storage)",
|
||||
description="""
|
||||
task_id에 연결된 이미지를 Azure Blob Storage에 업로드합니다.
|
||||
이미지를 Azure Blob Storage에 업로드하고 새로운 task_id를 생성합니다.
|
||||
바이너리 파일은 로컬 서버에 저장하지 않고 Azure Blob에 직접 업로드됩니다.
|
||||
|
||||
## 요청 방식
|
||||
|
|
@ -447,24 +457,25 @@ jpg, jpeg, png, webp, heic, heif
|
|||
### cURL로 테스트
|
||||
```bash
|
||||
# 바이너리 파일만 업로드
|
||||
curl -X POST "http://localhost:8000/image/upload/blob/test-task-001" \\
|
||||
curl -X POST "http://localhost:8000/image/upload/blob" \\
|
||||
-F "files=@/path/to/image1.jpg" \\
|
||||
-F "files=@/path/to/image2.png"
|
||||
|
||||
# URL + 바이너리 파일 동시 업로드
|
||||
curl -X POST "http://localhost:8000/image/upload/blob/test-task-001" \\
|
||||
curl -X POST "http://localhost:8000/image/upload/blob" \\
|
||||
-F 'images_json=[{"url":"https://example.com/image.jpg"}]' \\
|
||||
-F "files=@/path/to/local_image.jpg"
|
||||
```
|
||||
|
||||
## 반환 정보
|
||||
- **task_id**: 작업 고유 식별자
|
||||
- **task_id**: 새로 생성된 작업 고유 식별자
|
||||
- **total_count**: 총 업로드된 이미지 개수
|
||||
- **url_count**: URL로 등록된 이미지 개수 (Image 테이블에 외부 URL 그대로 저장)
|
||||
- **file_count**: 파일로 업로드된 이미지 개수 (Azure Blob Storage에 저장)
|
||||
- **saved_count**: Image 테이블에 저장된 row 수
|
||||
- **images**: 업로드된 이미지 목록
|
||||
- **source**: "url" (외부 URL) 또는 "blob" (Azure Blob Storage)
|
||||
- **image_urls**: Image 테이블에 저장된 현재 task_id의 이미지 URL 목록
|
||||
|
||||
## 저장 경로
|
||||
- 바이너리 파일: Azure Blob Storage ({BASE_URL}/{task_id}/image/{파일명})
|
||||
|
|
@ -478,7 +489,6 @@ curl -X POST "http://localhost:8000/image/upload/blob/test-task-001" \\
|
|||
tags=["image"],
|
||||
)
|
||||
async def upload_images_blob(
|
||||
task_id: str,
|
||||
images_json: Optional[str] = Form(
|
||||
default=None,
|
||||
description="외부 이미지 URL 목록 (JSON 문자열)",
|
||||
|
|
@ -490,6 +500,9 @@ async def upload_images_blob(
|
|||
session: AsyncSession = Depends(get_session),
|
||||
) -> ImageUploadResponse:
|
||||
"""이미지 업로드 (URL + Azure Blob Storage)"""
|
||||
# task_id 생성
|
||||
task_id = await generate_task_id()
|
||||
|
||||
# 1. 진입 검증
|
||||
has_images_json = images_json is not None and images_json.strip() != ""
|
||||
has_files = files is not None and len(files) > 0
|
||||
|
|
@ -609,6 +622,9 @@ async def upload_images_blob(
|
|||
saved_count = len(result_images)
|
||||
await session.commit()
|
||||
|
||||
# Image 테이블에서 현재 task_id의 이미지 URL 목록 조회
|
||||
image_urls = [img.img_url for img in result_images]
|
||||
|
||||
return ImageUploadResponse(
|
||||
task_id=task_id,
|
||||
total_count=len(result_images),
|
||||
|
|
@ -616,4 +632,5 @@ async def upload_images_blob(
|
|||
file_count=len(valid_files) - len(skipped_files),
|
||||
saved_count=saved_count,
|
||||
images=result_images,
|
||||
image_urls=image_urls,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -211,9 +211,50 @@ class ImageUploadResultItem(BaseModel):
|
|||
class ImageUploadResponse(BaseModel):
|
||||
"""이미지 업로드 응답 스키마"""
|
||||
|
||||
task_id: str = Field(..., description="작업 고유 식별자")
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"total_count": 3,
|
||||
"url_count": 2,
|
||||
"file_count": 1,
|
||||
"saved_count": 3,
|
||||
"images": [
|
||||
{
|
||||
"id": 1,
|
||||
"img_name": "외관",
|
||||
"img_url": "https://example.com/images/image_001.jpg",
|
||||
"img_order": 0,
|
||||
"source": "url",
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"img_name": "내부",
|
||||
"img_url": "https://example.com/images/image_002.jpg",
|
||||
"img_order": 1,
|
||||
"source": "url",
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"img_name": "uploaded_image.jpg",
|
||||
"img_url": "/media/image/2024-01-15/0694b716-dbff-7219-8000-d08cb5fce431/uploaded_image_002.jpg",
|
||||
"img_order": 2,
|
||||
"source": "file",
|
||||
},
|
||||
],
|
||||
"image_urls": [
|
||||
"https://example.com/images/image_001.jpg",
|
||||
"https://example.com/images/image_002.jpg",
|
||||
"/media/image/2024-01-15/0694b716-dbff-7219-8000-d08cb5fce431/uploaded_image_002.jpg",
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
task_id: str = Field(..., description="작업 고유 식별자 (새로 생성된 UUID7)")
|
||||
total_count: int = Field(..., description="총 업로드된 이미지 개수")
|
||||
url_count: int = Field(..., description="URL로 등록된 이미지 개수")
|
||||
file_count: int = Field(..., description="파일로 업로드된 이미지 개수")
|
||||
saved_count: int = Field(..., description="Image 테이블에 저장된 row 수")
|
||||
images: list[ImageUploadResultItem] = Field(..., description="업로드된 이미지 목록")
|
||||
image_urls: list[str] = Field(..., description="Image 테이블에 저장된 현재 task_id의 이미지 URL 목록")
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ from app.lyric.schemas.lyric import (
|
|||
LyricStatusResponse,
|
||||
)
|
||||
from app.utils.chatgpt_prompt import ChatgptService
|
||||
from app.utils.common import generate_task_id
|
||||
from app.utils.pagination import PaginatedResponse, get_paginated
|
||||
|
||||
router = APIRouter(prefix="/lyric", tags=["lyric"])
|
||||
|
|
@ -159,6 +158,7 @@ async def get_lyric_by_task_id(
|
|||
고객 정보를 기반으로 ChatGPT를 이용하여 가사를 생성합니다.
|
||||
|
||||
## 요청 필드
|
||||
- **task_id**: 작업 고유 식별자 (이미지 업로드 시 생성된 task_id, 필수)
|
||||
- **customer_name**: 고객명/가게명 (필수)
|
||||
- **region**: 지역명 (필수)
|
||||
- **detail_region_info**: 상세 지역 정보 (선택)
|
||||
|
|
@ -180,6 +180,7 @@ async def get_lyric_by_task_id(
|
|||
```
|
||||
POST /lyric/generate
|
||||
{
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"customer_name": "스테이 머뭄",
|
||||
"region": "군산",
|
||||
"detail_region_info": "군산 신흥동 말랭이 마을",
|
||||
|
|
@ -220,9 +221,10 @@ async def generate_lyric(
|
|||
session: AsyncSession = Depends(get_session),
|
||||
) -> GenerateLyricResponse:
|
||||
"""고객 정보를 기반으로 가사를 생성합니다."""
|
||||
task_id = await generate_task_id(session=session, table_name=Project)
|
||||
task_id = request_body.task_id
|
||||
print(
|
||||
f"[generate_lyric] START - task_id: {task_id}, customer_name: {request_body.customer_name}, region: {request_body.region}"
|
||||
f"[generate_lyric] START - task_id: {task_id}, "
|
||||
f"customer_name: {request_body.customer_name}, region: {request_body.region}"
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Lyric API Schemas
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class GenerateLyricRequest(BaseModel):
|
||||
|
|
@ -37,6 +37,7 @@ class GenerateLyricRequest(BaseModel):
|
|||
|
||||
Example Request:
|
||||
{
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"customer_name": "스테이 머뭄",
|
||||
"region": "군산",
|
||||
"detail_region_info": "군산 신흥동 말랭이 마을",
|
||||
|
|
@ -44,17 +45,21 @@ class GenerateLyricRequest(BaseModel):
|
|||
}
|
||||
"""
|
||||
|
||||
model_config = {
|
||||
"json_schema_extra": {
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"customer_name": "스테이 머뭄",
|
||||
"region": "군산",
|
||||
"detail_region_info": "군산 신흥동 말랭이 마을",
|
||||
"language": "Korean",
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
task_id: str = Field(
|
||||
..., description="작업 고유 식별자 (이미지 업로드 시 생성된 task_id)"
|
||||
)
|
||||
customer_name: str = Field(..., description="고객명/가게명")
|
||||
region: str = Field(..., description="지역명")
|
||||
detail_region_info: Optional[str] = Field(None, description="상세 지역 정보")
|
||||
|
|
@ -76,26 +81,20 @@ class GenerateLyricResponse(BaseModel):
|
|||
- ChatGPT API 오류
|
||||
- ChatGPT 거부 응답 (I'm sorry, I cannot, I can't, I apologize 등)
|
||||
- 응답에 ERROR: 포함
|
||||
|
||||
Example Response (Success):
|
||||
{
|
||||
"success": true,
|
||||
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
|
||||
"lyric": "인스타 감성의 스테이 머뭄...",
|
||||
"language": "Korean",
|
||||
"error_message": null
|
||||
}
|
||||
|
||||
Example Response (Failure):
|
||||
{
|
||||
"success": false,
|
||||
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
|
||||
"lyric": null,
|
||||
"language": "Korean",
|
||||
"error_message": "I'm sorry, I can't comply with that request."
|
||||
}
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"success": True,
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"lyric": "인스타 감성의 스테이 머뭄\n군산 신흥동 말랭이 마을에서\n여유로운 하루를 보내며\n추억을 만들어가요",
|
||||
"language": "Korean",
|
||||
"error_message": None,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
success: bool = Field(..., description="생성 성공 여부")
|
||||
task_id: Optional[str] = Field(None, description="작업 고유 식별자 (uuid7)")
|
||||
lyric: Optional[str] = Field(None, description="생성된 가사 (성공 시)")
|
||||
|
|
@ -109,15 +108,18 @@ class LyricStatusResponse(BaseModel):
|
|||
Usage:
|
||||
GET /lyric/status/{task_id}
|
||||
Returns the current processing status of a lyric generation task.
|
||||
|
||||
Example Response:
|
||||
{
|
||||
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
|
||||
"status": "completed",
|
||||
"message": "가사 생성이 완료되었습니다."
|
||||
}
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"status": "completed",
|
||||
"message": "가사 생성이 완료되었습니다.",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
task_id: str = Field(..., description="작업 고유 식별자")
|
||||
status: str = Field(..., description="처리 상태 (processing, completed, failed)")
|
||||
message: str = Field(..., description="상태 메시지")
|
||||
|
|
@ -129,19 +131,22 @@ class LyricDetailResponse(BaseModel):
|
|||
Usage:
|
||||
GET /lyric/{task_id}
|
||||
Returns the generated lyric content for a specific task.
|
||||
|
||||
Example Response:
|
||||
{
|
||||
"id": 1,
|
||||
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
|
||||
"project_id": 1,
|
||||
"status": "completed",
|
||||
"lyric_prompt": "...",
|
||||
"lyric_result": "생성된 가사...",
|
||||
"created_at": "2024-01-01T12:00:00"
|
||||
}
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"id": 1,
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"project_id": 1,
|
||||
"status": "completed",
|
||||
"lyric_prompt": "고객명: 스테이 머뭄, 지역: 군산...",
|
||||
"lyric_result": "인스타 감성의 스테이 머뭄\n군산 신흥동 말랭이 마을에서\n여유로운 하루를 보내며\n추억을 만들어가요",
|
||||
"created_at": "2024-01-15T12:00:00",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
id: int = Field(..., description="가사 ID")
|
||||
task_id: str = Field(..., description="작업 고유 식별자")
|
||||
project_id: int = Field(..., description="프로젝트 ID")
|
||||
|
|
@ -158,6 +163,18 @@ class LyricListItem(BaseModel):
|
|||
Used as individual items in paginated lyric list responses.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"id": 1,
|
||||
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
|
||||
"status": "completed",
|
||||
"lyric_result": "인스타 감성의 스테이 머뭄\n군산 신흥동 말랭이 마을에서...",
|
||||
"created_at": "2024-01-15T12:00:00",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
id: int = Field(..., description="가사 ID")
|
||||
task_id: str = Field(..., description="작업 고유 식별자")
|
||||
status: str = Field(..., description="처리 상태")
|
||||
|
|
|
|||
Loading…
Reference in New Issue