feat: implement image generation service
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1,79 @@
|
||||
"""Image service placeholder."""
|
||||
import base64
|
||||
import os
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from google.genai import Client
|
||||
from app.config import settings
|
||||
|
||||
class ImageGenerationService:
|
||||
def __init__(self):
|
||||
self._client = None
|
||||
|
||||
@property
|
||||
def client(self) -> Client:
|
||||
if self._client is None:
|
||||
self._client = Client(api_key=settings.GEMINI_API_KEY)
|
||||
return self._client
|
||||
|
||||
async def generate_text2image(
|
||||
self,
|
||||
prompt: str,
|
||||
model: str = "gemini-2.5-flash"
|
||||
) -> dict:
|
||||
response = self.client.models.generate_content(
|
||||
model=model,
|
||||
contents=prompt,
|
||||
config={"response_modalities": ["TEXT", "IMAGE"]}
|
||||
)
|
||||
|
||||
image_data = None
|
||||
for part in response.parts:
|
||||
if hasattr(part, 'inline_data') and part.inline_data:
|
||||
image_data = base64.b64encode(part.inline_data.data).decode('utf-8')
|
||||
break
|
||||
|
||||
return {
|
||||
"image_b64": image_data,
|
||||
"model": model,
|
||||
"finish_reason": response.candidates[0].finish_reason if hasattr(response, 'candidates') and response.candidates else None
|
||||
}
|
||||
|
||||
async def generate_image2image(
|
||||
self,
|
||||
prompt: str,
|
||||
input_image_b64: str,
|
||||
input_mime_type: str = "image/png",
|
||||
model: str = "gemini-2.5-flash"
|
||||
) -> dict:
|
||||
response = self.client.models.generate_content(
|
||||
model=model,
|
||||
contents=[
|
||||
{"text": prompt},
|
||||
{"inline_data": {"mime_type": input_mime_type, "data": input_image_b64}}
|
||||
],
|
||||
config={"response_modalities": ["TEXT", "IMAGE"]}
|
||||
)
|
||||
|
||||
image_data = None
|
||||
for part in response.parts:
|
||||
if hasattr(part, 'inline_data') and part.inline_data:
|
||||
image_data = base64.b64encode(part.inline_data.data).decode('utf-8')
|
||||
break
|
||||
|
||||
return {
|
||||
"image_b64": image_data,
|
||||
"model": model,
|
||||
"finish_reason": response.candidates[0].finish_reason if hasattr(response, 'candidates') and response.candidates else None
|
||||
}
|
||||
|
||||
def save_image(self, image_b64: str, user_id: str) -> str:
|
||||
os.makedirs(settings.IMAGE_STORAGE_PATH, exist_ok=True)
|
||||
filename = f"{user_id}/{uuid.uuid4()}.png"
|
||||
filepath = os.path.join(settings.IMAGE_STORAGE_PATH, filename)
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
|
||||
image_data = base64.b64decode(image_b64)
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(image_data)
|
||||
|
||||
return f"/uploads/{filename}"
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
import pytest
|
||||
from app.services.image import ImageGenerationService
|
||||
|
||||
def test_generate_text2image_request_structure():
|
||||
# Test that the service creates proper request structure
|
||||
# This is a unit test - actual generation would require API key
|
||||
service = ImageGenerationService()
|
||||
# Just verify service initializes
|
||||
assert service is not None
|
||||
Reference in New Issue
Block a user