Problem
BTK Akademi Hackathon 2026'nın finans konseptinde çalıştım. Ele aldığım somut sorun şu: yüksek enflasyon ortamında bütçe yönetmek isteyen biri, harcama listesini kendi başına anlamlı kategorilere ayırmakta ve buradan uygulanabilir bir plana geçmekte zorlanıyor. Elektronik tablo tutmak veri girişi problemi çözüyor ama yorumlama problemini çözmüyor. Amacım harcama satırlarını serbest metinden alıp kategorize eden ve üzerine Türkiye bağlamında bütçe planı üretebilen bir arka uç kurmaktı.
Yaklaşım
FastAPI arka ucu dört uç sunuyor: /chat (çok turlu sohbet), /harcama-analiz (agentik kategorize + rapor), /butce-olustur (bütçe planı) ve /health. Model gemini-2.5-flash, erişim google-genai SDK'sı üzerinden. Kategorize işini serbest metne bırakmak yerine bir function declaration olarak tanımladım: kategorize_harcama aracı, kategoriyi kapalı bir enum'dan (gida, ulasim, kira_aidat, faturalar, eglence, saglik, giyim, egitim, tasarruf, diger), risk seviyesini üç kademeden seçmek ve kısa bir öneri döndürmek zorunda. Analiz akışı iki turlu: birinci çağrı tool call'ları üretiyor, kod bunları toplayıp kategori dağılımını sayıyor, ikinci çağrı bu dağılımı prompta geri koyarak markdown raporu yazdırıyor. Ön yüz React 18 + Vite; sohbet geçmişi istemciden geliyor ve build_contents ile Gemini'nin user/model rol biçimine çevriliyor, yani sunucu oturum tutmuyor.
Kararlar ve takaslar
- Kategorize işini serbest metin yerine Gemini function calling ile yaptım (types.FunctionDeclaration + enum'lu types.Schema), çünkü kategorilerin sabit bir kümeden gelmesini ve zorunlu alanların şemayla garanti edilmesini istedim; alternatif modelden JSON istemekti, o zaman kategori adları koşumlar arasında kayıyor ve ayrıştırma hatalarını elle yakalamak gerekiyordu.
- Harcama analizini iki çağrıya böldüm: önce tool call turu, sonra toplanan kategori dağılımı prompta geri verilerek rapor turu. Çünkü tek turda hem yapılandırılmış kategori çıktısı hem uzun markdown rapor istemek ikisini birden zayıflatıyordu; alternatif tek çağrıydı ve bir istek fazladan gecikme karşılığında daha temiz bir ayrım aldım.
- Sıcaklığı uç ve tur başına ayarladım: sohbet 0.7; harcama analizinin kategorize turu 0.3, rapor turu 0.5; bütçe 0.4. Kategorize turunda tutarlılık, rapor turunda biraz daha akıcılık istedim. Çünkü sohbet akıcılık isterken kategorize ve rapor tutarlılık istiyor; alternatif tek bir global sıcaklıktı, o da ya sohbeti kuru ya analizi savruk yapıyordu.
- Sistem promptunu tek bir sabitte topladım ve içine açık sınır yazdım ("kesin yatırım tavsiyesi verme, genel bilgi çerçevesinde kal", finans dışı soruyu kibarca reddet). Çünkü finans alanında model kendiliğinden tavsiye kipine kayıyor; alternatif sınırı her endpoint'in prompt'una dağıtmaktı, o zaman uçlar arasında tutarsızlaşıyordu.
- API anahtarı yoksa client'ı None bırakıp uçların 500 dönmesini seçtim, çünkü anahtarsız durumda sessizce sahte/boş cevap üretmesindense açıkça hata vermesi doğru; alternatif varsayılan bir sahte cevap döndürmekti, o demo sırasında gerçek cevapla karışabilirdi.
Sonuç
ÖLÇÜM YOK — bu projede hiçbir sayı iddia edemem, çünkü depoda test, değerlendirme seti ya da koşum kaydı yok. Somut çıktı şudur: dört uçlu çalışan bir FastAPI servisi (chat, harcama-analiz, butce-olustur, health), enum kısıtlı tek bir tool declaration'ı, iki turlu analiz akışı, uç başına sıcaklık ayarı ve React 18 + Vite ön yüzü. /harcama-analiz cevabı analiz metninin yanında toplam harcamayı, kategori dağılımını ve kaç agent çağrısı yapıldığını (agent_calls) döndürüyor — yani agentik davranış istemciye ölçülebilir biçimde raporlanıyor. Depodaki CLAUDE.md yarışma takvimini veriyor: teslim 19.05.2026, ön jüri 20-30.05.2026, jüri sunumu 05.06.2026. Depoda yarışma SONUCU, puan ya da derece bilgisi YOK; bu sayfa bir sonuç iddia etmiyor. Dürüst bir teknik borç notu: frontend/src altında Vite'ın vanilla-TypeScript şablonundan kalan kullanılmayan dosyalar duruyor (main.ts, counter.ts, style.css, assets/typescript.svg) — index.html yalnızca /src/main.jsx yüklüyor, yani bunlar ölü dosya.
Teknolojiler
Kaynaklar
Bu sayfadaki teknik iddialar aşağıdaki kaynaklardan çıkarıldı.
- https://github.com/msgxr/KizilelmaAI
- https://github.com/msgxr/KizilelmaAI/blob/main/README.md
- https://github.com/msgxr/KizilelmaAI/blob/main/src/api.py
- https://github.com/msgxr/KizilelmaAI/blob/main/src/main.py
- https://github.com/msgxr/KizilelmaAI/blob/main/requirements.txt
- https://github.com/msgxr/KizilelmaAI/blob/main/frontend/package.json
- https://github.com/msgxr/KizilelmaAI/blob/main/frontend/index.html
- https://github.com/msgxr/KizilelmaAI/blob/main/CLAUDE.md
Doğrulayamadıklarım
Metni yazarken teyit edemediğim noktalar. Görünür tutuyorum — teyitsizi sessizce iddia etmektense.
- lib/projects.ts stack'i ['JavaScript','Google Gemini','CSS','HTML'] diyor — bu GERÇEK YIĞINI YANLIŞ GÖSTERİYOR. Depoda Python 3.11 + FastAPI + uvicorn + google-genai arka ucu ve React 18 + Vite ön yüzü var; 'HTML' ve 'CSS' etiketleri asıl işi gizliyor. GitHub'ın dili 'CSS' göstermesi App.css'in (8.5 KB) büyüklüğünden kaynaklanıyor, projenin doğasından değil. Kart dili de 'CSS / JavaScript' diyor; 'Python / JavaScript' olmalı.
- DOGRULANAMADI: Yarışma sonucu, puanı veya derecesi. Depoda yalnızca takvim ve jüri kriter başlıkları var (CLAUDE.md), hiçbir sonuç kaydı yok. Vaka sayfası derece/başarı iddia ETMEMELİ.
- DOGRULANAMADI: CLAUDE.md zorunlu teslim olarak "1 dakikalık video" ve opsiyonel "canlı link" listeliyor; depoda ne video linki ne dağıtım yapılandırması var. Canlı demo YOK (GitHub Pages API 404) ve ön yüz localhost:5173 / arka uç localhost:8000 varsayıyor.
- DOGRULANAMADI: CLAUDE.md agentic katman için "LangGraph veya google-genai ile tool calling" diyor; gerçekleşen yol google-genai tool calling. LangGraph depoda hiç kullanılmıyor — plan belgesindeki alternatif, uygulanmış mimari değil.
- Kodda doğrulanmış güvenlik notu (vaka sayfasında övgüye çevrilmemeli): CORS allow_origins=["*"] ile tamamen açık. Hackathon demosu için anlaşılır, üretim duruşu olarak sunulamaz.
- DOGRULANAMADI: README "Türkiye'de milyonlarca kişi bütçe yönetiminde zorlanmakta" diyor; bu bir kaynak gösterilmeyen pazar iddiası, ölçüm değil. Problem metninde bunu sayısal iddiaya çevirmedim.