py-aidol 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_aidol-0.2.0 → py_aidol-0.4.0}/PKG-INFO +24 -6
- {py_aidol-0.2.0 → py_aidol-0.4.0}/README.md +22 -5
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/api/aidol.py +68 -73
- py_aidol-0.4.0/aidol/api/common.py +72 -0
- py_aidol-0.4.0/aidol/api/companion.py +286 -0
- py_aidol-0.4.0/aidol/api/lead.py +123 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/factories.py +8 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/protocols.py +26 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/repositories/aidol_lead.py +3 -6
- py_aidol-0.4.0/aidol/services/companion_service.py +96 -0
- py_aidol-0.4.0/aidol/services/image_generation_service.py +112 -0
- py_aidol-0.4.0/aidol/settings.py +37 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/pyproject.toml +2 -1
- py_aidol-0.2.0/aidol/api/companion.py +0 -168
- py_aidol-0.2.0/aidol/services/image_generation_service.py +0 -145
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/__init__.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/api/__init__.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/models/__init__.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/models/aidol.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/models/aidol_lead.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/models/companion.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/py.typed +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/repositories/__init__.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/repositories/aidol.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/repositories/companion.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/schemas/__init__.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/schemas/aidol.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/schemas/aidol_lead.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/schemas/companion.py +0 -0
- {py_aidol-0.2.0 → py_aidol-0.4.0}/aidol/services/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: py-aidol
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Create and chat with your own AI idol group
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: kpop,idol,aidol,ai-companion,chatbot,image-generation
|
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Requires-Dist: aioia-core (>=2.2.0,<3.0.0)
|
|
16
16
|
Requires-Dist: fastapi (>=0.115.12,<0.116.0)
|
|
17
|
+
Requires-Dist: google-genai (>=1.60.0,<2.0.0)
|
|
17
18
|
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
18
19
|
Requires-Dist: openai (>=1.0.0)
|
|
19
20
|
Requires-Dist: pillow (>=10.0.0,<11.0.0)
|
|
@@ -33,7 +34,7 @@ AI 아이돌 그룹 생성 및 채팅 Python 패키지
|
|
|
33
34
|
## 주요 기능
|
|
34
35
|
|
|
35
36
|
- AI 아이돌 그룹/멤버 CRUD
|
|
36
|
-
-
|
|
37
|
+
- Google Gemini 이미지 생성 (엠블럼, 프로필)
|
|
37
38
|
- 텍스트 채팅 (페르소나 기반 응답)
|
|
38
39
|
- Buppy 통합 Adapter 패턴
|
|
39
40
|
|
|
@@ -61,7 +62,7 @@ from aidol.factories import AIdolRepositoryFactory, CompanionRepositoryFactory
|
|
|
61
62
|
# AIdol 라우터
|
|
62
63
|
aidol_router = AIdolRouter(
|
|
63
64
|
repository_factory=AIdolRepositoryFactory(),
|
|
64
|
-
|
|
65
|
+
google_settings=google_settings,
|
|
65
66
|
image_storage=image_storage,
|
|
66
67
|
)
|
|
67
68
|
|
|
@@ -86,11 +87,27 @@ make format
|
|
|
86
87
|
|
|
87
88
|
## 환경 변수
|
|
88
89
|
|
|
89
|
-
###
|
|
90
|
+
### 이미지 생성 인증 (선택, ADC 지원)
|
|
90
91
|
|
|
91
92
|
| 변수 | 설명 |
|
|
92
93
|
|------|------|
|
|
93
|
-
| `
|
|
94
|
+
| `GOOGLE_API_KEY` | Google API 키 (Google AI API) |
|
|
95
|
+
| `GOOGLE_CLOUD_PROJECT` | GCP 프로젝트 ID (Vertex AI) |
|
|
96
|
+
|
|
97
|
+
**인증 방법:**
|
|
98
|
+
|
|
99
|
+
**Option 1: Google AI API (API Key)**
|
|
100
|
+
```bash
|
|
101
|
+
export GOOGLE_API_KEY=your-api-key
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Option 2: Vertex AI (ADC)**
|
|
105
|
+
```bash
|
|
106
|
+
export GOOGLE_CLOUD_PROJECT=your-project-id
|
|
107
|
+
gcloud auth application-default login # 로컬 개발
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
> **참고**: Vertex AI 사용 시 `location=global`이 하드코딩되어 있습니다 (Gemini 이미지 생성 모델 요구사항).
|
|
94
111
|
|
|
95
112
|
### 선택
|
|
96
113
|
|
|
@@ -105,7 +122,8 @@ make format
|
|
|
105
122
|
|
|
106
123
|
- aioia-core (공통 인프라)
|
|
107
124
|
- FastAPI, SQLAlchemy, Pydantic
|
|
108
|
-
-
|
|
125
|
+
- Google Generative AI (이미지 생성)
|
|
126
|
+
- OpenAI (채팅)
|
|
109
127
|
- Pillow (이미지 처리)
|
|
110
128
|
|
|
111
129
|
## 라이선스
|
|
@@ -5,7 +5,7 @@ AI 아이돌 그룹 생성 및 채팅 Python 패키지
|
|
|
5
5
|
## 주요 기능
|
|
6
6
|
|
|
7
7
|
- AI 아이돌 그룹/멤버 CRUD
|
|
8
|
-
-
|
|
8
|
+
- Google Gemini 이미지 생성 (엠블럼, 프로필)
|
|
9
9
|
- 텍스트 채팅 (페르소나 기반 응답)
|
|
10
10
|
- Buppy 통합 Adapter 패턴
|
|
11
11
|
|
|
@@ -33,7 +33,7 @@ from aidol.factories import AIdolRepositoryFactory, CompanionRepositoryFactory
|
|
|
33
33
|
# AIdol 라우터
|
|
34
34
|
aidol_router = AIdolRouter(
|
|
35
35
|
repository_factory=AIdolRepositoryFactory(),
|
|
36
|
-
|
|
36
|
+
google_settings=google_settings,
|
|
37
37
|
image_storage=image_storage,
|
|
38
38
|
)
|
|
39
39
|
|
|
@@ -58,11 +58,27 @@ make format
|
|
|
58
58
|
|
|
59
59
|
## 환경 변수
|
|
60
60
|
|
|
61
|
-
###
|
|
61
|
+
### 이미지 생성 인증 (선택, ADC 지원)
|
|
62
62
|
|
|
63
63
|
| 변수 | 설명 |
|
|
64
64
|
|------|------|
|
|
65
|
-
| `
|
|
65
|
+
| `GOOGLE_API_KEY` | Google API 키 (Google AI API) |
|
|
66
|
+
| `GOOGLE_CLOUD_PROJECT` | GCP 프로젝트 ID (Vertex AI) |
|
|
67
|
+
|
|
68
|
+
**인증 방법:**
|
|
69
|
+
|
|
70
|
+
**Option 1: Google AI API (API Key)**
|
|
71
|
+
```bash
|
|
72
|
+
export GOOGLE_API_KEY=your-api-key
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Option 2: Vertex AI (ADC)**
|
|
76
|
+
```bash
|
|
77
|
+
export GOOGLE_CLOUD_PROJECT=your-project-id
|
|
78
|
+
gcloud auth application-default login # 로컬 개발
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **참고**: Vertex AI 사용 시 `location=global`이 하드코딩되어 있습니다 (Gemini 이미지 생성 모델 요구사항).
|
|
66
82
|
|
|
67
83
|
### 선택
|
|
68
84
|
|
|
@@ -77,7 +93,8 @@ make format
|
|
|
77
93
|
|
|
78
94
|
- aioia-core (공통 인프라)
|
|
79
95
|
- FastAPI, SQLAlchemy, Pydantic
|
|
80
|
-
-
|
|
96
|
+
- Google Generative AI (이미지 생성)
|
|
97
|
+
- OpenAI (채팅)
|
|
81
98
|
- Pillow (이미지 처리)
|
|
82
99
|
|
|
83
100
|
## 라이선스
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=duplicate-code
|
|
1
2
|
"""
|
|
2
3
|
AIdol API router
|
|
3
4
|
|
|
@@ -8,32 +9,25 @@ Public access pattern: no authentication required.
|
|
|
8
9
|
from aioia_core.auth import UserInfoProvider
|
|
9
10
|
from aioia_core.errors import ErrorResponse
|
|
10
11
|
from aioia_core.fastapi import BaseCrudRouter
|
|
11
|
-
from aioia_core.settings import JWTSettings
|
|
12
|
-
from fastapi import APIRouter, Depends, HTTPException, status
|
|
12
|
+
from aioia_core.settings import JWTSettings
|
|
13
|
+
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
|
13
14
|
from pydantic import BaseModel
|
|
14
15
|
from sqlalchemy.orm import sessionmaker
|
|
15
16
|
|
|
17
|
+
from aidol.api.common import register_image_generation_route
|
|
16
18
|
from aidol.protocols import (
|
|
17
19
|
AIdolRepositoryFactoryProtocol,
|
|
18
20
|
AIdolRepositoryProtocol,
|
|
19
21
|
ImageStorageProtocol,
|
|
20
22
|
)
|
|
21
|
-
from aidol.schemas import
|
|
22
|
-
|
|
23
|
-
AIdolCreate,
|
|
24
|
-
AIdolPublic,
|
|
25
|
-
AIdolUpdate,
|
|
26
|
-
ImageGenerationData,
|
|
27
|
-
ImageGenerationRequest,
|
|
28
|
-
ImageGenerationResponse,
|
|
29
|
-
)
|
|
30
|
-
from aidol.services import ImageGenerationService
|
|
23
|
+
from aidol.schemas import AIdol, AIdolCreate, AIdolPublic, AIdolUpdate
|
|
24
|
+
from aidol.settings import GoogleGenAISettings
|
|
31
25
|
|
|
32
26
|
|
|
33
|
-
class
|
|
34
|
-
"""
|
|
27
|
+
class AIdolCreateResponse(BaseModel):
|
|
28
|
+
"""Response for AIdol creation (only id)."""
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
id: str
|
|
37
31
|
|
|
38
32
|
|
|
39
33
|
class AIdolRouter(
|
|
@@ -48,49 +42,92 @@ class AIdolRouter(
|
|
|
48
42
|
|
|
49
43
|
def __init__(
|
|
50
44
|
self,
|
|
51
|
-
|
|
45
|
+
google_settings: GoogleGenAISettings | None,
|
|
52
46
|
image_storage: ImageStorageProtocol,
|
|
53
47
|
**kwargs,
|
|
54
48
|
):
|
|
55
|
-
|
|
56
|
-
self.openai_settings = openai_settings
|
|
49
|
+
self.google_settings = google_settings
|
|
57
50
|
self.image_storage = image_storage
|
|
51
|
+
super().__init__(**kwargs)
|
|
58
52
|
|
|
59
53
|
def _register_routes(self) -> None:
|
|
60
54
|
"""Register routes (public CRUD + image generation)"""
|
|
61
|
-
|
|
55
|
+
# Register shared image generation route
|
|
56
|
+
register_image_generation_route(
|
|
57
|
+
router=self.router,
|
|
58
|
+
resource_name=self.resource_name,
|
|
59
|
+
google_settings=self.google_settings,
|
|
60
|
+
image_storage=self.image_storage,
|
|
61
|
+
)
|
|
62
|
+
|
|
62
63
|
self._register_public_create_route()
|
|
63
64
|
self._register_public_get_route()
|
|
65
|
+
self._register_public_update_route()
|
|
66
|
+
|
|
67
|
+
def _register_public_update_route(self) -> None:
|
|
68
|
+
"""PATCH /{resource_name}/{id} - Update AIdol group (public)"""
|
|
69
|
+
|
|
70
|
+
@self.router.patch(
|
|
71
|
+
f"/{self.resource_name}/{{item_id}}",
|
|
72
|
+
response_model=AIdolPublic,
|
|
73
|
+
status_code=status.HTTP_200_OK,
|
|
74
|
+
summary="Update AIdol group",
|
|
75
|
+
description="Update AIdol group by ID (public endpoint). Returns updated AIdol data directly.",
|
|
76
|
+
responses={
|
|
77
|
+
404: {"model": ErrorResponse, "description": "AIdol group not found"},
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
async def update_aidol(
|
|
81
|
+
item_id: str,
|
|
82
|
+
data: AIdolUpdate,
|
|
83
|
+
repository: AIdolRepositoryProtocol = Depends(self.get_repository_dep),
|
|
84
|
+
):
|
|
85
|
+
"""Update AIdol group."""
|
|
86
|
+
# TODO: Verify ClaimToken if strict ownership is required (Sprint 1)
|
|
87
|
+
updated = repository.update(item_id, data)
|
|
88
|
+
if not updated:
|
|
89
|
+
raise HTTPException(
|
|
90
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
91
|
+
detail="AIdol group not found",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Return updated AIdol as public schema
|
|
95
|
+
return AIdolPublic(**updated.model_dump())
|
|
64
96
|
|
|
65
97
|
def _register_public_create_route(self) -> None:
|
|
66
98
|
"""POST /{resource_name} - Create an AIdol group (public)"""
|
|
67
99
|
|
|
68
100
|
@self.router.post(
|
|
69
101
|
f"/{self.resource_name}",
|
|
70
|
-
response_model=
|
|
102
|
+
response_model=AIdolCreateResponse,
|
|
71
103
|
status_code=status.HTTP_201_CREATED,
|
|
72
104
|
summary="Create AIdol group",
|
|
73
|
-
description="Create a new AIdol group (public endpoint)",
|
|
105
|
+
description="Create a new AIdol group (public endpoint). Returns only the created id.",
|
|
74
106
|
)
|
|
75
107
|
async def create_aidol(
|
|
76
108
|
request: AIdolCreate,
|
|
109
|
+
response: Response,
|
|
77
110
|
repository: AIdolRepositoryProtocol = Depends(self.get_repository_dep),
|
|
78
111
|
):
|
|
79
112
|
"""Create a new AIdol group."""
|
|
80
113
|
created = repository.create(request)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
114
|
+
|
|
115
|
+
# Set ClaimToken header
|
|
116
|
+
if created.claim_token:
|
|
117
|
+
response.headers["ClaimToken"] = created.claim_token
|
|
118
|
+
|
|
119
|
+
# Return only id
|
|
120
|
+
return AIdolCreateResponse(id=created.id)
|
|
84
121
|
|
|
85
122
|
def _register_public_get_route(self) -> None:
|
|
86
123
|
"""GET /{resource_name}/{id} - Get an AIdol group (public)"""
|
|
87
124
|
|
|
88
125
|
@self.router.get(
|
|
89
126
|
f"/{self.resource_name}/{{item_id}}",
|
|
90
|
-
response_model=
|
|
127
|
+
response_model=AIdolPublic,
|
|
91
128
|
status_code=status.HTTP_200_OK,
|
|
92
129
|
summary="Get AIdol group",
|
|
93
|
-
description="Get AIdol group by ID (public endpoint)",
|
|
130
|
+
description="Get AIdol group by ID (public endpoint). Returns AIdol data directly.",
|
|
94
131
|
responses={
|
|
95
132
|
404: {"model": ErrorResponse, "description": "AIdol group not found"},
|
|
96
133
|
},
|
|
@@ -101,54 +138,12 @@ class AIdolRouter(
|
|
|
101
138
|
):
|
|
102
139
|
"""Get AIdol group by ID."""
|
|
103
140
|
aidol = self._get_item_or_404(repository, item_id)
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
return AIdolSingleItemResponse(data=public_aidol)
|
|
107
|
-
|
|
108
|
-
def _register_image_generation_route(self) -> None:
|
|
109
|
-
"""POST /{resource_name}/images - Generate image for AIdol or Companion"""
|
|
110
|
-
|
|
111
|
-
@self.router.post(
|
|
112
|
-
f"/{self.resource_name}/images",
|
|
113
|
-
response_model=ImageGenerationResponse,
|
|
114
|
-
status_code=status.HTTP_201_CREATED,
|
|
115
|
-
summary="Generate image",
|
|
116
|
-
description="Generate image for AIdol emblem or Companion profile",
|
|
117
|
-
responses={
|
|
118
|
-
500: {"model": ErrorResponse, "description": "Image generation failed"},
|
|
119
|
-
},
|
|
120
|
-
)
|
|
121
|
-
async def generate_image(request: ImageGenerationRequest):
|
|
122
|
-
"""Generate image from prompt."""
|
|
123
|
-
# Generate and download image (TTS pattern: service returns data)
|
|
124
|
-
service = ImageGenerationService(self.openai_settings)
|
|
125
|
-
image = service.generate_and_download_image(
|
|
126
|
-
prompt=request.prompt,
|
|
127
|
-
size="1024x1024",
|
|
128
|
-
quality="standard",
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
if image is None:
|
|
132
|
-
raise HTTPException(
|
|
133
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
134
|
-
detail="Image generation failed",
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
# Upload to permanent storage (TTS pattern: API layer orchestrates)
|
|
138
|
-
image_url = self.image_storage.upload_image(image)
|
|
139
|
-
|
|
140
|
-
return ImageGenerationResponse(
|
|
141
|
-
data=ImageGenerationData(
|
|
142
|
-
image_url=image_url,
|
|
143
|
-
width=1024,
|
|
144
|
-
height=1024,
|
|
145
|
-
format="png",
|
|
146
|
-
)
|
|
147
|
-
)
|
|
141
|
+
# Return AIdol as public schema
|
|
142
|
+
return AIdolPublic(**aidol.model_dump())
|
|
148
143
|
|
|
149
144
|
|
|
150
145
|
def create_aidol_router(
|
|
151
|
-
|
|
146
|
+
google_settings: GoogleGenAISettings | None,
|
|
152
147
|
db_session_factory: sessionmaker,
|
|
153
148
|
repository_factory: AIdolRepositoryFactoryProtocol,
|
|
154
149
|
image_storage: ImageStorageProtocol,
|
|
@@ -161,7 +156,7 @@ def create_aidol_router(
|
|
|
161
156
|
Create AIdol router with dependency injection.
|
|
162
157
|
|
|
163
158
|
Args:
|
|
164
|
-
|
|
159
|
+
google_settings: Google API settings (uses ADC if api_key is None)
|
|
165
160
|
db_session_factory: Database session factory
|
|
166
161
|
repository_factory: Factory implementing AIdolRepositoryFactoryProtocol
|
|
167
162
|
image_storage: Image storage for permanent URLs
|
|
@@ -174,7 +169,7 @@ def create_aidol_router(
|
|
|
174
169
|
FastAPI APIRouter instance
|
|
175
170
|
"""
|
|
176
171
|
router = AIdolRouter(
|
|
177
|
-
|
|
172
|
+
google_settings=google_settings,
|
|
178
173
|
image_storage=image_storage,
|
|
179
174
|
model_class=AIdol,
|
|
180
175
|
create_schema=AIdolCreate,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Common API utilities.
|
|
3
|
+
|
|
4
|
+
Shared functions for registering common routes across different routers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from aioia_core.errors import ErrorResponse
|
|
8
|
+
from fastapi import APIRouter, HTTPException, status
|
|
9
|
+
|
|
10
|
+
from aidol.protocols import ImageStorageProtocol
|
|
11
|
+
from aidol.schemas import (
|
|
12
|
+
ImageGenerationData,
|
|
13
|
+
ImageGenerationRequest,
|
|
14
|
+
ImageGenerationResponse,
|
|
15
|
+
)
|
|
16
|
+
from aidol.services import ImageGenerationService
|
|
17
|
+
from aidol.settings import GoogleGenAISettings
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def register_image_generation_route(
|
|
21
|
+
router: APIRouter,
|
|
22
|
+
resource_name: str,
|
|
23
|
+
google_settings: GoogleGenAISettings | None,
|
|
24
|
+
image_storage: ImageStorageProtocol,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Register image generation route to the given router.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
router: FastAPI APIRouter instance
|
|
31
|
+
resource_name: Resource name for the route path
|
|
32
|
+
google_settings: Google API settings (API Key or Vertex AI with ADC)
|
|
33
|
+
image_storage: Image Storage instance
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@router.post(
|
|
37
|
+
f"/{resource_name}/images",
|
|
38
|
+
response_model=ImageGenerationResponse,
|
|
39
|
+
status_code=status.HTTP_201_CREATED,
|
|
40
|
+
summary="Generate image",
|
|
41
|
+
description=f"Generate image for {resource_name}",
|
|
42
|
+
responses={
|
|
43
|
+
500: {"model": ErrorResponse, "description": "Image generation failed"},
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
async def generate_image(request: ImageGenerationRequest):
|
|
47
|
+
"""Generate image from prompt."""
|
|
48
|
+
# Generate and download image
|
|
49
|
+
service = ImageGenerationService(settings=google_settings)
|
|
50
|
+
image = service.generate_and_download_image(
|
|
51
|
+
prompt=request.prompt,
|
|
52
|
+
size="1024x1024",
|
|
53
|
+
quality="standard",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if image is None:
|
|
57
|
+
raise HTTPException(
|
|
58
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
59
|
+
detail="Image generation failed",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Upload to permanent storage
|
|
63
|
+
image_url = image_storage.upload_image(image)
|
|
64
|
+
|
|
65
|
+
return ImageGenerationResponse(
|
|
66
|
+
data=ImageGenerationData(
|
|
67
|
+
image_url=image_url,
|
|
68
|
+
width=1024,
|
|
69
|
+
height=1024,
|
|
70
|
+
format="png",
|
|
71
|
+
)
|
|
72
|
+
)
|