Metin İşin Kolay Kısmı: Yapay Zekâ Yazımı Makaleleri Görselleştiren Pipeline
Metin üretmek çözülmüş bir problem. Onu görselleştirmek değil. Uçtan uca pipeline — yönlendirici prompt, fotoğraf arama, Mermaid diyagramları, doğrulanmış grafikler ve bunu SEO'ya dönüştüren alt metin, kredi ve ImageObject markup'ı.
Bir içerik hedefi olan bir geliştiricisiniz: ayda düzinelerce, belki yüzlerce makale. Yazma modeli taslağı, ana hatları, meta açıklamasını, iç bağlantıları hallediyor. Sonra hat, kendine ait modeli olmayan tek adıma çarpıyor — görseller — ve duruyor. Fotoğraf bulmak zor olduğu için değil, yığındaki hiçbir şey hangi fotoğrafın, nereden, hangi lisansla, nasıl tanımlanacağını bilmediği için.
Bu makale, o eksik adımın uçtan uca kablolanmış hâli: hangi bölüm için hangi tür görselin üretileceği, bitmiş bir taslağı arama brief'lerine dönüştüren prompt, fotoğrafları döndüren API çağrısı, bir fotoğrafın anlatamayacağını çizen ikinci model ve Google'ın gerçekten okuyabileceği işaretlemeyi üreten derleyici. Sonda çalmaya hazır iki eksiksiz iş akışı var.
Metin çözüldü. İllüstrasyon takıldığı yer.
Otomatik bir makale hattının dürüst denetimini yapın. Ana hat: çözüldü. Taslak: çözüldü. Başlık, meta açıklama, şema, iç bağlantılar, çeviri: hepsi çözüldü, hepsi aynı model tarafından, hepsi metin olarak. Sonra:
| Hat adımı | Durum | Asıl engelleyen |
|---|---|---|
| Ana hat & taslak | Çözüldü | Bir model çağrısı, bir prompt |
| Başlıklar, meta, şema, bağlantılar | Çözüldü | Metin girer, metin çıkar |
| Hero görseli | Engellendi | Gerçek bir dosya, bir lisans, boyutlar ve alt metin gerektirir — bunların hiçbiri bir metin modeli tarafından üretilemez |
| Bölüm görselleri | Engellendi | Makale başına üç ila beş, her biri farklı, sitede hiçbiri tekrarlanmıyor |
| Grafikler & diyagramlar | Engellendi | Doğru olmalı — bir aramanın döndüremeyeceği ve bir üreticinin uyduramayacağı tek görsel türü |
Bu başarısızlık estetik değil, yapısaldır: makale bir stok yer tutucu ile, ya da son on iki
makaleyle aynı fotoğrafla, ya da altı parmaklı elinin okuyucunun gördüğü ilk şey olduğu üretilmiş
bir görselle yayınlanır. Ve görsel süsleme değildir — Google'ın kendi görsel belgeleri bunu açıkça
ortaya koyar: alt metin “bir görsel için meta veri sağlama söz konusu olduğunda en önemli
özelliktir” ve tavsiye edilen, görselin bulunabilmesi ve anlaşılabilmesi için CSS arka planları
yerine açıklayıcı alt içeren gerçek <img> öğeleri kullanmaktır.1
Dört tür görsel, dört tür model
En büyük tasarım hatası, “görseli” tek bir sağlayıcıya sahip tek bir problem olarak ele almaktır. Aslında dörttür ve aralarındaki yönlendirici bir servis değil, bir satırlık prompt'tur:
| Bölümün ihtiyacı… | Şununla üret | Diğerleri neden olmaz |
|---|---|---|
| Gerçek dünyadan bir sahnehero, insan durumları, yerler, nesneler, jestler | Semantik fotoğraf arama (Pexafy) | Bir üretici ayrıntıları uydurur; bir grafiğin çizecek bir şeyi yoktur |
| Gerçekten sahip olduğunuz sayılarkıyaslamalar, fiyatlandırma, anket sonuçları, gecikme | Bir sandbox'ta çalıştırılan, çizim kodu yazan bir model | Bir görsel modeline bir değer konusunda güvenilemez; bir fotoğraf veri taşıyamaz |
| Bir yapı veya akışmimari, sıra, durum makinesi | Mermaid / Graphviz yazan, deterministik olarak render edilen bir model | Ücretsiz fotoğraf kütüphanelerinde sizin sisteminizin diyagramı yoktur |
| Ekrandaki ürününüzdokümantasyon, changelog, öğreticiler | Betikle alınan bir tarayıcı ekran görüntüsü (Playwright) | Sadece sizin derlemenizde var olan bir UI'ı başka hiçbir şey gösteremez |
Ve üretilmiş illüstrasyon? Tek bir dürüst kullanım alanı bırakıyor: fotoğrafı çekilemeyecek ve veri olmayan sahne — soyut bir mekanizma, henüz var olmayan bir ürün, sahibi olduğunuz bir ev illüstrasyon stili. (Üretim yerine gerçek fotoğrafçılık için tam gerekçe — hacimde hız, doğruluk, tekrarlılık sorunu — burada anlatılıyor.) Gidişat yönünde bir işaret: 2 Ağustos 2026 tarihinden itibaren, AB Yapay Zeka Yasası'nın 50. Maddesi, üretici (generatif) sistem sağlayıcılarının sentetik çıktıları makine tarafından okunabilir bir biçimde işaretlemesini zorunlu kılıyor.2 Bu, bir blogun ne yayınlayabileceğine ilişkin bir kural değil, yapay zeka sağlayıcıları ve dağıtıcılarına yönelik bir yükümlülük — ama tam da bu yüzden, makalenizin en üstündeki görselin kaynağı, okuyucunun güvenmesi gereken bir şey olmaktan çıkıp kontrol edebileceği bir şey haline geliyor.
Hat, uçtan uca
Beş aşama. Sadece aşama 3 bir görsel API'sine dokunur ve sadece aşama 4 isteğe bağlıdır:
┌─ 1. YAZ ────────────────────────────────────────────────────┐
konu ──▶ LLM ──▶ draft.md (h2 bölümleri, ön-madde)
└───────────────────────────────┬───────────────────────────────┘
┌─ 2. BRIEF ────────────────────┴───────────────────────────────┐
draft.md ──▶ LLM ──▶ { hero: {...}, sections: [ {...} ] }
tek JSON nesnesi: her slot için bir kind +
ya bir kamera brief'i ya da bir veri/diyagram şeması
└──────────┬──────────────────────────────────┬─────────────────┘
│ kind = "photo" │ kind = "chart" | "diagram"
▼ ▼
┌─ 3. ARA ───────────────┐ ┌─ 4. ÇİZ (isteğe bağlı) ─────────┐
GET /search/photos LLM ──▶ mermaid | çizim kodu
← kaynağı belirtilmiş foto + ──▶ sandbox ──▶ .svg / .png
g/y, blur_hash, alt, (deterministik render, uydurma
lisans, kaynak URL sayı yok)
└──────────┬────────────────┘ └──────────────┬───────────────┘
└───────────────┬──────────────────┘
┌─ 5. DERLE ─────────────┴───────────────────────────────────┐
genişlik/yükseklik + fetchpriority | loading içeren <img>
bir insan için yazılmış alt · görünür kredi · ImageObject JSON-LD
iki sayfanın aynı hero'yu paylaşmaması için photo_id saklanır
└───────────────────────────────────────────────────────────────┘
Diyagramdan daha önemli olan iki özellik var. Aşama 2 bir yönlendiricidir: her slot için hangi üreticinin çalışacağına karar verir, böylece bir fotoğraf kütüphanesinden asla bir çubuk grafik istemezsiniz. Ve SEO'nun yaşadığı yer aşama 5'tir — Google'ın görseller hakkında belgelediği her şey (açıklayıcı alt, lisans meta verisi, LCP açısından güvenli bir hero) burada, arama yanıtının zaten taşıdığı alanlardan üretilir.
Aşama 2: taslağı görsel brief'lerine dönüştür
Bitmiş taslak üzerinde tek bir model çağrısı, ve döndürdüğü şey bir sorgu değil bir plandır. Tek bir fotoğraf brifi nasıl yazılır — makale başlığının neden mümkün olan en kötü girdi olduğu, 12 ile 25 kelimelik bir kamera brifinin neye benzediği ve bunun nasıl başarısız olduğu — tek bir makaleyi görsellendirme kılavuzunda ayrıntılı olarak anlatılıyor ve burada tekrarlanmıyor. Bir boru hattının eklediği şey yönlendirmedir: aynı çağrı, yuva yuva, hangi üreticinin çalışacağına karar vermek zorundadır — ve bir grafik girdisi veri taşırken bir fotoğraf girdisi sahne taşır.
# sistem promptu — bitmiş her taslak için bir kez çalıştırın
Sen teknik bir yayının sanat yönetmenisin. Makaleyi oku ve
görsel planı döndür: hero için bir giriş, her H2 bölümü için bir tane.
Her giriş için tam olarak bir kind seç:
"photo" gerçek bir sahne: birinin bir yerde bir şey yapması, bir yer,
bir nesne, bir jest. Hero'lar için varsayılan.
"chart" bölüm makalenin İÇİNDE olan sayılar belirtiyor. Asla
değer uydurma: data içine olduğu gibi kopyala.
"diagram" bölüm bir yapıyı, akışı veya diziyi tanımlıyor.
"none" bölüm kısa veya zaten bir kod bloğu taşıyor.
"photo" girişleri için kurallar — alan query:
Bir kamera notu yazın: bir kameranın çekebileceği bir sahne, 12 ile 25 kelime
arasında, İngilizce olarak, bölümün havasına uygun. Kadrajda ne olduğunu
belirtin, konuyu değil. Metin, logo, marka veya ünlü kişi yok; görünmez
metafor yok. (Örnekler ve başarısız durumlarla birlikte tüm kurallar:
pexafy.com/blog/illustrate-blog-articles-at-scale/)
Bir fotoğraf girişinin alt metnini YAZMA: geri aldığınız görsel, brief'e
en yakın eşleşmedir, tanımladığınız sahne değildir, bu yüzden alt metni
seçilen fotoğraftan yazılmalıdır. Grafik ve diyagram girişleri alt TAŞIR —
orada tam olarak neyin render edildiğini siz kontrol edersiniz.
Sadece JSON döndür:
{
"hero": { "kind": "photo", "query": "…", "orientation": "landscape" },
"sections": [
{ "h2": "…", "kind": "photo", "query": "…" },
{ "h2": "…", "kind": "chart", "title": "…", "unit": "ms",
"data": [ {"label": "…", "value": 0} ], "alt": "…" },
{ "h2": "…", "kind": "diagram", "spec": "flowchart LR; …", "alt": "…" }
]
}
kind satırı işin çoğunu yapar, data talimatı da gerisini tamamlar: bir
grafik girdisi yalnızca taslakta zaten geçen sayıları taşıyabilir, böylece model icat etmek yerine
aktarır. İşte yönlendiricinin gerçek bir geliştirici makalesinin üç bölümü üzerindeki hali:
| Bölüm | kind | Yönlendiricinin döndürdüğü |
|---|---|---|
| Hero — “Gece derlememiz neden 40 dakika sürüyor” | photo |
“iki monitörü ve mekanik klavyesi olan, ekranların aydınlattığı karanlık bir odada masada geç saatte çalışan bir geliştirici” |
| “Zaman aslında nereye gidiyor” | chart |
Paragraftan kopyalanan data: kurulum 480 s, derleme 1080 s, test 720 s, yükleme 120 s |
| “Grafiği nasıl böldük” | diagram |
İş bağımlılık grafiğinin flowchart LR'ı |
| “Neyi değiştirdik ve tekrar ne yapardık” | photo |
“diyagramlarla kaplı bir beyaz tahta önünde bir sorunu birlikte çözen iki mühendis” |
Aşama 3: fotoğraflar kaynağı belirtilmiş şekilde geri gelir
Her kind: "photo" girişi bir isteğe karşılık gelir. Yukarıdaki hero brief'i, herkese
açık API'ye karşı çalıştırıldığında, bunu 147 ms içinde döndürür:
Son bölüm brief'i, tamamen farklı bir sahne, 144 ms içinde:
Her fotoğraf için geri gelen şey, aşama 5'i mümkün kılan kısımdır — sadece bir dosya değil:
{
"photo_id": "019e1c7f-0063-759e-b498-33ce1714e6c9", // sakla: tekrar yok
"urls": { "small": "…?w=400", "regular": "…?w=1080",
"large": "…?w=1920" },
"width": 3000, "height": 1688, // → düzen kayması yok
"blur_hash": "LJ8gjv9rVq-6OFxanNNFI7xco$Na", // → gerçek yer tutucu
"alt_description": "Person types on keyboard in front of dual monitors…",
"photographer_full_name": "Jakub Żerdzicki", // → ImageObject.creator
"source": "Unsplash", "license_type": "free",
"source_image_url": "https://unsplash.com/photos/…",
"attribution": { "html": "<span…>Photo by …</span>",
"plain": "Photo by Jakub Żerdzicki on Unsplash (…)" }
}
Aşama 4: bir fotoğrafın anlatamayacağı şey
Plandaki iki slot aranabilir değildir ve tam olarak burada ikinci bir model yerini hak eder — bir görsel çizmek için değil, onu çizen kodu yazmak için. Bu ayrım önemlidir: kod incelenebilir, deterministiktir ve bir çubuk yüksekliğini halüsinasyon göremez.
Diyagramlar: metin girer, SVG çıkar
Mermaid, diyagramları düz metin bir tanımdan render eder,3 bu da onu bir model için en güvenli hedef yapar: çıktı incelenebilir, git'te fark alınabilir ve her seferinde aynı şekilde render edilir. Yönlendirici şemayı zaten döndürmüştü.
# bir diyagram girişinin "spec" alanı, build/graph.mmd'ye yazılır
cat build/graph.mmd
flowchart LR
install["install deps · 480s"] --> compile["compile · 1080s"]
compile --> test["test suite · 720s"]
compile --> upload["upload artifacts · 120s"]
npx -y @mermaid-js/mermaid-cli -i build/graph.mmd -o static/img/graph.svg
# → PR'da inceleyebileceğiniz bir SVG, güvenmek zorunda olduğunuz bir görsel değil
Grafikler: yalnızca makalenin zaten içerdiği sayılar
Aynı ilke, bir ekstra koruma. Yönlendirici değerleri taslaktan kopyaladı; model çizim kodunu yazar; kod bir sandbox'ta çalışır; derleyici grafiğin bir sayfaya yaklaşmasına izin verilmeden önce render edilen değerleri kaynak sayılarla yeniden kontrol eder.
import re, matplotlib
matplotlib.use("Agg") # başsız: CI'da görüntü yok
import matplotlib.pyplot as plt
def assert_in_draft(value, draft: str) -> None:
"""Çizilen bir sayı makalede BİR SAYI OLARAK görünmelidir."""
# Buradaki tuzak alt dize eşleştirmesidir: "120", "1200" içindedir ve
# "?w=1200" içinde de — saf bir `str(v) in draft` her şeyi geçer.
# Kelime sınırlarına göre eşleştir ve 1 234 / 1,234 / 1234'ü kabul et.
body = re.sub(r"(?<=\d)[ ,](?=\d{3}\b)", "", draft) # ayırıcıları temizle
if not re.search(rf"(?<![\d.]){re.escape(str(value))}(?![\d.])", body):
raise ValueError(f"{value} is not stated in the article — refusing to plot")
def render_chart(entry: dict, draft: str, out: str) -> str:
labels = [d["label"] for d in entry["data"]]
values = [d["value"] for d in entry["data"]]
for v in values:
assert_in_draft(v, draft) # halüsinasyon değeri → grafik yok
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=160)
ax.barh(labels, values)
ax.set_xlabel(entry["unit"])
ax.set_title(entry["title"])
fig.tight_layout()
fig.savefig(out) # deterministik, incelenebilir çıktı
return out
Koruma kısa, ama dikkatle yazın: bir alt dize kontrolü işe yaramaz.
"120" in draft, 1200 veya ?w=1200 içeren bir makale için
doğrudur, yani saf sürüm her şeyi geçer ve hiçbir şeyi korumaz. Basamak sınırlarına dayanın, binlik
ayırıcıları normalleştirin ve bir teknik makaleyi yorumlarda parçalara ayıran hata sınıfı — kendi
paragrafıyla çelişen bir grafik — üretime ulaşamaz. Ekran görüntüleri aynı ilkeyi izler: gerçek
derlemenize karşı betikle alınan bir page.screenshot(), kendi UI'ınız için tek gerçek
kaynaktır ve UI değiştikçe doğru kalır.
Aşama 5: SEO'nun yaşadığı yer derleme
Şimdiye kadar her şey dosya ve alan üretti. Bu aşama bunları işaretlemeye dönüştürür — ve burada hassas olmakta fayda var, çünkü belgelenmiş üç davranış bu birkaç satırda karar veriliyor.
<!-- Baytlar başka bir kaynaktan gelir: el sıkışmayı erkenden öde -->
<link rel="preconnect" href="https://images.unsplash.com" crossorigin>
<!-- LCP öğesi: asla lazy değil, her zaman yüksek öncelik -->
<figure>
<img src="{urls.regular}"
width="{width}" height="{height}" <!-- düzen kaymasını öldürür -->
alt="{alt}" <!-- seçimden SONRA yazılır -->
fetchpriority="high" decoding="async"
style="background:{color_hex}"> <!-- baskın renk, 1 alan -->
<figcaption>{attribution.html}</figcaption>
</figure>
<!-- Bölüm görselleri, katlamanın altında: tam tersi ayarlar -->
<img src="{urls.regular}" width="{width}" height="{height}"
alt="{alt}" loading="lazy" decoding="async">
Hotlink mi barındırma mı? Yukarıdaki parça hotlink yapar, ki bu yayınlanacak en
hızlı şeydir ve preconnect'in nedeni budur: uzaktaki bir hero, kritik yolda bir DNS
aramasına ve bir TLS el sıkışmasına mal olur ve bu, fetchpriority ile satın
aldığınız kazancı yiyebilir. Yeniden barındırmak üçüncü taraf kaynağı tamamen ortadan kaldırır,
kendi kesim noktalarınızda AVIF/WebP sunmanıza izin verir ve bir üst akış URL'sinin değişmesine
dayanıklı kalır — depolama, hatta bir getirme adımı ve kendi CDN faturanız pahasına. Hangisini
seçerseniz seçin, color_hex tek bir alan için bir yer tutucu sağlar (bir blur hash
daha şık ama önce bir veri URI'sine kod çözülmesi gerekir — bir CSS rengi değildir). Kaba bir
hero'yu doğrudan background: içine kopyalamak, çoğu hattın sessizce boş gri bir
kutu yayınladığı yerdir.
-
Hero'yu asla lazy-load yapmayın. web.dev açık: “LCP görselinizi asla lazy-load
yapmayın, çünkü bu her zaman gereksiz kaynak yükleme gecikmesine yol açar ve LCP üzerinde olumsuz
bir etkisi olur” ve LCP olması muhtemel öğede — dikkatlice, tek bir görselde kullanılarak —
fetchpriority="high"önerir.4 Hero dahil her görseleloading="lazy"damgalayan bir hat, otomatik yayıncılıkta en yaygın kendi kendine verilen Core Web Vitals yarasıdır. -
Her zaman
widthveheightüretin — bunlar yanıtta geri gelir, dolayısıyla mazeret yoktur; tarayıcının alanı ayırmasını sağlayan ve düzenin zıplamasını durduran şey tam olarak bu özellik çiftidir. Dosya yüklenirken yer tutucu olarakblur_hashkullanın. -
Alt metni seçimden sonra yazın, asla önce değil. Bu incelikli olan.
Planın
altalanı istediğiniz sahneyi tanımlar; aldığınız fotoğraf en yakın eşleşmedir, o sahne değildir. Brief'in metnini alt olarak yayınlamak, bu hattın önlemesi gereken tam olarak erişilebilirlik hatasıdır — sayfada olmayan bir görselin açıklaması. Alt metni, seçilen fotoğrafınalt_description'ından oluşturun, içinde bulunduğu paragrafa göre inceltin. Google'ın tavsiyesi “anahtar kelimeleri uygun şekilde kullanan ve sayfanın içeriği bağlamında olan yararlı, bilgi açısından zengin içerik oluşturmaya odaklanmak”tır ve alt özniteliklerini anahtar kelimeyle doldurmanın “olumsuz bir kullanıcı deneyimine yol açacağı ve sitenizin spam olarak görülmesine neden olabileceği” konusunda uyarır.1
Neredeyse hiç kimsenin otomatikleştirmediği kısım: lisans meta verisi
Google, görsel lisanslama için ImageObject yapılandırılmış verisini destekler.
contentUrl artı creator, creditText,
copyrightNotice veya license'dan en az birini gerektirir,
acquireLicensePage'i önerir ve lisans bilgisi olan görseller Google Görseller'de
Lisanslanabilir rozeti için uygun hâle gelir.5 Bu alanların
her biri zaten arama yanıtındadır — bu yüzden onu yayınlamak bir proje değil, bir şablondur:
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "ImageObject",
"contentUrl": "{urls.large}", // zorunlu
"creator": { "@type": "Person",
"name": "{photographer_full_name}" },
"creditText": "{photographer_full_name} on {source}",
"license": "{LICENSE_URL[source]}", // kütüphanenin kendi sayfası
"acquireLicensePage": "{source_image_url}" // fotoğrafın sayfası
}
</script>
# LICENSE_URL, `source` alanını fotoğrafı gerçekten yöneten lisansa eşler
# — unsplash.com/license, pexels.com/license, pixabay.com/…
Doğru yapmaya değer bir ayrıntı: license, sizin alan adınızdaki bir özet sayfaya
değil, o fotoğrafı yöneten lisansa — kaynak kütüphanenin kendi lisans sayfasına —
işaret etmelidir. Google, rozet uygunluğuna karar vermek için onu okur ve kendine referans veren
bir URL, hem bir sinyal olarak daha zayıftır hem de kendinize geri dönen bir bağlantıdan başka
bir şey olarak savunulması zordur. Kendi lisans özetinizi okuyucular için dahili bir sayfa olarak
tutun; kanonik olanı işaretlemeye koyun.
Derleyicideyken: dosyaya IMG_0042.jpg yerine kısa, açıklayıcı bir isim verin ve
görseli bir site haritasına ekleyin — Google'ın görsel site haritası biçimi, sayfa URL'si başına
1.000'e kadar görsel kabul eder.6 İkisi de bir hatta birer satırdır
ve hiçbiri elle yapılmaz.
Çalmak için iki hat
Aynı beş aşama, çok farklı iki şekil — biri yazdığınız makaleler için, biri çalışan bir ürünle eşleşmesi gereken dokümantasyon için. Başarısızlık modunu tanıdığınızı seçin.
1 · CI'da geliştirici blogu — depodaki Markdown
Makaleler Markdown olarak bulunur, görseller yanlarına commit edilir ve her şey push'ta çalışır. Deterministik, PR'da incelenebilir, hiçbir API'ye çalışma zamanı bağımlılığı yok:
on: { pull_request: { paths: ["content/**.md"] } }
jobs:
illustrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: python plan_to_pr.py $(git diff --name-only origin/main -- 'content/*.md')
env:
PEXAFY_API_KEY: ${{ secrets.PEXAFY_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- uses: peter-evans/create-pull-request@v6 # görseller PR'a düşer
with: { commit-message: "chore(content): illustrate" }
Bir insan yine de PR'ı onaylar, mesele de bu: hat önerir, inceleyici karar verir ve yazdığı ön-madde fark alınabilirdir.
Arama kısmı tek bir GET'tir — isteği, score_threshold'u ve döndürdüğü
alanlar
tek makale
kılavuzunda satır satır yazılıdır, dolayısıyla burada yeniden basılmak yerine içe aktarılır.
Bu dosyanın eklediği şey, bir planın ihtiyaç duyduğu ve tek bir fotoğrafın ihtiyaç
duymadığı her şeydir: sonuç döndürmeyen bir brif için yeniden deneme, iki sayfanın aynı görseli
paylaşmaması için bir photo_id üzerinde hak talebi ve gelen fotoğraftan yazılan alt
metin.
import frontmatter
from photo_search import search # tek bir GET /search/photos; `used` içindeki id'leri atlar
def find_photo(entry: dict, used: set) -> dict | None:
"""Ara; brief çok özgülse bir kez genişlet, sonra vazgeç."""
orientation = entry.get("orientation", "landscape")
for query in (entry["query"], widen(entry["query"])):
photo = search(query, orientation, used)
if photo:
used.add(photo["photo_id"]) # talep et: site genelinde tekrar yok
return photo
return None # çağıran karar verir: slotu atla veya başarısız ol
def widen(query: str) -> str:
"""Son cümleyi bırak — genellikle aşırı özgül olan."""
return query.rsplit(" in ", 1)[0] if " in " in query else query
def illustrate(path: str, plan: dict, used: set) -> None:
post = frontmatter.load(path)
hero = find_photo(plan["hero"], used)
if hero is None: # hero olmaması, kötü bir hero'dan iyidir
raise SystemExit(f"{path}: no photo above threshold — rewrite the brief")
post["hero"] = { # şablonun ihtiyaç duyduğu her şey
"src": hero["urls"]["regular"], "w": hero["width"], "h": hero["height"],
# Alt, ALDIĞIMIZ fotoğrafı tanımlar, asla istediğimiz sahneyi değil.
"alt": alt_for(hero, section=post.get("title", "")),
"bg": hero["color_hex"], "credit": hero["attribution"]["html"],
"creator": hero["photographer_full_name"], "id": hero["photo_id"],
"source": hero["source"],
"source_url": hero["source_image_url"], # → acquireLicensePage
}
open(path, "w").write(frontmatter.dumps(post))
def alt_for(photo: dict, section: str) -> str:
"""alt_description'ı temel al, ekran okuyucular için ~125 karaktere kırp.
Daha iyisini istiyorsanız paragrafla birlikte modele geri gönderin."""
base = photo.get("alt_description") or photo.get("description", "")
return base[:125].rstrip(" ,;")
2 · Dokümantasyon & changelog — önce ekran görüntüleri, en son fotoğraflar
Yönlendiricinin varsayılanlarını tersine çevirin. Ürün dokümantasyonunda dürüst görsel neredeyse her zaman kendi UI'ınızdır: gerçek derlemeyi açan, sabit bir görünüm alanı ayarlayan ve paragrafın tanımladığı tam durumu yakalayan bir Playwright betiği. Diyagramlar mimari sayfaları kapsar ve fotoğraflar yalnızca kavramsal ve açılış sayfalarında görünür — bir ekran görüntüsünün hiçbir şey söylemeyeceği yerlerde.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1440, "height": 900},
device_scale_factor=2) # retina keskinliği
page.goto("http://localhost:3000/dashboard")
page.get_by_role("button", name="New API key").click()
page.screenshot(path="static/img/docs/new-api-key.png")
browser.close()
# Dokümantasyon derlemesiyle aynı CI işinde çalışır → ekran görüntüsü asla
# artık var olmayan bir UI sürümünü tanımlayamaz.
Adı verilmeye değer ama kendi tarifini hak etmeyen iki varyant. Programatik SEO
döngüyü tersine çevirir: bir veritabanından üretilen yüzlerce sayfayla sayfa başına arama yapmazsınız
— bir istek 100'e kadar fotoğraf döndürür, bu yüzden konu kümesi başına arama yapıp bir
havuzdan atarsınız, tekilleştirmeyi bir benzersizlik kısıtlaması yapar
(o mimari, tam olarak).
Ve bültenler ve sosyal medya kartları, aynı fotoğrafı dört kırpımda gerektirir:
photo_id'yi saklayın, urls'dan ihtiyacınız olan boyutu isteyin ve bir
kırpım gerçekten başarısız olduğunda ancak yeniden arama yapın.
Aynı hat, tek bir ajan olarak
Taslağı zaten bir model yazıyorsa, en kısa yol JSON'u süreçler arasında dolaştırmak yerine
arama aracını doğrudan modele vermektir. Pexafy, mcp.pexafy.com/mcp adresinde
barındırılan bir Model Context Protocol sunucusu çalıştırır. Bağlayıcı kurulumu
ve sunduğu araçlar başka yerlerde ele alınmıştır — masaüstü ve editör kurulumu
tekil makale kılavuzunda,
bir CI çalıştırıcısı için başsız (headless) varyant
ölçekte içerik hakkındaki makalede,
ve daha geniş bağlayıcı pazarının neye benzediği — kimin bir MCP görsel sunucusu sunduğu, hangi
şartlarla —
AI ajanları için görsel arama altyapısı incelemesinde
anlatılmıştır.
Burada göstermeye değer olan şey, ajan araçları elinde tuttuğunda bu ardışık düzenin
başına gelenlerdir: beş aşama olmaktan çıkar ve tek bir talimata dönüşür.
You İşte taslak. Görsel planı oluştur, illüstre et ve bir PR aç.
Grafikler yalnızca metinde zaten olan sayılardan.
Agent → plan: hero=photo · §2=chart · §3=diagram · §4=photo
→ search_photos(q="a developer working late at a desk with two
monitors and a mechanical keyboard in a dark room…")
← 16 fotoğraf · 147 ms · #1 seçildi, 3000×1688, kaynağı belirtildi
→ mermaid-cli build/graph.mmd → static/img/graph.svg
→ chart.py §2 → taslağa karşı doğrulanan 4 değer ✓
→ search_photos(q="two engineers standing at a whiteboard…")
← 16 fotoğraf · 144 ms · #1 seçildi
✓ 4 slot dolduruldu · 2 API çağrısı · alt + kredi + ImageObject yazıldı
⚠ §5, 0.5 üzerinde hiçbir şey döndürmedi — brief çok soyuttu, şu şekilde
yeniden yazıldı: "bir mutfak masasında dizüstü bilgisayarda rakamları
kontrol eden bir kişi"
Bu son satır, saf bir betik yerine bu döngüde bir ajanın bulundurulmaya değer olmasının nedenidir: otomatik illüstrasyonun başarısızlık modu kötü bir brief'tir ve kötü bir brief'i yeniden yazmak tam olarak bir dil modelinin işidir. Deterministik parçaları — atama, tekilleştirme, sayısal koruma — kodda tutun.
Bir illüstre makale neye mal olur
Makale başına üç fotoğraf slotu üç arama isteği anlamına gelir, dolayısıyla ücretsiz plan (ayda 5,000 istek), ayda 1,666 makaleyi herhangi bir ödeme sorusu ortaya çıkmadan kapsar — ve aramaları makale başına değil konu kümesi başına havuzlarsanız, bu tavan bir kat daha büyüklük sırası hareket eder. Plan bazında dökümü ve bunu önemsiz kılan havuzlama mimarisi ölçekte içeriği illüstre etme üzerine yardımcı makalede.
Makale başına iki model çağrısı — biri taslak için, biri görsel plan için — birkaç bin token tutar ve hattaki en ucuz satır olacaktır; Mermaid ve matplotlib render'ları CI saniyeleri dışında hiçbir şeye mal olmaz. İnsanları şaşırtan sayı, hangi satırın ucuz olmadığıdır: makale başına dört görsel üretmek, ayda dört yüz görsel, artı işi başaramayan denemeler — ve çıktı yine de hiçbir fotoğrafçı, tarih veya kaynak URL taşımaz.
Bu hattın çözmediği şey
Dürüst bir bölüm, çünkü önlediği başarısızlık pahalıdır. İyi illüstre edilmiş bir makale hâlâ bir makaledir: gerçek fotoğrafçılık, doğru grafikler ve doğru işaretleme, var olmayı hak eden bir sayfayı iyileştirir. İnce, kitlesel olarak üretilmiş içeriğin sıralanmasını sağlamazlar. Google'ın spam politikaları ölçekli içerik istismarını adlandırır — sıralamaları manipüle etmek amacıyla birçok sayfa üretmek ve kullanıcılara çok az değer sunmak, otomasyon dahil olsun olmasın — ve illüstrasyonların kalitesi bu değerlendirmede bir faktör değildir.7
Yani ayakta kalan çerçeve şudur: bu hat, zaten yayınlanmak için bir nedeni olan sayfalara uygulanan kontrol ettiğiniz bir kalite tabanıdır. Belirgin şekilde işe yaradığı yerler:
- Okuyucunun doğrulayabileceği köken. Gerçek bir fotoğrafçı ve kaynak URL'si
olan bir kredi satırı, kontrol edilebilir bir iddiadır — ve aynı alanlar Google'ın okuduğu
ImageObjectişaretlemesini besler. - Erişilebilirlik ve Core Web Vitals. Gerçek alt metin, her görselde boyutlar, asla lazy-load edilmeyen bir hero. Yayınladığınız her makaleyle çarpın ve bu, sitenin görsel kalitesi hikâyesi hâline gelir.
- Kontrol edilebilir olan yerde doğruluk. Sayıları makaleye karşı doğrulanan bir grafik, çalışan derlemeden üretilmiş bir ekran görüntüsü, PR'da metin olarak incelenebilir bir diyagram — bir testin başarısız olmadan gerçeklerden sapamayacağı üç görsel.
Atıf konusunda, boru hattına özel nokta dardır:
kredinin her zaman
gösterilmesi gerektiği argümanı başka yerde yapılıyor, ve otomatik bir birleştiricinin
eklediği şey, bastığı aynı attribution dizesinin, yapılandırılmış verinin ihtiyaç
duyduğu creditText olmasıdır. Bir alan, iki yer, aynı şablon geçişinde yayınlanır —
bu yüzden bir boru hattının bunu es geçmek için bir insandan daha bile az bahanesi vardır.
Nereden başlanır
- Yönlendirici promptu ekleyin taslaklarınızı zaten yazan şeye ve JSON'u ona göre hareket etmeden yazdırın. On plan okuyun. Brief'ler sahne yerine konu adlandırıyorsa, herhangi bir entegrasyon yazmadan önce prompt'u düzeltin.
- Yalnızca fotoğraf slotlarını kablolayın. Brief başına bir
GET /search/photosve ilk günden itibarenphoto_id'yi saklayın — 3.000 canlı sayfada sonradan uygulanan tekilleştirme bir sütun değil, bir geçiştir. - Genişlik, yükseklik ve alt üretin aynı commit'te. Yapacağınız en ucuz Core Web Vitals çalışmasıdır.
- Sonra aşama 4'ü ekleyin, grafiklerden önce diyagramlar — Mermaid metindir, bu yüzden bir sözdizimi hatasının ötesinde başarısızlık modu olmayan tek olanıdır.
- Sayısal korumayı ekleyin ilk grafik bir okuyucuya ulaşmadan önce, sonra değil.
Kaynaklar & dipnotlar
1 Google Search Central, Görsel SEO en iyi uygulamaları:
alt metin “bir görsel için meta veri sağlama söz konusu olduğunda en önemli özelliktir”; tavsiye
“anahtar kelimeleri uygun şekilde kullanan ve sayfanın içeriği bağlamında olan yararlı, bilgi
açısından zengin içerik” oluşturmak, anahtar kelimeyle doldurulmuş alt özniteliklerinden
kaçınmak, CSS görselleri yerine HTML <img> öğeleri kullanmak ve dosyalara kısa
ama açıklayıcı isimler vermektir.
2 AB Yapay Zeka Yasası, Madde 50 — 2 Ağustos 2026'dan itibaren geçerli şeffaflık yükümlülükleri: sentetik görsel, ses, video veya metin üreten sistem sağlayıcıları, çıktıları makine tarafından okunabilir bir biçimde işaretlemeli ve yapay olarak üretildiğinin tespit edilebilir olmasını sağlamalıdır. Yapay zeka sağlayıcılarını ve dağıtıcılarını bağlar; bir web sitesinin hangi görselleri yayınlayabileceğine dair bir kural değildir.
3 Mermaid, diyagramları ve grafikleri Markdown'dan esinlenilmiş metin tanımlarından render eder, ki bu çıktıyı incelenebilir ve deterministik yapan şeydir.
4 web.dev, En Büyük İçerik Boyaması'nı Optimize Etme:
“Bir <img> öğesinin sayfanızın LCP öğesi olma olasılığı yüksekse üzerine
fetchpriority="high" ayarlamak iyi bir fikirdir”, dikkatlice kullanılır; ve “LCP
görselinizi asla lazy-load yapmayın, çünkü bu her zaman gereksiz kaynak yükleme gecikmesine yol
açar ve LCP üzerinde olumsuz bir etkisi olur.”
5 Google Search Central, Görsel meta verisi (yapılandırılmış
veri): ImageObject, contentUrl artı creator,
creditText, copyrightNotice veya license'dan en az birini
gerektirir; acquireLicensePage önerilir ve lisans bilgisi taşıyan görseller Google
Görseller'de Lisanslanabilir rozeti için uygun hâle gelebilir.
6 Google Search Central, Görsel site haritaları: görsel site haritaları, JavaScript aracılığıyla bulunanlar dahil olmak üzere bir sitedeki görseller hakkında Google'ı bilgilendirir ve sayfa URL'si başına 1.000'e kadar görsel kabul eder.
7 Google Arama spam politikaları — ölçekli içerik istismarı: otomasyon, insan çabası veya bir kombinasyonuyla oluşturulmuş olsun olmasın, sıralamaları manipüle etmek amacıyla birçok sayfa üretmek ve kullanıcılara çok az değer sunmak.
Kaynaklar 17 Ağustos 2026 tarihinde kontrol edildi: Görsel SEO en iyi uygulamaları · Görsel meta verisi · Görsel site haritaları · LCP'yi Optimize Et · Arama spam politikaları · AI Act Madde 50 · Mermaid · Pexafy API & MCP dokümantasyonu. Arama süreleri (147 ms, 144 ms) ve gösterilen her fotoğraf, aynı gün yakalanan gerçek API yanıtlarıdır.
Sıkça sorulan sorular
Bir LLM tarafından yazılan makaleleri otomatik olarak nasıl görselleştiririm?
GET /api/v1/search/photos, yaklaşık 150 ms). Grafik ve diyagram girişleri, çizim kodu veya Mermaid yazan bir modele gönderilir ve deterministik olarak render edilir. Makale başlığını asla bir görsel aramaya beslemeyin: başlıklar soyuttur ve hiçbir fotoğraf onları tasvir etmez.Bir dokümantasyon sitesi ekran görüntüsü mü yoksa stok fotoğraf mı kullanmalı?
Bir yapay zekâ pipeline'ının bir grafiğe yanlış sayılar koymasını nasıl önlerim?
data alanına kopyalayabilir. Ardından render etmeden önce bunu kodda doğrulayın — her değer için, dizesinin makalede göründüğünü kontrol edin, yoksa hata verin. Dokuz satır, ve kendi paragrafıyla çelişen bir grafik asla bir okuyucuya ulaşamaz.Otomatikleştirilmiş bir pipeline, SEO için hangi görsel markup'ını üretmeli?
alt — Google, alt metnini en önemli görsel meta verisi olarak tanımlar ve anahtar kelime doldurmaya karşı uyarır. Her görselde width ve height, hero görselinde fetchpriority="high" ve asla üzerinde loading="lazy" olmamalı, çünkü LCP görseli geç yüklenmemelidir (lazy load edilmemelidir). Ve contentUrl, creator, creditText ve license içeren ImageObject yapılandırılmış verisi, bu da bir görselin Google Görseller'de Lisanslanabilir rozetine hak kazanmasını sağlayan şeydir.Yapay zekâ tarafından yazılmış makaleleri görselleştirmek sıralamada yardımcı olur mu?
Editoryal kontrolü kaybetmeden görselleştirme adımını CI'da nasıl çalıştırırım?
photo_id ile tekrarları ayıklama, grafiğe dökülen her sayının makalede geçtiğine dair doğrulama ve hiçbir fotoğraf puan eşiğini geçemediğinde sert bir hata verme. Hiç görsel olmaması, yanlış bir görselden daha iyidir.