Files
quoter/docs/vercel-og-quickstart.md
Untone 7497b8c426
Some checks failed
Deploy / deploy (push) Has been skipped
CI / test (push) Failing after 20s
CI / lint (push) Successful in 7m1s
build-reconfig2
2025-09-02 10:46:51 +03:00

234 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🚀 Quick Start: @vercel/og + Quoter
## ⚡ 5-минутная настройка
### 1. Установка зависимостей
```bash
npm install @vercel/og
```
### 2. Создание API endpoint
```typescript
// pages/api/og.tsx (Next.js)
import { ImageResponse } from '@vercel/og'
export const config = { runtime: 'edge' }
export default function handler(req) {
const { searchParams } = new URL(req.url)
const title = searchParams.get('title') ?? 'Hello World'
return new ImageResponse(
(
<div style={{
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 60,
fontWeight: 700,
}}>
{title}
</div>
),
{ width: 1200, height: 630 }
)
}
```
### 3. Интеграция с Quoter
```typescript
// utils/quoter.ts
export async function uploadToQuoter(imageBuffer: Buffer, filename: string, token: string) {
const formData = new FormData()
const blob = new Blob([imageBuffer], { type: 'image/png' })
formData.append('file', blob, filename)
const response = await fetch('https://quoter.staging.discours.io/', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: formData,
})
return response.text() // URL файла
}
```
### 4. Использование
```typescript
// Генерация OG изображения
const ogResponse = await fetch('/api/og?title=My%20Amazing%20Post')
const imageBuffer = Buffer.from(await ogResponse.arrayBuffer())
// Загрузка в Quoter
const quoterUrl = await uploadToQuoter(imageBuffer, 'og-image.png', userToken)
// Использование в meta tags
<meta property="og:image" content={quoterUrl} />
```
## 🎨 Расширенный пример с изображением фона
```typescript
// pages/api/og-advanced.tsx
import { ImageResponse } from '@vercel/og'
export default async function handler(req) {
const { searchParams } = new URL(req.url)
const title = searchParams.get('title')
const imageUrl = searchParams.get('image') // Quoter URL
// Загружаем изображение из Quoter
let backgroundImage = null
if (imageUrl) {
const imageResponse = await fetch(imageUrl)
const buffer = await imageResponse.arrayBuffer()
backgroundImage = `data:image/jpeg;base64,${Buffer.from(buffer).toString('base64')}`
}
return new ImageResponse(
(
<div style={{
background: backgroundImage ? `url(${backgroundImage})` : '#667eea',
backgroundSize: 'cover',
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}>
{/* Затемнение для читаемости */}
<div style={{
position: 'absolute',
inset: 0,
background: 'rgba(0,0,0,0.4)',
}} />
{/* Заголовок */}
<h1 style={{
fontSize: 72,
fontWeight: 'bold',
color: 'white',
textAlign: 'center',
textShadow: '2px 2px 4px rgba(0,0,0,0.8)',
zIndex: 1,
}}>
{title}
</h1>
</div>
),
{ width: 1200, height: 630 }
)
}
```
## 📱 React Hook для удобства
```typescript
// hooks/useOgImage.ts
import { useState } from 'react'
export function useOgImage() {
const [loading, setLoading] = useState(false)
const generateAndUpload = async (title: string, backgroundImage?: string) => {
setLoading(true)
try {
// Генерируем OG изображение
const ogUrl = `/api/og?title=${encodeURIComponent(title)}${
backgroundImage ? `&image=${encodeURIComponent(backgroundImage)}` : ''
}`
const response = await fetch(ogUrl)
const buffer = await response.arrayBuffer()
// Загружаем в Quoter
const formData = new FormData()
const blob = new Blob([buffer], { type: 'image/png' })
formData.append('file', blob, `og-${Date.now()}.png`)
const uploadResponse = await fetch('/api/upload-to-quoter', {
method: 'POST',
body: formData,
})
return await uploadResponse.text()
} finally {
setLoading(false)
}
}
return { generateAndUpload, loading }
}
// Использование в компоненте
function MyComponent() {
const { generateAndUpload, loading } = useOgImage()
const handleCreateOg = async () => {
const quoterUrl = await generateAndUpload('My Post Title', '/existing-image.jpg')
console.log('OG image uploaded to:', quoterUrl)
}
return (
<button onClick={handleCreateOg} disabled={loading}>
{loading ? 'Generating...' : 'Create OG Image'}
</button>
)
}
```
## ⚡ Production Tips
### Кэширование
```typescript
// Cache OG images for 24 hours
export default function handler(req) {
const response = new ImageResponse(/* ... */)
response.headers.set('Cache-Control', 'public, max-age=86400')
response.headers.set('CDN-Cache-Control', 'public, max-age=86400')
return response
}
```
### Error Handling
```typescript
export default async function handler(req) {
try {
return new ImageResponse(/* ... */)
} catch (error) {
console.error('OG generation failed:', error)
// Fallback изображение
return new Response('Failed to generate image', { status: 500 })
}
}
```
### Environment Variables
```bash
# .env.local
QUOTER_API_URL=https://quoter.staging.discours.io
QUOTER_AUTH_TOKEN=your_jwt_token
NEXT_PUBLIC_OG_BASE_URL=https://yoursite.com/api/og
```
## 🔗 Полезные ссылки
- [Полная документация по интеграции](./vercel-og-integration.md)
- [Quoter API Reference](./api-reference.md)
- [Vercel OG Official Docs](https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation)
---
💋 **Упрощение**: Один endpoint для генерации, один для загрузки - минимум кода, максимум результата!