Nette Documentation Preview

syntax
Generování obrázků
******************

.[perex]
Popíšeš slovy, co chceš vidět, a dostaneš obrázek. Ukážeme si, jak se generuje a ukládá, jak modelu přidat předlohu a na co narazíš, až přijde na cenu a na čekání.


První obrázek
=============

Na generování stačí jediná metoda. Řekneš jí, který model má kreslit a co:

```php
$client = new AIAccess\Provider\OpenAI\Client($apiKey);

$image = $client->generateImage('gpt-image-2', 'Maják na útesu za bouřky, plochá vektorová ilustrace');
$image->save('/cesta/k/majaku.png');
```

Návratová hodnota není řetězec s adresou, ale objekt `Media` se samotnými daty obrázku. Ten už znáš z kapitoly o [obrázcích na vstupu |multimodal]; je to tentýž objekt, jen jednou putuje k modelu a podruhé od něj.

Kromě `save()` z něj dostaneš i syrová data metodou `getData()`, pokud si obrázek chceš uložit sám třeba do databáze nebo rovnou poslat do prohlížeče.


Zjisti si, co ti přišlo
=======================

Tady je první past, na kterou se dá snadno naletět: **nepředpokládej, že dostaneš PNG**. OpenAI ve výchozím nastavení posílá PNG, ale Gemini vrací JPEG. Když si natvrdo napíšeš příponu `.png`, skončíš s JPEGem uloženým pod špatným jménem.

Typ obsahu ti obrázek řekne sám, tak ho použij:

```php
$extension = explode('/', $image->getMimeType())[1];
$image->save("/cesta/k/majaku.$extension");
```


Předloha místo pouhého popisu
=============================

K popisu můžeš modelu přidat i obrázky, ze kterých má vyjít. Hodí se to na úpravy, variace jednoho motivu nebo na udržení jednotného stylu napříč sadou obrázků:

```php
use AIAccess\Media;

$image = $client->generateImage(
	'gpt-image-2',
	'Stejný maják, ale za slunečného rána',
	references: [Media::fromFile('/cesta/k/majaku.png')],
);
```

Předloh může být víc než jedna. Grok je nepřijímá vůbec a odmítne je výjimkou `AIAccess\LogicException` ještě před odesláním požadavku.


Co který provider umí
=====================

| Provider | Generování | Předlohy | Kde to běží                       |
|----------|------------|----------|-----------------------------------|
| OpenAI   | ✅         | ✅       | samostatný endpoint pro obrázky   |
| Gemini   | ✅         | ✅       | obyčejný chat, obrázkovým modelem |
| Grok     | ✅         | ➖       | samostatný endpoint pro obrázky   |
| Claude   | ➖         | ➖       | obrázky negeneruje                |
| DeepSeek | ➖         | ➖       | obrázky negeneruje                |

Poslední sloupec stojí za vysvětlení, protože je to hezká ukázka toho, co knihovna dělá. **Gemini žádný endpoint pro obrázky nemá.** Obrázkový model se u něj oslovuje úplně stejně jako běžný chat, jen si řekne o obrázek místo textu. Ty o tom ale vědět nemusíš: `generateImage()` vypadá u všech tří providerů stejně.

OpenAI navíc bere nepovinné parametry `size`, `quality`, `background` a `format`, kterými řekneš, jak velký a jak kvalitní obrázek chceš a jestli má mít průhledné pozadí:

```php
$image = $client->generateImage(
	'gpt-image-2',
	'Ikona obálky, plochý styl',
	size: '1024x1024',
	quality: 'low',
	background: 'transparent',
);
```


Než to pustíš do provozu
========================

**Obrázky jsou řádově dražší než text.** Zatímco běžný dotaz stojí zlomky haléře, jeden obrázek ve vysoké kvalitě se počítá v korunách. Při testování proto generuj v nízké kvalitě a menším rozlišení; na ověření, že kód funguje, to bohatě stačí.

**Když jich generuješ hodně, zvaž [dávkové zpracování |batch].** Provideři za odloženou odpověď účtují zhruba polovinu a v praxi to u obrázků nebývá pomalejší než generování po jednom, spíš naopak. Obrázky se přidávají do obyčejné dávky metodou `addImageRequest()` a umí to OpenAI a Gemini.

**Generování trvá dlouho.** Obyčejný obrázek vznikne v řádu sekund, ale vysoká kvalita s předlohami klidně minuty. Výchozí timeout HTTP klienta je 180 sekund, což na tyhle případy nemusí stačit, takže si ho zvedni:

```php
$http = (new AIAccess\Http\CurlClient)->setOptions(requestTimeout: 600);
$client = new AIAccess\Provider\OpenAI\Client($apiKey, $http);
```

**U Gemini je potřeba placený projekt.** Obrázkové modely mají na free tieru nulovou denní kvótu, takže volání skončí chybou o překročeném limitu, i když jsi ještě nic nevygeneroval.

A jedna samozřejmost, na kterou se zapomíná: model může místo obrázku odmítnout kreslit, typicky u obsahu, který jeho pravidla nedovolují. Pak dostaneš `AIAccess\UnexpectedResponseException`, protože v odpovědi žádný obrázek není. Počítej s tím, obzvlášť když popis skládáš z uživatelského vstupu.


Kam dál
=======

- [Obrázky a dokumenty na vstupu |multimodal] - opačný směr, když se má model na obrázek podívat
- [HTTP vrstva |http] - timeouty, opakování a logování požadavků
- [Ošetření chyb |errors] - co znamenají jednotlivé výjimky
- [Provideři |providers] - co který umí a čím se liší

Generování obrázků

Popíšeš slovy, co chceš vidět, a dostaneš obrázek. Ukážeme si, jak se generuje a ukládá, jak modelu přidat předlohu a na co narazíš, až přijde na cenu a na čekání.

První obrázek

Na generování stačí jediná metoda. Řekneš jí, který model má kreslit a co:

$client = new AIAccess\Provider\OpenAI\Client($apiKey);

$image = $client->generateImage('gpt-image-2', 'Maják na útesu za bouřky, plochá vektorová ilustrace');
$image->save('/cesta/k/majaku.png');

Návratová hodnota není řetězec s adresou, ale objekt Media se samotnými daty obrázku. Ten už znáš z kapitoly o obrázcích na vstupu; je to tentýž objekt, jen jednou putuje k modelu a podruhé od něj.

Kromě save() z něj dostaneš i syrová data metodou getData(), pokud si obrázek chceš uložit sám třeba do databáze nebo rovnou poslat do prohlížeče.

Zjisti si, co ti přišlo

Tady je první past, na kterou se dá snadno naletět: nepředpokládej, že dostaneš PNG. OpenAI ve výchozím nastavení posílá PNG, ale Gemini vrací JPEG. Když si natvrdo napíšeš příponu .png, skončíš s JPEGem uloženým pod špatným jménem.

Typ obsahu ti obrázek řekne sám, tak ho použij:

$extension = explode('/', $image->getMimeType())[1];
$image->save("/cesta/k/majaku.$extension");

Předloha místo pouhého popisu

K popisu můžeš modelu přidat i obrázky, ze kterých má vyjít. Hodí se to na úpravy, variace jednoho motivu nebo na udržení jednotného stylu napříč sadou obrázků:

use AIAccess\Media;

$image = $client->generateImage(
	'gpt-image-2',
	'Stejný maják, ale za slunečného rána',
	references: [Media::fromFile('/cesta/k/majaku.png')],
);

Předloh může být víc než jedna. Grok je nepřijímá vůbec a odmítne je výjimkou AIAccess\LogicException ještě před odesláním požadavku.

Co který provider umí

Provider Generování Předlohy Kde to běží
OpenAI samostatný endpoint pro obrázky
Gemini obyčejný chat, obrázkovým modelem
Grok samostatný endpoint pro obrázky
Claude obrázky negeneruje
DeepSeek obrázky negeneruje

Poslední sloupec stojí za vysvětlení, protože je to hezká ukázka toho, co knihovna dělá. Gemini žádný endpoint pro obrázky nemá. Obrázkový model se u něj oslovuje úplně stejně jako běžný chat, jen si řekne o obrázek místo textu. Ty o tom ale vědět nemusíš: generateImage() vypadá u všech tří providerů stejně.

OpenAI navíc bere nepovinné parametry size, quality, background a format, kterými řekneš, jak velký a jak kvalitní obrázek chceš a jestli má mít průhledné pozadí:

$image = $client->generateImage(
	'gpt-image-2',
	'Ikona obálky, plochý styl',
	size: '1024x1024',
	quality: 'low',
	background: 'transparent',
);

Než to pustíš do provozu

Obrázky jsou řádově dražší než text. Zatímco běžný dotaz stojí zlomky haléře, jeden obrázek ve vysoké kvalitě se počítá v korunách. Při testování proto generuj v nízké kvalitě a menším rozlišení; na ověření, že kód funguje, to bohatě stačí.

Když jich generuješ hodně, zvaž dávkové zpracování. Provideři za odloženou odpověď účtují zhruba polovinu a v praxi to u obrázků nebývá pomalejší než generování po jednom, spíš naopak. Obrázky se přidávají do obyčejné dávky metodou addImageRequest() a umí to OpenAI a Gemini.

Generování trvá dlouho. Obyčejný obrázek vznikne v řádu sekund, ale vysoká kvalita s předlohami klidně minuty. Výchozí timeout HTTP klienta je 180 sekund, což na tyhle případy nemusí stačit, takže si ho zvedni:

$http = (new AIAccess\Http\CurlClient)->setOptions(requestTimeout: 600);
$client = new AIAccess\Provider\OpenAI\Client($apiKey, $http);

U Gemini je potřeba placený projekt. Obrázkové modely mají na free tieru nulovou denní kvótu, takže volání skončí chybou o překročeném limitu, i když jsi ještě nic nevygeneroval.

A jedna samozřejmost, na kterou se zapomíná: model může místo obrázku odmítnout kreslit, typicky u obsahu, který jeho pravidla nedovolují. Pak dostaneš AIAccess\UnexpectedResponseException, protože v odpovědi žádný obrázek není. Počítej s tím, obzvlášť když popis skládáš z uživatelského vstupu.

Kam dál