기본 프롬프트
Develop a service based on the concepts and details outlined in the attached text.
Focus on integrating the core features and specifications provided.
Markdown
복사
아래의 요구사항에 따라 기능을 수정해줘.
1.
2.
Markdown
복사
아래의 요구사항에 따라 기능을 수정해줘.
1. 첫 화면의 애니메이션의 지속시간은 3초로 해주고 이후에 노란 픽셀 뭉치가 완전히 사라지게 해줘.
2. 첫 화면에서 노란 픽셀 뭉치가 완전히 사라지는 시점에 문구 및 입력창이 등장하도록 타이밍을 조정해줘.
Markdown
복사
아래의 요구사항에 따라 기능을 수정해줘.
1. 첫화면에 발생하는 픽셀 애니메이션 효과는 단 한번만 발생하도록 해줘.
2. 첫화면에서 발생하는 픽셀 애니메이션 효과로 인해 정중앙에 생긴 픽셀의 모음이 사라지고나서 그 자리에 동그란 'pixelize' 문구의 버튼이 위치하게 수정해줘.
3. 동그란 'pixelize' 문구의 버튼이 화면 정중앙에 위치하기 때문에 문구와 입력창의 위치를 전체적인 UI/UX에 맞게 재조정해줘.
Markdown
복사
아래의 프롬프트를 자연스러운 영어로 번역해줘.
Markdown
복사
아래의 프롬프트를 통해 vercel v0에서 서비스를 구현할 예정인데, 네가 스티브잡스와 조니악의 관점에서 UI/UX를 개선해줘.
Markdown
복사
GEMINI_API_KEY
Markdown
복사
내거
AIzaSyCnl63EBb_uYggwBGP2JiLQDbyew-3PQrY
Markdown
복사
아닌거
AIzaSyDeZU6alP2BdGFos-v-eCwUPcMOjqDrCaU
Markdown
복사
https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent
Markdown
복사
이모티콘 프롬프트
Please create a "Pixel Transition Emoticon Generator".
## Core Features:
### Stage 1 - The First Screen (Invitation & Inspiration)
* Black background (#000000).
* IMPORTANT: On page load, 1500 yellow pixels slowly converge from the edges of the screen to the center over 3 seconds.
* IMPORTANT: The pixels gather to form a circular 'Pixelize' button in the exact center of the screen.
* IMPORTANT: Pixcel and effect should be big and active effect enough to catch attention.
* Display the main phrase "Emoticon, in pixels." at the top.
* Display small size phrase "Type 3–5 words to create pixel emoticons" under the main phrase.
* Place a single, medium text input field above the button.
* Placeholder text: e.g., 운동하는 귀염둥이 호랑이 천사
* IMPORTANT: All UI elements should appear together after the pixel convergence animation is complete.
* IMPORTANT: All UI elements color style should be fit.
### Stage 2 - The Second Screen (Creation & Result)
* When the 'Pixelize' button is clicked, trigger an animation where 1500 yellow pixels explode outwards from the center over 6v seconds, accompanied by an 8-bit 'blip' sound effect and subtle haptic feedback on mobile devices.
* Maintain the black background.
* While the image is being generated, 1000 yellow pixels act as a loading animation. this animation should be active.
* While being generated, no dispaly the phrase. only animaition or effect should express loading.
* Use the Google Gemini API to generate emoticons based on the three input words.
* Once generation is complete, display the resulting image. Below it, show a [Download] button and a [Create New] button.
## Google Gemini API Setup:
### API Endpoint (/api/generate-emoticon):
* Environment Variable: Use GEMINI_API_KEY. I will set it after finishing implementation by myself.
* Use the gemini model & request url: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent
* Convert 5 reference images to base64 and send them with the request:
* https://mjbae.github.io/emoticon-sheets/pixel/1.png
* https://mjbae.github.io/emoticon-sheets/pixel/2.png
* https://mjbae.github.io/emoticon-sheets/pixel/3.png
* https://mjbae.github.io/emoticon-sheets/pixel/4.png
* https://mjbae.github.io/emoticon-sheets/pixel/5.png
### Image Generation Requirements:
* A single image containing 12 emoticons in a 4x3 grid.
* A pixel art style with prominent, well-defined pixels.
* A black background (#000000) is mandatory.
* no text in emoticons.
* Emoticons with diverse expressions and emotions that reflect the three input words.
* Maintain the same style as the reference images.
### Technical Details:
* Implement pixel animations using the Canvas API.
* Ensure smooth animation for 1500 pixels using requestAnimationFrame.
* Randomize pixel delay times to create a natural convergence/dispersion effect.
* Responsive design (for mobile and desktop).
* Utilize the Kakao Design System color palette (Yellow: #FEE500).
* Use TypeScript.
### UI/UX Requirements:
* A minimal interface with a touch of magic and intuition.
* A unified dark theme with a black background.
* Consistent use of yellow as a point color.
* Delightful feedback (visual, auditory, haptic) that responds instantly to user actions.
* An intelligent loading state animation that is visually connected to the user's input.
* A single-input system that minimizes the user's cognitive load.
Markdown
복사
이모티콘 프롬프트 2
# Create a "Pixel Emoticon Forge"
With the following exact specifications, focusing on an immediate, interactive, and seamless user experience.
## CORE FUNCTIONALITY
Build a 3-stage interactive web app that lets users craft pixel art emoticons using Google Gemini AI. The experience should be fluid, with no hard stops or disconnected loading screens.
### Stage 1 - The Interactive Canvas & Word Weaving
- On page load, immediately display the UI. No loading animation or artificial delay.
- UI:
- Main title: "Emoticon, in pixels." (yellow pixel-style font)
- Text input field (placeholder: "운동하는 귀염둥이 호랑이 천사"), input field and placeholder both should be center aligned
- Background:
- Full-screen pure black canvas
- 1500 ambiently floating yellow (#FEE500) pixels
- Interactive Pixel Universe:
- Subtle, slow, random drift
- Mouse Magnetism: Pixels within a 150px radius of the cursor are gently pulled towards it (stirring-the-stars effect).
- Click Ripple: Single click creates ripple pushing pixels away.
- Pixel-Word Formation:
- As user types, nearby pixels fly up to form words around the input field in real time.
- Pixelize Button:
- Present but disabled until at least one word is entered.
### Stage 2 - Creative Fusion (The "Loading" Experience)
- On click of Pixelize:
- Play an 8-bit blip sound
- Provide haptic feedback
- Pixel-word dissolve:
- Words dissolve and flow into a swirling vortex at screen center.
- Vortex animation:
- Yellow pixels swirl, new vibrant colors (reds, blues, greens) emerge.
### Stage 3 - The Living Galler
- After generation, vortex fades out → reveals 4x3 grid (12 emoticons).
- Icon Actions:
- Below grid, only 2 icon buttons without words:
- down arrow → save grid as PNG
- redo arrow → restart (smooth transition back to input)
- Error Handling:
- Show clear message + retry icon if AI generation fails.
## TECHNICAL REQUIREMENTS
### Frontend (Next.js App Router)
- TypeScript with strict typing
- Canvas-based pixel animation (1500 pixels, word formation, vortex)
- Custom useMousePosition hook
- Fully responsive, mobile-optimized
- image-rendering: pixelated for all pixel art
- Web Audio API for sound
- Smooth, physics-based animations with easing
### API Endpoint (/api/generate-emoticon):
* Environment Variable: Use GEMINI_API_KEY, I will set it after finishing implementation by myself.
* (Improvement) The string from the single input field should be parsed by spaces to extract the three words before sending them to the API.
* Use the gemini model & request url: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent
* Convert 5 reference images to base64 and send them with the request:
* https://mjbae.github.io/emoticon-sheets/pixel/1.png
* https://mjbae.github.io/emoticon-sheets/pixel/2.png
* https://mjbae.github.io/emoticon-sheets/pixel/3.png
* https://mjbae.github.io/emoticon-sheets/pixel/4.png
* https://mjbae.github.io/emoticon-sheets/pixel/5.png
### Image Generation Requirements:
* A single image containing 12 emoticons in a 4x3 grid.
* A pixel art style with prominent, well-defined pixels.
* A black background (#000000) is mandatory.
* Emoticons with diverse expressions and emotions that reflect the three input words.
* Maintain the same style as the reference images.
### STYLING & DESIGN
- Background: pure black #000000
- Primary accent: yellow #FEE500
- Monospace font family
- Aesthetic: fluid, magical creation (not explosions)
- Visual motifs:
- Interactive pixel sea
- Words woven from light
- Creative vortex
- Living gallery
- Soft glow effects for hovered/active pixels
## ANIMATION DETAILS
- Interactive Pixel Universe: Gentle drift + responsive magnetism + ripple effects
- Pixel-Word Formation: Smooth, non-linear pixel paths forming letters
- Creative Fusion: 6s vortex dissolve animation (with color emergence)
- Reveal Transition: Smooth cross-fade from vortex → results grid
- Idle Animation: Subtle, non-distracting loops for emoticons
Markdown
복사
동화책 창작 프롬프트 1
Create an “Kid Storybook Crafter”
With the following exact specifications, focusing on an immediate, magical yet simple but visually engaging user experience that feels delightful and inspiring.
The app should be production-ready in a Next.js (App Router) + TypeScript environment.
## CORE FUNCTIONALITY
Build a 3-stage interactive web app that helps users create a short illustrated children’s storybook from a single idea.
The design should combine Jobs’ simplicity with Wozniak’s playful delight — minimal UI, but with warm, immersive details.
## Stage 1 — Spark (Inspiration & Input)
- On page load, show the UI immediately. No loading splash.
- **UI**:
- Centered title: “이야기를 들려주세요”
- Style: handwritten-like serif, gentle glowing gradient (lavender → soft yellow).
- Subtext: “단 하나의 아이디어로 충분합니다.” (faded ink effect).
- Input area:
- Multiline input box with rounded edges, light paper-texture background.
- Placeholder: “수줍은 토끼가 반짝이는 달꽃을 발견했어요…”
- Toggle buttons (pill-shaped with icons):
- Age: “3–4세” / “5–7세” / “8–10세”
(each button has a small star, balloon, or book icon).
- Tone: “잔잔한” / “모험적인” / “재미있는”
(emoji-style icons: 🌙 / 🗺️ / 😄).
- Style: “수채화” / “크레용” / “종이 오려내기”
(background color of button subtly reflects the style).
- Primary button: “이야기 시작하기” (large, rounded, gradient fill: soft pink → peach).
- **Delight**:
- As user types, tiny glowing particles float upwards and fade (storybook sparks).
- Button reveal: soft fade-in with slight scale-up.
- Progress bar (top, thin line): “개요 작성 → 페이지 생성 → 삽화 추가” with animated dots.
## Stage 2 — Story Outline (Draft Pages)
- **Layout**: storybook planner view with warm off-white background.
- **Each page block**:
- Header: “페이지 {n}” (soft colored ribbon).
- Page text inside a rounded card with faint shadow.
- Below text, smaller muted prompt text.
- **Actions**:
- Inline edit on click (input appears with a soft glow).
- ↻ icon: rotate on hover before regen.
- Lock checkbox: stylized as a small padlock icon.
- **Sticky footer bar**:
- Primary: “삽화 만들기” (vibrant gradient button).
- Secondary: “개요 수정하기” (outlined button).
- Subtle page-divider animation: cards appear with slide-up + fade.
## Stage 3 — Living Storybook (Illustrated Mode)
- **Fullscreen reading mode**:
- Background: subtle gradient (ivory → pale pastel) for cozy feel.
- Page container: soft drop-shadow, slightly rounded edges like a book.
- Page text (top): Cute Korean font, larger size with high line spacing, dark gray.
- Illustration (below text): fades in with shimmer.
- **Navigation**:
- Swipe or arrows.
- Bottom: page dots (colored pastel circles).
- **Top bar**:
- Title (editable inline).
- **Animation**:
- Page turn = soft slide + slight rotation (not skeuomorphic).
- New illustration = shimmer → crossfade.
## TECHNICAL REQUIREMENTS
- Next.js App Router + TypeScript.
- Tailwind CSS + shadcn/ui.
- Fully responsive; mobile-optimized.
- Typography: rounded serif for headings, clean sans for body.
- Autosave to localStorage.
**API**
- `/api/generate-story` → Text model: gemini-2.0-flash.
- `/api/generate-illustration` → Image model: gemini-2.5-flash-image-preview:generateContent.
- Prompt template for image:
`“{style} children’s storybook illustration, {characterTokens}, scene: {pagePrompt}.”`
## ANIMATION DETAILS
- Typing sparks (CSS + opacity).
- Button reveal: fade + slight scale.
- Page cards: slide-up fade-in.
- Page turn: soft slide+rotation; cross-fade if reduced-motion.
- Image load: shimmer placeholder → crossfade.
## ACCEPTANCE CHECKLIST
- Stage 1: Inputs styled with icons, gradients, sparks.
- Outline pages show in warm card UI, edit/regenerate intuitive.
- Illustrated mode feels cozy, immersive, readable.
- Errors: gentle toasts with retry.
Markdown
복사
동화책 창작 프롬프트 2 - V0
Create a 3-stage interactive web application that transforms a single story idea into a beautifully illustrated children's storybook using AI.
### **Core User Flow**
1. **Stage 1 (Spark)**: User inputs story idea with customization options
2. **Stage 2 (Outline)**: User reviews and edits generated story pages, not illustration card but generated story card.
3. **Stage 3 (Living Storybook)**: User reads the complete illustrated storybook
### **Stage 1: Spark Input Form**
**Layout & Design:**
- Centered card layout with magical gradient background (lavender to pink to peach)
- Animated sparkle particles floating across the screen
- Korean text throughout the interface with Noto Sans KR font
- Title: "✨ 이야기의 씨앗을 심어보세요" (Plant the seed of your story)
**Input Components:**
- Large textarea with placeholder: "정직하고 용감한 토끼가 귀염둥이 행성으로 모험을 떠나는 이야기"
- Character limit: 500 characters with live counter
- Gradient text effect on focus
**Customization Toggles (3 rows):**
- **연령대 (Age Group)**: 3-5세, 6-8세, 9-12세 (with child icons)
- **톤 (Tone)**: 재미있게, 따뜻하게, 모험적으로 (with emotion icons)
- **스타일 (Style)**: 동화책, 만화책, 사실적 (with book icons)
**Interactive Elements:**
- Hover effects on all toggles with scale and glow
- Submit button with shimmer animation: "이야기 만들기 시작!"
- Progress bar appears during generation (0-100%)
- Loading states with rotating sparkles
### **Stage 2: Story Outline Editor**
**Layout:**
- Header with story title (editable) and "다음 단계로" button
- Grid of story page cards (2-3 columns responsive)
- Each page shows: page number, text content, illustration placeholder
**Page Card Features:**
- Staggered slide-in animations (100ms delays)
- Inline text editing with save/cancel buttons
- Lock/unlock toggle to prevent regeneration
- Individual "다시 생성" (regenerate) button per page
- Visual feedback: locked pages have golden border
- Hover effects with subtle lift and shadow
**Interactions:**
- Click to edit page text inline
- Drag to reorder pages (optional enhancement)
- Bulk actions: "모든 페이지 다시 생성"
- Auto-save to localStorage every 2 seconds
### **Stage 3: Living Storybook Reader**
**Reading Interface:**
- Full-screen immersive reading mode
- Large illustration area (60% of screen height)
- Text below illustration with large, readable Korean font
- Subtle paper texture background
**Navigation:**
- Previous/Next arrow buttons (large, accessible)
- Page indicator dots at bottom
- Keyboard support: arrow keys, spacebar
- Touch/swipe gestures for mobile
- Smooth page transition animations (slide effect)
**Header Controls:**
- Story title display
- "처음부터 다시" button to restart process
- Reading progress indicator
**Illustration Loading:**
- Shimmer placeholder while generating
- Fade-in animation when loaded
- Fallback to colorful placeholder if generation fails
### **Technical Architecture**
**Frontend Stack:**
- Next.js 14+ App Router with TypeScript
- Tailwind CSS v4 with custom design tokens
- shadcn/ui components as base
- React Context for storybook state management
- localStorage for auto-save functionality
**API Endpoints:**
```plaintext
POST /api/generate-story
- Input: { idea, ageGroup, tone, style }
- Output: { title, pages: [{ pageNumber, text, imagePrompt }] }
POST /api/generate-illustrations
- Input: { pages: [{ text, imagePrompt }] }
- Output: { illustrations: [{ pageNumber, imageUrl }] }
POST /api/regenerate-page
- Input: { pageNumber, currentText, settings }
- Output: { text, imagePrompt, imageUrl }
```
**AI Integration:**
- IMPORTANT: Google Gemini API for story generation
- IMPORTANT: Gemini 2.5 Flash Image Preview for illustrations
- IMPORTANT: no text in illustrations
- IMPORTANT: To maintain overall consistency, you should first create a key visual for the main character. Then, use this key visual image to generate the characters that appear in the illustrations.
- IMPORTANT: When creating a key visual, a detailed description of the character's appearance, including clothing and colors, is required. This description should be used to create a consistent character throughout subsequent illustrations.
- VERY IMPORTANT: every time, illustrations generating, the key visual should be send so that consistent character is generated.
- Korean language prompts and responses
- Proper error handling and fallbacks
### **Design System**
**Colors:**
- Primary: Lavender (`#E6E6FA`) to Pink (`#FFB6C1`) to Peach (`#FFCBA4`) gradients
- Neutrals: White, warm grays, soft blacks
- Accents: Golden yellow for locks, soft blue for actions
- Background: Subtle paper texture with warm tint
**Typography:**
- Headings: Noto Sans KR Bold (24px, 32px, 40px)
- Body: Noto Sans KR Regular (16px, 18px)
- Reading text: Noto Sans KR Medium (20px) with 1.6 line height
- Korean character optimization throughout
**Animations:**
- Sparkle particles: continuous floating motion
- Page transitions: smooth slide effects (300ms)
- Button interactions: scale + glow on hover
- Loading states: shimmer, pulse, rotation effects
- Staggered reveals: 100ms delays for card grids
**Responsive Design:**
- Mobile-first approach
- Touch-friendly button sizes (44px minimum)
- Swipe gestures for story navigation
- Collapsible layouts for small screens
- Optimized Korean text rendering
### **Key Features**
**User Experience:**
- Seamless 3-stage progression
- Auto-save prevents data loss
- Immediate visual feedback
- Accessible keyboard navigation
- Error states with helpful messages
**Content Generation:**
- Age-appropriate story content
- Consistent illustration style
- Korean cultural context awareness
- Individual page regeneration
- Bulk regeneration options
**Performance:**
- Optimistic UI updates
- Image lazy loading
- Efficient state management
- Minimal re-renders
- Fast page transitions
JavaScript
복사
이모티콘 라우트
Refer to the working route.ts from another project below to resolve this issue.
JavaScript
복사
import { type NextRequest, NextResponse } from "next/server"
const GEMINI_API_KEY = process.env.GEMINI_API_KEY
const GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent"
// Reference images to convert to base64
const REFERENCE_IMAGES = [
"https://mjbae.github.io/emoticon-sheets/pixel/1.png",
"https://mjbae.github.io/emoticon-sheets/pixel/2.png",
"https://mjbae.github.io/emoticon-sheets/pixel/3.png",
"https://mjbae.github.io/emoticon-sheets/pixel/4.png",
"https://mjbae.github.io/emoticon-sheets/pixel/5.png",
]
async function imageToBase64(url: string): Promise<string> {
try {
const response = await fetch(url)
const arrayBuffer = await response.arrayBuffer()
const base64 = Buffer.from(arrayBuffer).toString("base64")
return base64
} catch (error) {
console.error(`Failed to convert image ${url} to base64:`, error)
throw error
}
}
export async function POST(request: NextRequest) {
try {
if (!GEMINI_API_KEY) {
return NextResponse.json({ error: "GEMINI_API_KEY environment variable is not set" }, { status: 500 })
}
const { text } = await request.json()
if (!text || typeof text !== "string") {
return NextResponse.json({ error: "Text input is required" }, { status: 400 })
}
// Convert reference images to base64
console.log("[v0] Converting reference images to base64...")
const base64Images = await Promise.all(
REFERENCE_IMAGES.map(async (url) => {
const base64 = await imageToBase64(url)
return {
inlineData: {
mimeType: "image/png",
data: base64,
},
}
}),
)
console.log("[v0] Sending request to Gemini API...")
// Prepare the request payload
const payload = {
contents: [
{
parts: [
{
text: `Create a single image containing exactly 12 pixel art emoticons arranged in a 4x3 grid (4 columns, 3 rows).
Requirements:
- Pixel art style with prominent, well-defined pixels (similar to the reference images)
- Black background (#000000) is mandatory
- No text in emoticons
- Emoticons should have diverse expressions and emotions that reflect these words: "${text}"
- Each emoticon should be clearly separated and distinct
- Maintain the same retro pixel art style as the reference images
- Make sure all 12 emoticons are visible and well-spaced in the grid
The emoticons should express various emotions and concepts related to: ${text}`,
},
...base64Images,
],
},
],
generationConfig: {
temperature: 0.7,
topK: 32,
topP: 1,
maxOutputTokens: 4096,
response_modalities: ["Image"],
},
}
const response = await fetch(`${GEMINI_API_URL}?key=${GEMINI_API_KEY}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
})
if (!response.ok) {
const errorText = await response.text()
console.error("[v0] Gemini API error:", errorText)
return NextResponse.json({ error: "Failed to generate emoticon" }, { status: response.status })
}
const data = await response.json()
console.log("[v0] Received response from Gemini API")
// Extract the generated image
if (data.candidates && data.candidates[0] && data.candidates[0].content && data.candidates[0].content.parts) {
const parts = data.candidates[0].content.parts
// Look for inline data (base64 image)
for (const part of parts) {
if (part.inlineData && part.inlineData.data) {
const base64Image = part.inlineData.data
const mimeType = part.inlineData.mimeType || "image/png"
const imageUrl = `data:${mimeType};base64,${base64Image}`
console.log("[v0] Successfully generated emoticon image")
return NextResponse.json({ imageUrl })
}
}
}
console.error("[v0] No image found in Gemini response:", JSON.stringify(data, null, 2))
return NextResponse.json({ error: "No image generated" }, { status: 500 })
} catch (error) {
console.error("[v0] Error in generate-emoticon API:", error)
return NextResponse.json({ error: "Internal server error" }, { status: 500 })
}
}
JavaScript
복사
동화책 라우트 - illustrations
# app > api > generate-illustrations > route.ts
import { type NextRequest, NextResponse } from "next/server"
import type { Storybook } from "@/types/storybook"
const GEMINI_API_KEY = process.env.GOOGLE_GENERATIVE_AI_API_KEY
const GEMINI_API_URL =
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent"
export async function POST(request: NextRequest) {
try {
if (!GEMINI_API_KEY) {
return NextResponse.json(
{ error: "GOOGLE_GENERATIVE_AI_API_KEY environment variable is not set" },
{ status: 500 },
)
}
const { storybook }: { storybook: Storybook } = await request.json()
if (!storybook?.pages?.length) {
return NextResponse.json({ error: "유효한 스토리북이 필요합니다." }, { status: 400 })
}
console.log("[v0] Starting illustration generation for", storybook.pages.length, "pages")
const updatedPages = await Promise.all(
storybook.pages.map(async (page) => {
try {
console.log(`[v0] Generating illustration for page ${page.id}:`, page.prompt)
// Prepare the request payload for image generation
const payload = {
contents: [
{
parts: [
{
text: `Create a beautiful, colorful children's storybook illustration for this scene: "${page.prompt}".
Style requirements:
- Child-friendly and engaging artwork
- Bright, vibrant colors
- Soft, rounded shapes suitable for young children
- Clear, simple composition
- Storybook illustration style similar to popular children's books
- Age-appropriate content for ${storybook.ageGroup || "3-7"} year olds
- ${storybook.artStyle || "whimsical"} art style
- High quality, detailed illustration
The illustration should capture the essence of: ${page.content}`,
},
],
},
],
generationConfig: {
temperature: 0.7,
topK: 32,
topP: 1,
maxOutputTokens: 4096,
response_modalities: ["Image"], // Added proper response modality for image generation
},
}
const response = await fetch(`${GEMINI_API_URL}?key=${GEMINI_API_KEY}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
})
if (!response.ok) {
const errorText = await response.text()
console.error(`[v0] Gemini API error for page ${page.id}:`, errorText)
// Return page with placeholder if generation fails
return {
...page,
imageUrl: `/placeholder.svg?height=400&width=600&query=${encodeURIComponent(page.prompt)}`,
}
}
const data = await response.json()
console.log(`[v0] Received response from Gemini API for page ${page.id}`)
if (data.candidates && data.candidates[0] && data.candidates[0].content && data.candidates[0].content.parts) {
const parts = data.candidates[0].content.parts
// Look for inline data (base64 image)
for (const part of parts) {
if (part.inlineData && part.inlineData.data) {
const base64Image = part.inlineData.data
const mimeType = part.inlineData.mimeType || "image/png"
const imageUrl = `data:${mimeType};base64,${base64Image}`
console.log(`[v0] Successfully generated illustration for page ${page.id}`)
return {
...page,
imageUrl,
}
}
}
}
console.error(`[v0] No image found in Gemini response for page ${page.id}:`, JSON.stringify(data, null, 2))
// Fallback to placeholder
return {
...page,
imageUrl: `/placeholder.svg?height=400&width=600&query=${encodeURIComponent(page.prompt)}`,
}
} catch (error) {
console.error(`[v0] Failed to generate image for page ${page.id}:`, error)
return {
...page,
imageUrl: `/placeholder.svg?height=400&width=600&query=${encodeURIComponent(page.prompt)}`,
}
}
}),
)
const updatedStorybook: Storybook = {
...storybook,
pages: updatedPages,
updatedAt: new Date(),
}
console.log("[v0] Illustration generation completed successfully")
return NextResponse.json(updatedStorybook)
} catch (error) {
console.error("[v0] Illustration generation error:", error)
return NextResponse.json({ error: "삽화 생성 중 오류가 발생했습니다." }, { status: 500 })
}
}
BNF
복사
동화책 라우트 - story
# app > api > generate-story > route.ts
import { type NextRequest, NextResponse } from "next/server"
import { generateText } from "ai"
import { google } from "@ai-sdk/google"
import type { StorySettings, Storybook } from "@/types/storybook"
export async function POST(request: NextRequest) {
try {
const { idea, settings }: { idea: string; settings: StorySettings } = await request.json()
if (!idea?.trim()) {
return NextResponse.json({ error: "아이디어를 입력해주세요." }, { status: 400 })
}
// Generate story outline using Gemini
const { text } = await generateText({
model: google("gemini-2.0-flash-exp"),
prompt: `당신은 창의적인 동화 작가입니다. 다음 조건에 맞는 아름다운 동화를 만들어주세요:
아이디어: ${idea}
연령대: ${settings.age}세
분위기: ${settings.tone === "gentle" ? "잔잔하고 따뜻한" : settings.tone === "adventurous" ? "모험적이고 흥미진진한" : "재미있고 유쾌한"}
그림 스타일: ${settings.style === "watercolor" ? "수채화" : settings.style === "crayon" ? "크레용" : "종이 오려내기"}
요구사항:
1. 5-7페이지의 짧은 동화로 구성
2. 각 페이지는 1-2문장의 간단한 텍스트
3. 아이들이 이해하기 쉬운 한국어 사용
4. 긍정적이고 교육적인 메시지 포함
5. 각 페이지마다 삽화 설명도 함께 제공
다음 JSON 형식으로 응답해주세요:
{
"title": "동화 제목",
"pages": [
{
"text": "페이지 텍스트",
"prompt": "삽화 설명 (영어로, 상세하게)"
}
]
}
삽화 설명은 다음 형식을 따라주세요:
"${settings.style} children's storybook illustration, [캐릭터 설명], scene: [장면 설명], warm and inviting atmosphere, suitable for ${settings.age} year old children"`,
})
// Parse the generated story
let storyData
try {
// Extract JSON from the response
const jsonMatch = text.match(/\{[\s\S]*\}/)
if (!jsonMatch) throw new Error("No JSON found in response")
storyData = JSON.parse(jsonMatch[0])
} catch (parseError) {
console.error("Failed to parse story JSON:", parseError)
return NextResponse.json({ error: "이야기 생성 중 오류가 발생했습니다." }, { status: 500 })
}
// Create storybook object
const storybook: Storybook = {
id: `story-${Date.now()}`,
title: storyData.title || "새로운 이야기",
idea,
settings,
pages: storyData.pages.map((page: any, index: number) => ({
id: `page-${index + 1}`,
text: page.text,
prompt: page.prompt,
isLocked: false,
})),
createdAt: new Date(),
updatedAt: new Date(),
}
return NextResponse.json(storybook)
} catch (error) {
console.error("Story generation error:", error)
return NextResponse.json({ error: "이야기 생성 중 오류가 발생했습니다." }, { status: 500 })
}
}
BNF
복사