# AI Integration Reference

## Google Gemini (Image Generation)

### Setup
```javascript
import { GoogleGenAI } from '@google/genai'
const ai = new GoogleGenAI({ apiKey })
```

### Image Generation (with reference image)
```javascript
const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash-image',
  contents: {
    parts: [
      { inlineData: { mimeType: 'image/jpeg', data: base64WithoutPrefix } },
      { text: promptText }
    ]
  },
  config: {
    imageConfig: { aspectRatio: '3:4' }  // '1:1', '3:4', '4:3', '9:16', '16:9'
  }
})

// Extract generated image
for (const part of response.candidates?.[0]?.content?.parts || []) {
  if (part.inlineData) {
    const imageBase64 = part.inlineData.data  // raw base64
    const imageBuffer = Buffer.from(imageBase64, 'base64')
  }
}
```

### Text Generation
```javascript
const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: { parts: [{ text: prompt }] }
})
const text = response.text
```

### Audio Transcription
```javascript
const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: {
    parts: [
      { inlineData: { mimeType: 'audio/ogg', data: audioBase64 } },
      { text: 'Transcribe this audio to text. Return ONLY the transcription.' }
    ]
  }
})
const transcription = response.text?.trim()
```

### Image Analysis (Consultation)
```javascript
const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: {
    parts: [
      { inlineData: { mimeType: 'image/jpeg', data: photoBase64 } },
      { text: 'Analyze this image and suggest...' }
    ]
  }
})
```

## OpenAI (Alternative)

### Setup
```javascript
import OpenAI from 'openai'
const openai = new OpenAI({ apiKey })
```

### Chat Completion
```javascript
const response = await openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [
    { role: 'system', content: systemPrompt },
    { role: 'user', content: userMessage }
  ]
})
const text = response.choices[0].message.content
```

### Image Generation (DALL-E)
```javascript
const response = await openai.images.generate({
  model: 'dall-e-3',
  prompt: promptText,
  size: '1024x1024',
  response_format: 'b64_json'
})
const imageBase64 = response.data[0].b64_json
```

### Vision (Image Analysis)
```javascript
const response = await openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{
    role: 'user',
    content: [
      { type: 'text', text: 'Analyze this image' },
      { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${base64}` } }
    ]
  }]
})
```

### Audio Transcription (Whisper)
```javascript
const response = await openai.audio.transcriptions.create({
  model: 'whisper-1',
  file: audioBuffer  // Buffer or File object
})
const text = response.text
```

## Retry with Exponential Backoff

```javascript
async function withRetry(fn, maxRetries = 2) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn()
    } catch (err) {
      const msg = err.message || ''
      const retryable = msg.includes('503') || msg.includes('UNAVAILABLE') ||
                         msg.includes('overloaded') || msg.includes('timeout')

      if (retryable && attempt < maxRetries) {
        const wait = (attempt + 1) * 5000  // 5s, 10s
        await new Promise(r => setTimeout(r, wait))
        continue
      }

      // NOT retryable or out of retries
      throw err
    }
  }
}
```

## Error Classification

```javascript
function classifyError(err) {
  const msg = err.message || ''

  if (msg.includes('403') || msg.includes('API_KEY') || msg.includes('PERMISSION_DENIED'))
    return 'invalid_key'

  if (msg.includes('429') || msg.includes('quota') || msg.includes('RESOURCE_EXHAUSTED'))
    return 'rate_limited'

  if (msg.includes('503') || msg.includes('UNAVAILABLE') || msg.includes('overloaded'))
    return 'server_busy'

  if (msg.includes('400') || msg.includes('INVALID_ARGUMENT'))
    return 'bad_request'

  return 'unknown'
}
```

## Base64 Utilities

```javascript
// Data URI → clean base64
function cleanBase64(dataUri) {
  return dataUri.replace(/^data:[^;]+;base64,/, '')
}

// Data URI → MIME type
function getMimeType(dataUri) {
  const match = dataUri.match(/^data:([^;]+);/)
  return match ? match[1] : 'image/jpeg'
}

// Buffer → data URI
function toDataUri(buffer, mimeType) {
  return `data:${mimeType};base64,${buffer.toString('base64')}`
}
```

## Prompt Engineering Tips

1. **Role assignment**: Start with "ROLE: [specific expert role]"
2. **Explicit restrictions**: List banned outputs (UI elements, watermarks, etc.)
3. **Quality anchors**: Reference real-world standards (RAW photo, magazine editorial)
4. **Negative prompts**: Explicitly state what to NOT generate
5. **Identity preservation**: For face/reference-based: "CRITICAL: maintain subject identity"
6. **Conditional sections**: `${realistic ? REALISM_PROMPT : ''}` — toggle prompt blocks
