Faturadan tarih, tutar, firma ve VKN’yi elle bir tabloya taşımak, az sayıda faturada can sıkıcı bir iş. Sayılar büyüyünce de hataya açık bir iş: bir satır kaydırırsan iki fatura birden yanlış olur. Bu yüzden bu işi bir otomasyona oturtmaya karar verdim. Sandığımdan zordu — ama ilginç olan, zorluğun nereden geldiğiydi.
Sorun, biçim çeşitliliği
İşin başında klasik bir otomasyon denemesi yaptım: fatura düzenlerini inceledim, alanların yerlerini buldum, kurallar yazdım. Sonra ilk yeni şablonda her şey kırıldı. Çünkü Türkiye’de “e-fatura” deyince tek bir şey yok: bazıları yapısal UBL XML, bazıları düz PDF, bazıları da taranmış görüntü. Ve her firmanın yerleşimi birbirinden farklı. Sabit kurallara dayanan bir ayrıştırıcı, daha önce görmediği her düzende yeniden baştan yazılmak zorunda.
Bu noktada yaklaşımı değiştirdim: şablon tanımak yerine belgeyi anlaması için işi bir dil modeline devrettim.
Gemini’ye okutmak
Uygulama her faturayı önce türüne göre ayırıyor. UBL XML zaten yapısal olduğu için kurallarla doğrudan ayrıştırılıyor — orada modele gerek yok. Geri kalanını Google Gemini okuyor: dijital PDF’te metin üzerinden, taranmış belgede görüntü üzerinden. Model yerleşim bilmiyor, belgeyi anlıyor; dolayısıyla daha önce görmediği bir fatura düzeni de çalışıyor.
Çıkarılacak alanlar tek bir prompt şablonunda tanımlı. Yeni bir alan eklemek yeni kod yazmak değil, o şablonu güncellemek demek — bu, projenin en çok işime yarayan kararı oldu.
Model çıktısına körü körüne güvenmedim
Modelin çıktısını doğrudan Excel’e yazdırmak cazip ama yanlış olurdu. Araya bir gözden geçirme ekranı koydum: fatura numarası uzunluğu, VKN biçimi ve KDV tutarlılığı gibi kontrollerin uyarıları ilgili alanın altında görünüyor. Onaylamazsan dosyaya dokunulmuyor. Yani makine öneriyor, insan karar veriyor.
Bir de zamanla öğrenen bir detay var: bir firmanın adını düzeltip “bu firma için hatırla” dersen, aynı VKN’li sonraki faturalarda düzeltme otomatik uygulanıyor. İlk seferde yanlış okunan şey ikincide tekrar sormuyor.
Küçük mühendislik kararları
- Beş iş parçacığıyla paralel işleme; ücretsiz kotayı aşmamak için dakikada 14 istekle sınırlı.
- Daha önce işlenmiş faturalar atlanıyor — tekrar çalıştırınca baştan başlamıyor.
- Excel çıktısında her satırın hangi yolla okunduğu yazıyor: Dijital, OCR veya XML. Kaynak dosyaya tıklanabilir bağlantı ve aylık-firma bazlı özet sayfası da çıkıyor.
- Arayüz pywebview penceresinde çalışan HTML/CSS/JS; mantık tümüyle Python tarafında. 179 testlik pytest paketi arkada duruyor — model çıktısına güvenmek yerine kendi koduna güvenmek için.
Neyi farklı yapardım
İlk denememi kurallarla yapıp zaman kaybetmeseydim iyi olurdu regex bu tarz işler için gerçekten zaman kaybı bir standart lazım onun için. Çeşitlilik gösteren belgelerde kural yazmak, model kullanmaktan daha “kontrollü” hissettiriyor ama kontrol illüzyonu: her yeni şablon yeni kural demek. Modelin çıktısını doğrulama katmanıyla kontrol etmek hem daha az kod hem daha sağlam çıktı.
Asıl öğrendiğim şu: bu işin püf noktası model seçimi değil, modelin çıktısını nasıl çerçevelediğin. Okuma işini modele, doğrulamayı kurallara, kararı insana bırakınca her parça kendi işini yapıyor.