CRANE AI ZeroGPU Space yüklendi
Browse files- README.md +98 -289
- app.py +143 -333
- config/__init__.py +16 -0
- config/settings.py +97 -0
- core/__init__.py +12 -0
- core/base_module.py +177 -0
- core/token_capsule.py +316 -0
- download_models.py +161 -0
- memory/__init__.py +7 -0
- memory/local_memory.py +324 -0
- modules/__init__.py +15 -0
- modules/chat_module.py +142 -0
- modules/code_module.py +172 -0
- modules/fast_module.py +258 -0
- modules/reason_module.py +196 -0
- requirements.txt +15 -7
- router/__init__.py +7 -0
- router/intelligent_router.py +306 -0
- setup.py +186 -0
- tools/__init__.py +7 -0
- tools/weather_tool.py +135 -0
- training/__init__.py +1 -0
- training/fine_tune.py +96 -0
README.md
CHANGED
|
@@ -1,289 +1,98 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom: red
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 4.
|
| 8 |
-
app_file:
|
| 9 |
-
pinned: false
|
| 10 |
-
license: mit
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
-
|
| 14 |
-
|
| 15 |
-
-
|
| 16 |
-
-
|
| 17 |
-
- turkish
|
| 18 |
-
-
|
| 19 |
-
-
|
| 20 |
-
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
-
|
| 34 |
-
-
|
| 35 |
-
-
|
| 36 |
-
-
|
| 37 |
-
|
| 38 |
-
##
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
-
|
| 48 |
-
-
|
| 49 |
-
-
|
| 50 |
-
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
- **
|
| 56 |
-
- **
|
| 57 |
-
- **
|
| 58 |
-
- **
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
-
|
| 81 |
-
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 100 |
-
import torch
|
| 101 |
-
|
| 102 |
-
# Nova AI modelini yükle
|
| 103 |
-
model_name = "Teknova/NovaAI"
|
| 104 |
-
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 105 |
-
model = AutoModelForCausalLM.from_pretrained(
|
| 106 |
-
model_name,
|
| 107 |
-
torch_dtype=torch.float16,
|
| 108 |
-
device_map="auto"
|
| 109 |
-
)
|
| 110 |
-
|
| 111 |
-
# Sohbet örneği
|
| 112 |
-
def chat_with_nova(message):
|
| 113 |
-
conversation = f"Kullanıcı: {message}\nNova AI:"
|
| 114 |
-
inputs = tokenizer(conversation, return_tensors="pt")
|
| 115 |
-
|
| 116 |
-
with torch.no_grad():
|
| 117 |
-
outputs = model.generate(
|
| 118 |
-
**inputs,
|
| 119 |
-
max_new_tokens=512,
|
| 120 |
-
temperature=0.7,
|
| 121 |
-
top_p=0.9,
|
| 122 |
-
do_sample=True,
|
| 123 |
-
pad_token_id=tokenizer.eos_token_id
|
| 124 |
-
)
|
| 125 |
-
|
| 126 |
-
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 127 |
-
return response[len(conversation):].strip()
|
| 128 |
-
|
| 129 |
-
# Örnek kullanım
|
| 130 |
-
response = chat_with_nova("Merhaba Nova AI, nasılsın?")
|
| 131 |
-
print(response)
|
| 132 |
-
```
|
| 133 |
-
|
| 134 |
-
### 🌐 **API ile Kullanım**
|
| 135 |
-
```python
|
| 136 |
-
import requests
|
| 137 |
-
|
| 138 |
-
API_URL = "https://api-inference.huggingface.co/models/Teknova/NovaAI"
|
| 139 |
-
headers = {"Authorization": "Bearer YOUR_HF_TOKEN"}
|
| 140 |
-
|
| 141 |
-
def query_nova_ai(payload):
|
| 142 |
-
response = requests.post(API_URL, headers=headers, json=payload)
|
| 143 |
-
return response.json()
|
| 144 |
-
|
| 145 |
-
# Örnek sorgu
|
| 146 |
-
output = query_nova_ai({
|
| 147 |
-
"inputs": "Yapay zeka teknolojileri hakkında bilgi ver",
|
| 148 |
-
"parameters": {
|
| 149 |
-
"max_new_tokens": 256,
|
| 150 |
-
"temperature": 0.7,
|
| 151 |
-
"top_p": 0.9
|
| 152 |
-
}
|
| 153 |
-
})
|
| 154 |
-
print(output)
|
| 155 |
-
```
|
| 156 |
-
|
| 157 |
-
---
|
| 158 |
-
|
| 159 |
-
## 💡 **Örnek Kullanım Alanları**
|
| 160 |
-
|
| 161 |
-
### 🎯 **Sohbet ve Asistan**
|
| 162 |
-
- Müşteri hizmetleri chatbotu
|
| 163 |
-
- Kişisel asistan uygulamaları
|
| 164 |
-
- Eğitim ve öğretim desteği
|
| 165 |
-
|
| 166 |
-
### 📝 **İçerik Üretimi**
|
| 167 |
-
- Blog yazısı ve makale yazımı
|
| 168 |
-
- Sosyal medya içeriği
|
| 169 |
-
- Yaratıcı yazım desteği
|
| 170 |
-
|
| 171 |
-
### 🔍 **Analiz ve Özetleme**
|
| 172 |
-
- Metin analizi ve özetleme
|
| 173 |
-
- Duygu analizi
|
| 174 |
-
- Bilgi çıkarma
|
| 175 |
-
|
| 176 |
-
---
|
| 177 |
-
|
| 178 |
-
## ⚙️ **Model Parametreleri**
|
| 179 |
-
|
| 180 |
-
| Parametre | Değer | Açıklama |
|
| 181 |
-
|-----------|-------|----------|
|
| 182 |
-
| `temperature` | 0.7 | Yaratıcılık seviyesi (0.1-1.5) |
|
| 183 |
-
| `top_p` | 0.9 | Nucleus sampling |
|
| 184 |
-
| `max_new_tokens` | 512 | Maksimum yanıt uzunluğu |
|
| 185 |
-
| `repetition_penalty` | 1.1 | Tekrar önleme |
|
| 186 |
-
|
| 187 |
-
---
|
| 188 |
-
|
| 189 |
-
## 🎨 **Demo ve Uygulamalar**
|
| 190 |
-
|
| 191 |
-
### 🌐 **Web Arayüzü**
|
| 192 |
-
- **Gradio Demo:** [Nova AI Chat](https://huggingface.co/spaces/Teknova/NovaAI-Chat)
|
| 193 |
-
- **HTML Arayüz:** Kendi web sitenizde kullanabilirsiniz
|
| 194 |
-
|
| 195 |
-
### 📱 **Entegrasyon**
|
| 196 |
-
```javascript
|
| 197 |
-
// Web sitesinde kullanım örneği
|
| 198 |
-
const API_URL = 'https://api-inference.huggingface.co/models/Teknova/NovaAI';
|
| 199 |
-
|
| 200 |
-
async function queryNovaAI(text) {
|
| 201 |
-
const response = await fetch(API_URL, {
|
| 202 |
-
headers: {
|
| 203 |
-
'Authorization': 'Bearer YOUR_TOKEN',
|
| 204 |
-
'Content-Type': 'application/json'
|
| 205 |
-
},
|
| 206 |
-
method: 'POST',
|
| 207 |
-
body: JSON.stringify({
|
| 208 |
-
inputs: text,
|
| 209 |
-
parameters: {
|
| 210 |
-
max_new_tokens: 256,
|
| 211 |
-
temperature: 0.7
|
| 212 |
-
}
|
| 213 |
-
})
|
| 214 |
-
});
|
| 215 |
-
|
| 216 |
-
return await response.json();
|
| 217 |
-
}
|
| 218 |
-
```
|
| 219 |
-
|
| 220 |
-
---
|
| 221 |
-
|
| 222 |
-
## 📊 **Performans**
|
| 223 |
-
|
| 224 |
-
### 🚀 **Hız ve Verimlilik**
|
| 225 |
-
- **CPU Modunda:** ~2-3 saniye yanıt süresi
|
| 226 |
-
- **GPU Modunda:** ~0.5-1 saniye yanıt süresi
|
| 227 |
-
- **Bellek Kullanımı:** ~14.5GB model boyutu
|
| 228 |
-
- **Optimizasyon:** 4-bit quantization desteği
|
| 229 |
-
|
| 230 |
-
### 🎯 **Kalite Metrikleri**
|
| 231 |
-
- **Türkçe Doğruluk:** Yüksek seviyede Türkçe anlama
|
| 232 |
-
- **Bağlamsal Tutarlılık:** Uzun konuşmalarda tutarlı yanıtlar
|
| 233 |
-
- **Yaratıcılık:** Özgün ve çeşitli içerik üretimi
|
| 234 |
-
|
| 235 |
-
---
|
| 236 |
-
|
| 237 |
-
## 🔧 **Sistem Gereksinimleri**
|
| 238 |
-
|
| 239 |
-
### 💻 **Minimum Gereksinimler**
|
| 240 |
-
- **RAM:** 16GB (4-bit quantization ile)
|
| 241 |
-
- **GPU:** 8GB VRAM (RTX 3070 veya üzeri)
|
| 242 |
-
- **CPU:** 4 çekirdek, 2.5GHz+
|
| 243 |
-
- **Depolama:** 20GB boş alan
|
| 244 |
-
|
| 245 |
-
### 🚀 **Önerilen Gereksinimler**
|
| 246 |
-
- **RAM:** 32GB
|
| 247 |
-
- **GPU:** 16GB+ VRAM (RTX 4080/4090)
|
| 248 |
-
- **CPU:** 8+ çekirdek, 3.0GHz+
|
| 249 |
-
- **Depolama:** SSD, 50GB+ boş alan
|
| 250 |
-
|
| 251 |
-
---
|
| 252 |
-
|
| 253 |
-
## 📜 **Lisans ve Kullanım**
|
| 254 |
-
|
| 255 |
-
Bu model **Apache 2.0** lisansı altında yayınlanmıştır. Ticari ve akademik kullanım için serbesttir.
|
| 256 |
-
|
| 257 |
-
### ⚠️ **Önemli Notlar**
|
| 258 |
-
- Model özgün Teknova teknolojisi içermektedir
|
| 259 |
-
- Türkçe optimizasyonları Teknova tarafından geliştirilmiştir
|
| 260 |
-
- Responsible AI ilkelerine uygun olarak kullanılmalıdır
|
| 261 |
-
|
| 262 |
-
---
|
| 263 |
-
|
| 264 |
-
## 🏢 **Teknova Hakkında**
|
| 265 |
-
|
| 266 |
-
**Teknova**, Türkiye'nin öncü yapay zeka teknoloji şirketidir. Özgün AI çözümleri geliştirerek teknoloji dünyasında fark yaratmayı hedefliyoruz.
|
| 267 |
-
|
| 268 |
-
### 🎯 **Misyonumuz**
|
| 269 |
-
Yapay zeka teknolojilerini Türkçe konuşan kullanıcılar için optimize etmek ve erişilebilir kılmak.
|
| 270 |
-
|
| 271 |
-
### 🚀 **Vizyonumuz**
|
| 272 |
-
Türkiye'den dünyaya özgün yapay zeka teknolojileri ihraç etmek.
|
| 273 |
-
|
| 274 |
-
---
|
| 275 |
-
|
| 276 |
-
## 📞 **İletişim ve Destek**
|
| 277 |
-
|
| 278 |
-
- **🌐 Website:** [teknova.ai](https://teknova.ai)
|
| 279 |
-
- **📧 E-posta:** info@teknova.ai
|
| 280 |
-
- **💬 Destek:** [GitHub Issues](https://github.com/teknova-ai/nova-ai/issues)
|
| 281 |
-
- **📱 Sosyal Medya:** [@TeknovaAI](https://twitter.com/TeknovaAI)
|
| 282 |
-
|
| 283 |
-
---
|
| 284 |
-
|
| 285 |
-
## 🙏 **Teşekkürler**
|
| 286 |
-
|
| 287 |
-
Nova AI'yi kullandığınız için teşekkürler! Geri bildirimleriniz bizim için değerlidir.
|
| 288 |
-
|
| 289 |
-
**Teknova Nova AI** - *Türkiye'nin Özgün Yapay Zeka Teknolojisi* 🚀
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: CRANE AI ZeroGPU
|
| 3 |
+
emoji: 🏗️
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: blue
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 4.29.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
hardware: zero-gpu
|
| 12 |
+
tags:
|
| 13 |
+
- ai
|
| 14 |
+
- multi-model
|
| 15 |
+
- zero-gpu
|
| 16 |
+
- crane
|
| 17 |
+
- turkish
|
| 18 |
+
- code-generation
|
| 19 |
+
- chat
|
| 20 |
+
- reasoning
|
| 21 |
+
language:
|
| 22 |
+
- tr
|
| 23 |
+
- en
|
| 24 |
+
short_description: CRANE AI Hibrit Yapay Zeka Sistemi - ZeroGPU Powered
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
# 🏗️ CRANE AI - ZeroGPU Powered
|
| 28 |
+
|
| 29 |
+
**Hibrit Yapay Zeka Sistemi** - HuggingFace ZeroGPU ile güçlendirilmiş
|
| 30 |
+
|
| 31 |
+
## 🔥 ZeroGPU Features
|
| 32 |
+
|
| 33 |
+
- **Ücretsiz GPU Erişimi**: HuggingFace'in ücretsiz GPU kaynaklarını kullanır
|
| 34 |
+
- **Hızlı Model Yükleme**: GPU'da optimize edilmiş model başlatma
|
| 35 |
+
- **Akıllı Router Sistemi**: Görevlere göre en uygun modeli seçer
|
| 36 |
+
- **Hibrit Mimari**: Birden fazla küçük model birlikte çalışır
|
| 37 |
+
|
| 38 |
+
## 🧠 Sistem Mimarisi
|
| 39 |
+
|
| 40 |
+
### MicroModule System
|
| 41 |
+
- **FastModule**: TinyLlama (hızlı yanıt)
|
| 42 |
+
- **CodeModule**: DeepSeek-Coder (kod yazma)
|
| 43 |
+
- **ChatModule**: Qwen2.5 (sohbet)
|
| 44 |
+
- **ReasonModule**: Phi-3 (mantık yürütme)
|
| 45 |
+
|
| 46 |
+
### ZeroGPU Optimizasyonları
|
| 47 |
+
- `@spaces.GPU` dekoratörleri
|
| 48 |
+
- GPU memory management
|
| 49 |
+
- Efficient model loading
|
| 50 |
+
- Concurrent request handling
|
| 51 |
+
|
| 52 |
+
## 🚀 Kullanım
|
| 53 |
+
|
| 54 |
+
### Desteklenen Görevler:
|
| 55 |
+
- 💬 **Genel sohbet**: Doğal dil işleme
|
| 56 |
+
- 🔧 **Kod yazma**: Python, JavaScript, vb.
|
| 57 |
+
- 🤔 **Problem çözme**: Mantık yürütme
|
| 58 |
+
- ⚡ **Hızlı sorular**: Kısa yanıtlar
|
| 59 |
+
|
| 60 |
+
### Örnek Kullanımlar:
|
| 61 |
+
```
|
| 62 |
+
"Python'da bir hesap makinesi yaz"
|
| 63 |
+
"Fibonacci dizisi algoritması"
|
| 64 |
+
"Web development hakkında bilgi ver"
|
| 65 |
+
"Bugün nasıl bir gün?"
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
## ⚡ Performans
|
| 69 |
+
|
| 70 |
+
- **GPU**: NVIDIA A100/T4 (ZeroGPU)
|
| 71 |
+
- **Memory**: ~4GB VRAM
|
| 72 |
+
- **Response Time**: ~2-5 saniye
|
| 73 |
+
- **Concurrent Users**: 2 kullanıcı
|
| 74 |
+
|
| 75 |
+
## 🔧 Teknik Detaylar
|
| 76 |
+
|
| 77 |
+
### Model Specifications:
|
| 78 |
+
- **TinyLlama**: 1.1B parametreli chat modeli
|
| 79 |
+
- **DeepSeek-Coder**: 1.3B kod üretim modeli
|
| 80 |
+
- **Qwen2.5**: 1.5B sohbet modeli
|
| 81 |
+
- **Phi-3**: Mini reasoning modeli
|
| 82 |
+
|
| 83 |
+
### ZeroGPU Configuration:
|
| 84 |
+
- Duration: 30-60 saniye GPU slots
|
| 85 |
+
- Concurrency: 2 eşzamanlı kullanıcı
|
| 86 |
+
- Auto-shutdown: Idle durumda otomatik kapanma
|
| 87 |
+
|
| 88 |
+
## 📄 Lisans
|
| 89 |
+
|
| 90 |
+
MIT Lisansı - Açık kaynak
|
| 91 |
+
|
| 92 |
+
## 👨💻 Geliştirici
|
| 93 |
+
|
| 94 |
+
[@veteroner](https://huggingface.co/veteroner)
|
| 95 |
+
|
| 96 |
+
---
|
| 97 |
+
|
| 98 |
+
🔥 **ZeroGPU ile ücretsiz GPU gücünden yararlanın!**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.py
CHANGED
|
@@ -1,360 +1,170 @@
|
|
|
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
ZeroGPU ile hızlandırılmış
|
| 5 |
"""
|
| 6 |
|
| 7 |
import gradio as gr
|
|
|
|
| 8 |
import torch
|
| 9 |
-
import
|
| 10 |
import logging
|
|
|
|
|
|
|
| 11 |
import time
|
| 12 |
-
from typing import List, Tuple
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
try:
|
| 16 |
-
import spaces
|
| 17 |
-
HAS_SPACES = True
|
| 18 |
-
except ImportError:
|
| 19 |
-
HAS_SPACES = False
|
| 20 |
-
# Spaces decorator'ı için dummy fonksiyon
|
| 21 |
-
def spaces_gpu(func):
|
| 22 |
-
return func
|
| 23 |
-
spaces = type('spaces', (), {'GPU': spaces_gpu})()
|
| 24 |
-
|
| 25 |
-
# Logging setup
|
| 26 |
logging.basicConfig(level=logging.INFO)
|
| 27 |
logger = logging.getLogger(__name__)
|
| 28 |
|
| 29 |
-
#
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
Demo yanıtları - model yokken kullanılacak
|
| 37 |
-
"""
|
| 38 |
-
demo_responses = {
|
| 39 |
-
"merhaba": "Merhaba! Ben Nova AI, Teknova'nın özgün yapay zeka teknolojisi. Size nasıl yardımcı olabilirim?",
|
| 40 |
-
"nasılsın": "Ben Nova AI'yım ve harika hissediyorum! Sizinle sohbet etmek için buradayım. Ne konuşmak istersiniz?",
|
| 41 |
-
"nova ai nedir": "Nova AI, Teknova tarafından geliştirilen özgün bir yapay zeka modelidir. Türkçe konuşabilir ve çeşitli konularda yardımcı olabilirim.",
|
| 42 |
-
"teknova": "Teknova, Türkiye'nin öncü yapay zeka teknoloji şirketidir. Özgün AI çözümleri geliştiriyoruz.",
|
| 43 |
-
"yapay zeka": "Yapay zeka, bilgisayarların insan benzeri düşünme ve öğrenme yetenekleri göstermesidir. Ben de bir yapay zeka örneğiyim!",
|
| 44 |
-
"projeler": "Size yenilikçi proje fikirleri önerebilirim: AI chatbot, veri analizi, web uygulaması, mobil uygulama gibi...",
|
| 45 |
-
"gelecek": "Gelecekte yapay zeka, otonom araçlar, akıllı şehirler ve personalize eğitim gibi alanlarda devrim yaratacak!"
|
| 46 |
-
}
|
| 47 |
-
return demo_responses
|
| 48 |
|
| 49 |
-
|
| 50 |
-
"""
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
try:
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
except Exception as e:
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
else:
|
| 90 |
-
# Demo yanıt
|
| 91 |
-
response = generate_demo_response(message)
|
| 92 |
-
response += "\n\n💡 *Not: Bu demo modunda çalışıyor. Gerçek Nova AI modeli yüklendiğinde daha gelişmiş yanıtlar alacaksınız.*"
|
| 93 |
-
|
| 94 |
-
# Add to history
|
| 95 |
-
history.append([message, response])
|
| 96 |
-
return "", history
|
| 97 |
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
"""
|
| 101 |
-
Gerçek model ile yanıt oluştur - ZeroGPU destekli
|
| 102 |
-
"""
|
| 103 |
-
if not model or not tokenizer:
|
| 104 |
-
return generate_demo_response(message)
|
| 105 |
-
|
| 106 |
-
try:
|
| 107 |
-
inputs = tokenizer.encode(message, return_tensors="pt")
|
| 108 |
-
if device == "cuda":
|
| 109 |
-
inputs = inputs.to(device)
|
| 110 |
-
|
| 111 |
-
with torch.no_grad():
|
| 112 |
-
outputs = model.generate(
|
| 113 |
-
inputs,
|
| 114 |
-
max_length=max_length,
|
| 115 |
-
temperature=temperature,
|
| 116 |
-
do_sample=True,
|
| 117 |
-
pad_token_id=tokenizer.eos_token_id,
|
| 118 |
-
no_repeat_ngram_size=3,
|
| 119 |
-
top_p=0.9
|
| 120 |
-
)
|
| 121 |
-
|
| 122 |
-
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 123 |
-
if message in response:
|
| 124 |
-
response = response.replace(message, "").strip()
|
| 125 |
-
|
| 126 |
-
return response if response else generate_demo_response(message)
|
| 127 |
-
|
| 128 |
-
except Exception as e:
|
| 129 |
-
logger.error(f"Model generation error: {e}")
|
| 130 |
-
return generate_demo_response(message)
|
| 131 |
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
Teknova Nova AI modelini yükle - ZeroGPU destekli
|
| 136 |
-
"""
|
| 137 |
-
global model, tokenizer
|
| 138 |
-
|
| 139 |
-
try:
|
| 140 |
-
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
|
| 141 |
-
|
| 142 |
-
# Model path - Hugging Face Hub'dan yükle
|
| 143 |
-
model_path = "veteroner/NovaAI"
|
| 144 |
-
|
| 145 |
-
logger.info(f"🚀 Teknova Nova AI modeli Hub'dan yükleniyor: {model_path}")
|
| 146 |
-
|
| 147 |
-
# Tokenizer yükle
|
| 148 |
-
tokenizer = AutoTokenizer.from_pretrained(
|
| 149 |
-
model_path,
|
| 150 |
-
trust_remote_code=True,
|
| 151 |
-
use_fast=True
|
| 152 |
-
)
|
| 153 |
-
|
| 154 |
-
# Pad token ayarla
|
| 155 |
-
if tokenizer.pad_token is None:
|
| 156 |
-
tokenizer.pad_token = tokenizer.eos_token
|
| 157 |
-
|
| 158 |
-
# Model yükle - ZeroGPU optimizasyonu
|
| 159 |
-
model = AutoModelForCausalLM.from_pretrained(
|
| 160 |
-
model_path,
|
| 161 |
-
device_map="auto",
|
| 162 |
-
trust_remote_code=True,
|
| 163 |
-
torch_dtype=torch.float16,
|
| 164 |
-
low_cpu_mem_usage=True
|
| 165 |
-
)
|
| 166 |
-
|
| 167 |
-
logger.info(f"✅ Nova AI model yüklendi ({device})")
|
| 168 |
-
return f"✅ Teknova Nova AI hazır! ({device})"
|
| 169 |
-
|
| 170 |
-
except Exception as e:
|
| 171 |
-
logger.error(f"Model yükleme hatası: {e}")
|
| 172 |
-
return f"❌ Model yüklenemedi: {str(e)} - Demo modunda çalışacak"
|
| 173 |
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
"""
|
| 179 |
-
global model, tokenizer
|
| 180 |
-
|
| 181 |
-
if model is None or tokenizer is None:
|
| 182 |
-
# Demo yanıt ver
|
| 183 |
-
return generate_demo_response(message) + "\n\n💡 *Not: Demo modunda çalışıyor.*"
|
| 184 |
-
|
| 185 |
-
if not message.strip():
|
| 186 |
-
return "❓ Lütfen bir mesaj yazın."
|
| 187 |
-
|
| 188 |
try:
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
if user_msg and bot_msg:
|
| 193 |
-
conversation += f"Kullanıcı: {user_msg}\nNova AI: {bot_msg}\n"
|
| 194 |
-
|
| 195 |
-
# Yeni mesajı ekle
|
| 196 |
-
conversation += f"Kullanıcı: {message}\nNova AI:"
|
| 197 |
-
|
| 198 |
-
# Tokenize et
|
| 199 |
-
inputs = tokenizer(
|
| 200 |
-
conversation,
|
| 201 |
-
return_tensors="pt",
|
| 202 |
-
truncation=True,
|
| 203 |
-
max_length=2048,
|
| 204 |
-
padding=True
|
| 205 |
-
)
|
| 206 |
-
|
| 207 |
-
# GPU'ya taşı
|
| 208 |
-
if torch.cuda.is_available():
|
| 209 |
-
inputs = {k: v.to(model.device) for k, v in inputs.items()}
|
| 210 |
-
|
| 211 |
-
# Yanıt üret
|
| 212 |
-
with torch.no_grad():
|
| 213 |
-
outputs = model.generate(
|
| 214 |
-
**inputs,
|
| 215 |
-
max_new_tokens=256,
|
| 216 |
-
temperature=0.7,
|
| 217 |
-
top_p=0.9,
|
| 218 |
-
do_sample=True,
|
| 219 |
-
pad_token_id=tokenizer.pad_token_id,
|
| 220 |
-
eos_token_id=tokenizer.eos_token_id,
|
| 221 |
-
repetition_penalty=1.1
|
| 222 |
-
)
|
| 223 |
-
|
| 224 |
-
# Yanıtı decode et
|
| 225 |
-
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 226 |
-
|
| 227 |
-
# Sadece yeni üretilen kısmı al
|
| 228 |
-
new_response = response[len(conversation):].strip()
|
| 229 |
-
|
| 230 |
-
return new_response if new_response else "Üzgünüm, yanıt üretemedi."
|
| 231 |
-
|
| 232 |
-
except Exception as e:
|
| 233 |
-
logger.error(f"Chat hatası: {e}")
|
| 234 |
-
return f"❌ Yanıt üretirken hata: {str(e)}"
|
| 235 |
-
|
| 236 |
-
# Model yüklemeyi başlat
|
| 237 |
-
logger.info("Model yükleme başlatılıyor...")
|
| 238 |
-
load_status = load_model()
|
| 239 |
-
logger.info(f"Model durumu: {load_status}")
|
| 240 |
|
| 241 |
# Gradio arayüzü
|
| 242 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
theme=gr.themes.Soft(),
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
color: white;
|
| 255 |
-
border-radius: 15px;
|
| 256 |
-
margin-bottom: 20px;
|
| 257 |
-
}
|
| 258 |
-
"""
|
| 259 |
-
) as demo:
|
| 260 |
-
|
| 261 |
-
# Header
|
| 262 |
-
gr.HTML("""
|
| 263 |
-
<div class="header-text">
|
| 264 |
-
<h1 style="font-size: 2.5rem; margin: 0; font-weight: bold;">
|
| 265 |
-
🚀 Teknova Nova AI
|
| 266 |
-
</h1>
|
| 267 |
-
<p style="font-size: 1.2rem; margin: 10px 0; opacity: 0.9;">
|
| 268 |
-
Türkiye'nin Özgün Yapay Zeka Modeli
|
| 269 |
-
</p>
|
| 270 |
-
<div style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; display: inline-block; font-size: 0.9rem;">
|
| 271 |
-
🧠 Nova AI • 🇹�� Türkçe Optimize • ⚡ ZeroGPU Hızlı
|
| 272 |
-
</div>
|
| 273 |
-
</div>
|
| 274 |
-
""")
|
| 275 |
-
|
| 276 |
-
# Chat interface
|
| 277 |
-
chatbot = gr.Chatbot(
|
| 278 |
-
height=500,
|
| 279 |
-
show_label=False,
|
| 280 |
-
show_share_button=True,
|
| 281 |
-
show_copy_button=True,
|
| 282 |
-
avatar_images=[None, "🤖"],
|
| 283 |
-
bubble_full_width=False
|
| 284 |
-
)
|
| 285 |
-
|
| 286 |
-
with gr.Row():
|
| 287 |
-
msg = gr.Textbox(
|
| 288 |
-
placeholder="Nova AI'ya mesajınızı yazın... (Örn: Merhaba, nasılsın?)",
|
| 289 |
-
show_label=False,
|
| 290 |
-
scale=4,
|
| 291 |
-
container=False
|
| 292 |
-
)
|
| 293 |
-
submit = gr.Button("🚀 Gönder", scale=1, variant="primary")
|
| 294 |
-
|
| 295 |
-
with gr.Row():
|
| 296 |
-
clear = gr.Button("🗑️ Temizle", scale=1)
|
| 297 |
-
retry = gr.Button("🔄 Tekrar Dene", scale=1)
|
| 298 |
-
|
| 299 |
-
# Examples
|
| 300 |
-
gr.Examples(
|
| 301 |
-
examples=[
|
| 302 |
-
"Merhaba Nova AI, nasılsın?",
|
| 303 |
-
"Yapay zeka nedir?",
|
| 304 |
-
"Teknova hakkında bilgi ver",
|
| 305 |
-
"Bana bir hikaye anlat",
|
| 306 |
-
"Python programlama hakkında bilgi ver"
|
| 307 |
-
],
|
| 308 |
-
inputs=msg,
|
| 309 |
-
label="💡 Örnek Sorular"
|
| 310 |
-
)
|
| 311 |
-
|
| 312 |
-
# Footer
|
| 313 |
-
gr.HTML("""
|
| 314 |
-
<div style="text-align: center; padding: 15px; color: #666; font-size: 0.9rem;">
|
| 315 |
-
<p>🌟 <strong>Teknova Nova AI</strong> - Tamamen özgün Türkçe dil modeli</p>
|
| 316 |
-
<p>🚀 ZeroGPU teknolojisi ile hızlandırılmış</p>
|
| 317 |
-
<p style="color: #999;">⚡ Teknova Innovation ile güçlendirilmiştir</p>
|
| 318 |
-
</div>
|
| 319 |
-
""")
|
| 320 |
-
|
| 321 |
-
# Event handlers
|
| 322 |
-
def user_message(message, history):
|
| 323 |
-
return "", history + [[message, None]]
|
| 324 |
-
|
| 325 |
-
@spaces.GPU
|
| 326 |
-
def bot_message(history):
|
| 327 |
-
"""Bot yanıtı oluştur - ZeroGPU destekli"""
|
| 328 |
-
if history and history[-1][1] is None:
|
| 329 |
-
user_msg = history[-1][0]
|
| 330 |
-
bot_response = chat_with_nova(user_msg, history[:-1])
|
| 331 |
-
history[-1][1] = bot_response
|
| 332 |
-
return history
|
| 333 |
-
|
| 334 |
-
@spaces.GPU
|
| 335 |
-
def retry_last(history):
|
| 336 |
-
"""Son mesajı yeniden dene - ZeroGPU destekli"""
|
| 337 |
-
if history and history[-1][1] is not None:
|
| 338 |
-
user_msg = history[-1][0]
|
| 339 |
-
bot_response = chat_with_nova(user_msg, history[:-1])
|
| 340 |
-
history[-1][1] = bot_response
|
| 341 |
-
return history
|
| 342 |
-
|
| 343 |
-
# Event bindings
|
| 344 |
-
msg.submit(user_message, [msg, chatbot], [msg, chatbot], queue=False).then(
|
| 345 |
-
bot_message, chatbot, chatbot
|
| 346 |
-
)
|
| 347 |
-
submit.click(user_message, [msg, chatbot], [msg, chatbot], queue=False).then(
|
| 348 |
-
bot_message, chatbot, chatbot
|
| 349 |
-
)
|
| 350 |
-
clear.click(lambda: None, None, chatbot, queue=False)
|
| 351 |
-
retry.click(retry_last, chatbot, chatbot)
|
| 352 |
|
| 353 |
-
# Launch
|
| 354 |
if __name__ == "__main__":
|
| 355 |
demo.launch(
|
|
|
|
| 356 |
server_name="0.0.0.0",
|
| 357 |
server_port=7860,
|
| 358 |
-
share=False,
|
| 359 |
show_error=True
|
| 360 |
-
)
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
CRANE AI - ZeroGPU Space Demo
|
| 4 |
+
HuggingFace ZeroGPU ile çalışır
|
|
|
|
| 5 |
"""
|
| 6 |
|
| 7 |
import gradio as gr
|
| 8 |
+
import spaces
|
| 9 |
import torch
|
| 10 |
+
import asyncio
|
| 11 |
import logging
|
| 12 |
+
import os
|
| 13 |
+
from typing import Dict, Any
|
| 14 |
import time
|
|
|
|
| 15 |
|
| 16 |
+
# Logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
logging.basicConfig(level=logging.INFO)
|
| 18 |
logger = logging.getLogger(__name__)
|
| 19 |
|
| 20 |
+
# ZeroGPU için import'lar
|
| 21 |
+
from config.settings import MODELS, HF_TOKEN
|
| 22 |
+
from modules.code_module import CodeModule
|
| 23 |
+
from modules.chat_module import ChatModule
|
| 24 |
+
from modules.reason_module import ReasonModule
|
| 25 |
+
from modules.fast_module import FastModule
|
| 26 |
+
from router.intelligent_router import IntelligentRouter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
class CRANEZeroGPU:
|
| 29 |
+
"""CRANE AI ZeroGPU Wrapper"""
|
| 30 |
+
|
| 31 |
+
def __init__(self):
|
| 32 |
+
self.modules = {}
|
| 33 |
+
self.router = None
|
| 34 |
+
self.is_initialized = False
|
| 35 |
+
|
| 36 |
+
@spaces.GPU(duration=60) # 60 saniye GPU
|
| 37 |
+
async def initialize_models(self):
|
| 38 |
+
"""Modelleri GPU'da başlatır"""
|
| 39 |
+
if self.is_initialized:
|
| 40 |
+
return
|
| 41 |
+
|
| 42 |
+
logger.info("🔥 ZeroGPU'da modeller yükleniyor...")
|
| 43 |
+
|
| 44 |
+
# GPU cihazını ayarla
|
| 45 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 46 |
+
logger.info(f"🖥️ Cihaz: {device}")
|
| 47 |
+
|
| 48 |
+
# Modelleri yükle
|
| 49 |
+
for name, cfg in MODELS.items():
|
| 50 |
+
try:
|
| 51 |
+
config = {**cfg, "device": device, "hf_token": os.getenv("HF_TOKEN", "")}
|
| 52 |
+
|
| 53 |
+
if name == "fast_module": # Sadece hızlı modeli yükle (GPU sınırlaması için)
|
| 54 |
+
module = FastModule(config)
|
| 55 |
+
await module.load_model()
|
| 56 |
+
self.modules[name] = module
|
| 57 |
+
logger.info(f" ✅ {name} GPU'da yüklendi")
|
| 58 |
+
break # Sadece bir model yükle
|
| 59 |
+
|
| 60 |
+
except Exception as e:
|
| 61 |
+
logger.error(f" ❌ {name} yükleme hatası: {e}")
|
| 62 |
+
|
| 63 |
+
# Router'ı başlat
|
| 64 |
+
if self.modules:
|
| 65 |
+
self.router = IntelligentRouter(self.modules, {
|
| 66 |
+
"confidence_threshold": 0.6,
|
| 67 |
+
"max_concurrent_requests": 1,
|
| 68 |
+
"timeout": 30,
|
| 69 |
+
"fallback_model": "fast_module"
|
| 70 |
+
})
|
| 71 |
+
|
| 72 |
+
self.is_initialized = True
|
| 73 |
+
logger.info("🔥 ZeroGPU başlatma tamamlandı")
|
| 74 |
+
|
| 75 |
+
@spaces.GPU(duration=30)
|
| 76 |
+
async def process_query(self, message: str, history: list) -> str:
|
| 77 |
+
"""Mesajı ZeroGPU'da işler"""
|
| 78 |
try:
|
| 79 |
+
# Modelleri başlat
|
| 80 |
+
await self.initialize_models()
|
| 81 |
+
|
| 82 |
+
if not self.router or not self.modules:
|
| 83 |
+
return "⚠️ Sistem başlatılamadı. Lütfen tekrar deneyin."
|
| 84 |
+
|
| 85 |
+
# Hızlı yanıt için basit kontrol
|
| 86 |
+
message_lower = message.lower()
|
| 87 |
+
|
| 88 |
+
# Basit selamlaşma
|
| 89 |
+
greetings = ["merhaba", "selam", "hi", "hello", "hey"]
|
| 90 |
+
if any(greeting in message_lower for greeting in greetings):
|
| 91 |
+
return "🏗️ Merhaba! Ben CRANE AI. Size nasıl yardımcı olabilirim?"
|
| 92 |
+
|
| 93 |
+
# Kod talebi kontrolü
|
| 94 |
+
code_keywords = ["kod", "code", "python", "javascript", "function", "def"]
|
| 95 |
+
if any(keyword in message_lower for keyword in code_keywords):
|
| 96 |
+
response = "🔧 Kod yazma modülü aktif... "
|
| 97 |
+
else:
|
| 98 |
+
response = "💬 "
|
| 99 |
+
|
| 100 |
+
# Modeli çalıştır
|
| 101 |
+
start_time = time.time()
|
| 102 |
+
result = await self.router.route_query(message, {"history": history})
|
| 103 |
+
duration = time.time() - start_time
|
| 104 |
+
|
| 105 |
+
if result and "response" in result:
|
| 106 |
+
response += result["response"]
|
| 107 |
+
response += f"\n\n⚡ İşlem süresi: {duration:.2f}s"
|
| 108 |
+
else:
|
| 109 |
+
response += "Üzgünüm, şu anda yanıt veremiyorum. Lütfen tekrar deneyin."
|
| 110 |
+
|
| 111 |
+
return response
|
| 112 |
+
|
| 113 |
except Exception as e:
|
| 114 |
+
logger.error(f"ZeroGPU işlem hatası: {e}")
|
| 115 |
+
return f"❌ Hata oluştu: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
+
# Global instance
|
| 118 |
+
crane_gpu = CRANEZeroGPU()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
|
| 120 |
+
async def chat_interface(message, history):
|
| 121 |
+
"""Gradio chat interface"""
|
| 122 |
+
return await crane_gpu.process_query(message, history)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
+
def sync_chat_interface(message, history):
|
| 125 |
+
"""Senkron wrapper"""
|
| 126 |
+
loop = asyncio.new_event_loop()
|
| 127 |
+
asyncio.set_event_loop(loop)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
try:
|
| 129 |
+
return loop.run_until_complete(chat_interface(message, history))
|
| 130 |
+
finally:
|
| 131 |
+
loop.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
# Gradio arayüzü
|
| 134 |
+
demo = gr.ChatInterface(
|
| 135 |
+
fn=sync_chat_interface,
|
| 136 |
+
type="messages",
|
| 137 |
+
title="🏗️ CRANE AI - ZeroGPU Powered",
|
| 138 |
+
description="""
|
| 139 |
+
**CRANE AI Hibrit Yapay Zeka Sistemi** - HuggingFace ZeroGPU ile güçlendirilmiş
|
| 140 |
+
|
| 141 |
+
🔥 **ZeroGPU Features:**
|
| 142 |
+
- Ücretsiz GPU erişimi
|
| 143 |
+
- Hızlı model yükleme
|
| 144 |
+
- Optimize edilmiş performans
|
| 145 |
+
|
| 146 |
+
🧠 **Desteklenen Görevler:**
|
| 147 |
+
- 💬 Genel sohbet
|
| 148 |
+
- 🔧 Kod yazma
|
| 149 |
+
- 🤔 Problem çözme
|
| 150 |
+
- ⚡ Hızlı sorular
|
| 151 |
+
""",
|
| 152 |
theme=gr.themes.Soft(),
|
| 153 |
+
examples=[
|
| 154 |
+
"Merhaba! CRANE AI nasıl çalışır?",
|
| 155 |
+
"Python'da bir hesap makinesi yaz",
|
| 156 |
+
"Fibonacci dizisi algoritması",
|
| 157 |
+
"Web development hakkında bilgi ver",
|
| 158 |
+
"Bugün nasıl bir gün?",
|
| 159 |
+
],
|
| 160 |
+
cache_examples=False, # ZeroGPU için
|
| 161 |
+
concurrency_limit=2, # Eşzamanlı kullanıcı sınırı
|
| 162 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
|
|
|
|
| 164 |
if __name__ == "__main__":
|
| 165 |
demo.launch(
|
| 166 |
+
share=False,
|
| 167 |
server_name="0.0.0.0",
|
| 168 |
server_port=7860,
|
|
|
|
| 169 |
show_error=True
|
| 170 |
+
)
|
config/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Configuration Package
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .settings import *
|
| 6 |
+
|
| 7 |
+
__all__ = [
|
| 8 |
+
'MODELS',
|
| 9 |
+
'ROUTER_CONFIG',
|
| 10 |
+
'MEMORY_CONFIG',
|
| 11 |
+
'API_CONFIG',
|
| 12 |
+
'SYSTEM_LIMITS',
|
| 13 |
+
'LOGGING_CONFIG',
|
| 14 |
+
'HF_TOKEN',
|
| 15 |
+
'DEVICE'
|
| 16 |
+
]
|
config/settings.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI Sistem Yapılandırması
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
from typing import Dict, Any
|
| 7 |
+
|
| 8 |
+
# Hugging Face Token güvenlik için ortam değişkeninden okunur
|
| 9 |
+
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
| 10 |
+
|
| 11 |
+
# Model Yapılandırması
|
| 12 |
+
MODELS = {
|
| 13 |
+
"code_module": {
|
| 14 |
+
"model_id": "deepseek-ai/deepseek-coder-1.3b-instruct",
|
| 15 |
+
"task": "code_generation",
|
| 16 |
+
"max_tokens": 2048,
|
| 17 |
+
"temperature": 0.1,
|
| 18 |
+
"priority": 1
|
| 19 |
+
},
|
| 20 |
+
"chat_module": {
|
| 21 |
+
"model_id": "Qwen/Qwen2.5-1.5B-Instruct",
|
| 22 |
+
"task": "chat",
|
| 23 |
+
"max_tokens": 1024,
|
| 24 |
+
"temperature": 0.7,
|
| 25 |
+
"priority": 2
|
| 26 |
+
},
|
| 27 |
+
"reason_module": {
|
| 28 |
+
"model_id": "microsoft/Phi-3-mini-4k-instruct",
|
| 29 |
+
"task": "reasoning",
|
| 30 |
+
"max_tokens": 1024,
|
| 31 |
+
"temperature": 0.3,
|
| 32 |
+
"priority": 3
|
| 33 |
+
},
|
| 34 |
+
"fast_module": {
|
| 35 |
+
"model_id": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
|
| 36 |
+
"task": "quick_response",
|
| 37 |
+
"max_tokens": 512,
|
| 38 |
+
"temperature": 0.8,
|
| 39 |
+
"priority": 4
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
# Router Yapılandırması
|
| 44 |
+
ROUTER_CONFIG = {
|
| 45 |
+
"confidence_threshold": 0.6,
|
| 46 |
+
"max_concurrent_requests": 4,
|
| 47 |
+
"timeout": 30,
|
| 48 |
+
"fallback_model": "fast_module"
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
# Memory Yapılandırması
|
| 52 |
+
MEMORY_CONFIG = {
|
| 53 |
+
"max_slots": 10,
|
| 54 |
+
"slot_size": 1024,
|
| 55 |
+
"cleanup_interval": 300 # 5 dakika
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
# API Yapılandırması
|
| 59 |
+
API_CONFIG = {
|
| 60 |
+
"host": "0.0.0.0",
|
| 61 |
+
"port": 8000,
|
| 62 |
+
"workers": 1
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
# Sistem Limitleri
|
| 66 |
+
SYSTEM_LIMITS = {
|
| 67 |
+
"max_input_length": 4096,
|
| 68 |
+
"max_output_length": 2048,
|
| 69 |
+
"max_concurrent_users": 10
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
# Logging
|
| 73 |
+
LOGGING_CONFIG = {
|
| 74 |
+
"level": "INFO",
|
| 75 |
+
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
| 76 |
+
"file": "logs/crane_ai.log"
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
def get_model_config(model_name: str) -> Dict[str, Any]:
|
| 80 |
+
"""Belirli bir model için yapılandırma döndürür"""
|
| 81 |
+
return MODELS.get(model_name, MODELS["fast_module"])
|
| 82 |
+
|
| 83 |
+
def get_device():
|
| 84 |
+
"""Kullanılacak cihazı belirler"""
|
| 85 |
+
try:
|
| 86 |
+
import torch
|
| 87 |
+
if torch.cuda.is_available():
|
| 88 |
+
return "cuda"
|
| 89 |
+
elif torch.backends.mps.is_available():
|
| 90 |
+
return "mps"
|
| 91 |
+
else:
|
| 92 |
+
return "cpu"
|
| 93 |
+
except ImportError:
|
| 94 |
+
return "cpu"
|
| 95 |
+
|
| 96 |
+
# Cihaz yapılandırması
|
| 97 |
+
DEVICE = get_device()
|
core/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Core Modülleri
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .base_module import BaseMicroModule
|
| 6 |
+
from .token_capsule import TokenCapsuleLayer, TokenCapsule
|
| 7 |
+
|
| 8 |
+
__all__ = [
|
| 9 |
+
'BaseMicroModule',
|
| 10 |
+
'TokenCapsuleLayer',
|
| 11 |
+
'TokenCapsule'
|
| 12 |
+
]
|
core/base_module.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Temel MicroModule Sınıfı
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from abc import ABC, abstractmethod
|
| 6 |
+
from typing import Any, Dict, List, Optional
|
| 7 |
+
import torch
|
| 8 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 9 |
+
from peft import PeftModel, PeftConfig
|
| 10 |
+
import os
|
| 11 |
+
import logging
|
| 12 |
+
import asyncio
|
| 13 |
+
from threading import Lock
|
| 14 |
+
|
| 15 |
+
logger = logging.getLogger(__name__)
|
| 16 |
+
|
| 17 |
+
class BaseMicroModule(ABC):
|
| 18 |
+
"""Tüm MicroModule'lar için temel sınıf"""
|
| 19 |
+
|
| 20 |
+
def __init__(self, model_id: str, config: Dict[str, Any]):
|
| 21 |
+
self.model_id = model_id
|
| 22 |
+
self.config = config
|
| 23 |
+
self.device = config.get("device", "cpu")
|
| 24 |
+
self.max_tokens = config.get("max_tokens", 1024)
|
| 25 |
+
self.temperature = config.get("temperature", 0.7)
|
| 26 |
+
self.priority = config.get("priority", 1)
|
| 27 |
+
|
| 28 |
+
# Model ve tokenizer
|
| 29 |
+
self.model = None
|
| 30 |
+
self.tokenizer = None
|
| 31 |
+
self.is_loaded = False
|
| 32 |
+
self.load_lock = Lock()
|
| 33 |
+
|
| 34 |
+
# İstatistikler
|
| 35 |
+
self.request_count = 0
|
| 36 |
+
self.total_tokens = 0
|
| 37 |
+
self.avg_response_time = 0
|
| 38 |
+
|
| 39 |
+
async def load_model(self):
|
| 40 |
+
"""Modeli yükler"""
|
| 41 |
+
if self.is_loaded:
|
| 42 |
+
return
|
| 43 |
+
|
| 44 |
+
with self.load_lock:
|
| 45 |
+
if self.is_loaded:
|
| 46 |
+
return
|
| 47 |
+
|
| 48 |
+
try:
|
| 49 |
+
logger.info(f"Loading model: {self.model_id}")
|
| 50 |
+
|
| 51 |
+
# Tokenizer yükleme
|
| 52 |
+
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 53 |
+
self.model_id,
|
| 54 |
+
trust_remote_code=True,
|
| 55 |
+
token=self.config.get("hf_token")
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# Model yükleme
|
| 59 |
+
self.model = AutoModelForCausalLM.from_pretrained(
|
| 60 |
+
self.model_id,
|
| 61 |
+
trust_remote_code=True,
|
| 62 |
+
torch_dtype=torch.float16 if self.device != "cpu" else torch.float32,
|
| 63 |
+
device_map="auto" if self.device != "cpu" else None,
|
| 64 |
+
token=self.config.get("hf_token")
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
# LoRA adaptörü kontrolü
|
| 68 |
+
adapter_dir = os.path.join("model_cache", self.model_id.replace("/", "_"), "adapter")
|
| 69 |
+
if os.path.isdir(adapter_dir):
|
| 70 |
+
try:
|
| 71 |
+
self.model = PeftModel.from_pretrained(self.model, adapter_dir, is_trainable=False)
|
| 72 |
+
self.model = self.model.merge_and_unload()
|
| 73 |
+
logger.info(f"LoRA adaptörü yüklendi: {adapter_dir}")
|
| 74 |
+
except Exception as adp_err:
|
| 75 |
+
logger.warning(f"Adaptör yüklenemedi ({adapter_dir}): {adp_err}")
|
| 76 |
+
|
| 77 |
+
# Pad token ayarı
|
| 78 |
+
if self.tokenizer.pad_token is None:
|
| 79 |
+
self.tokenizer.pad_token = self.tokenizer.eos_token
|
| 80 |
+
|
| 81 |
+
self.is_loaded = True
|
| 82 |
+
logger.info(f"Model loaded successfully: {self.model_id}")
|
| 83 |
+
|
| 84 |
+
except Exception as e:
|
| 85 |
+
logger.error(f"Error loading model {self.model_id}: {str(e)}")
|
| 86 |
+
raise
|
| 87 |
+
|
| 88 |
+
@abstractmethod
|
| 89 |
+
def can_handle(self, query: str, context: Dict[str, Any]) -> float:
|
| 90 |
+
"""Bu modülün sorguyu ne kadar iyi işleyebileceğini belirler (0-1)"""
|
| 91 |
+
pass
|
| 92 |
+
|
| 93 |
+
@abstractmethod
|
| 94 |
+
async def process(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 95 |
+
"""Ana işleme fonksiyonu"""
|
| 96 |
+
pass
|
| 97 |
+
|
| 98 |
+
async def generate_response(self, prompt: str, **kwargs) -> str:
|
| 99 |
+
"""Metin üretimi"""
|
| 100 |
+
if not self.is_loaded:
|
| 101 |
+
await self.load_model()
|
| 102 |
+
|
| 103 |
+
try:
|
| 104 |
+
# Tokenlara çevir
|
| 105 |
+
inputs = self.tokenizer(
|
| 106 |
+
prompt,
|
| 107 |
+
return_tensors="pt",
|
| 108 |
+
max_length=self.max_tokens,
|
| 109 |
+
truncation=True,
|
| 110 |
+
padding=True
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
# Tenzile cihaz aktarımı
|
| 114 |
+
if self.device != "cpu":
|
| 115 |
+
inputs = {k: v.to(self.device) for k, v in inputs.items()}
|
| 116 |
+
|
| 117 |
+
# Üretim parametreleri
|
| 118 |
+
generation_config = {
|
| 119 |
+
"max_new_tokens": kwargs.get("max_tokens", self.max_tokens),
|
| 120 |
+
"temperature": kwargs.get("temperature", self.temperature),
|
| 121 |
+
"do_sample": True,
|
| 122 |
+
"top_p": 0.9,
|
| 123 |
+
"top_k": 50,
|
| 124 |
+
"pad_token_id": self.tokenizer.pad_token_id,
|
| 125 |
+
"eos_token_id": self.tokenizer.eos_token_id,
|
| 126 |
+
"no_repeat_ngram_size": 3
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
# Üretim
|
| 130 |
+
with torch.no_grad():
|
| 131 |
+
outputs = self.model.generate(
|
| 132 |
+
**inputs,
|
| 133 |
+
**generation_config
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
# Metne çevir
|
| 137 |
+
response = self.tokenizer.decode(
|
| 138 |
+
outputs[0][inputs["input_ids"].shape[1]:],
|
| 139 |
+
skip_special_tokens=True
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
# İstatistikleri güncelle
|
| 143 |
+
self.request_count += 1
|
| 144 |
+
self.total_tokens += len(outputs[0])
|
| 145 |
+
|
| 146 |
+
return response.strip()
|
| 147 |
+
|
| 148 |
+
except Exception as e:
|
| 149 |
+
logger.error(f"Generation error in {self.model_id}: {str(e)}")
|
| 150 |
+
raise
|
| 151 |
+
|
| 152 |
+
def get_stats(self) -> Dict[str, Any]:
|
| 153 |
+
"""Modül istatistiklerini döndürür"""
|
| 154 |
+
return {
|
| 155 |
+
"model_id": self.model_id,
|
| 156 |
+
"is_loaded": self.is_loaded,
|
| 157 |
+
"request_count": self.request_count,
|
| 158 |
+
"total_tokens": self.total_tokens,
|
| 159 |
+
"avg_response_time": self.avg_response_time,
|
| 160 |
+
"priority": self.priority
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
def unload_model(self):
|
| 164 |
+
"""Modeli bellekten kaldırır"""
|
| 165 |
+
if self.model:
|
| 166 |
+
del self.model
|
| 167 |
+
self.model = None
|
| 168 |
+
if self.tokenizer:
|
| 169 |
+
del self.tokenizer
|
| 170 |
+
self.tokenizer = None
|
| 171 |
+
self.is_loaded = False
|
| 172 |
+
|
| 173 |
+
# GPU belleğini temizle
|
| 174 |
+
if torch.cuda.is_available():
|
| 175 |
+
torch.cuda.empty_cache()
|
| 176 |
+
|
| 177 |
+
logger.info(f"Model unloaded: {self.model_id}")
|
core/token_capsule.py
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Token Capsule Layer
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any, List, Optional, Tuple
|
| 6 |
+
import torch
|
| 7 |
+
import numpy as np
|
| 8 |
+
from transformers import AutoTokenizer
|
| 9 |
+
import logging
|
| 10 |
+
from dataclasses import dataclass
|
| 11 |
+
import asyncio
|
| 12 |
+
|
| 13 |
+
logger = logging.getLogger(__name__)
|
| 14 |
+
|
| 15 |
+
@dataclass
|
| 16 |
+
class TokenCapsule:
|
| 17 |
+
"""Token kapsülü veri yapısı"""
|
| 18 |
+
tokens: List[int]
|
| 19 |
+
attention_mask: List[int]
|
| 20 |
+
token_type_ids: List[int]
|
| 21 |
+
embeddings: Optional[torch.Tensor] = None
|
| 22 |
+
metadata: Dict[str, Any] = None
|
| 23 |
+
|
| 24 |
+
class TokenCapsuleLayer:
|
| 25 |
+
"""Token işleme ve optimizasyon katmanı"""
|
| 26 |
+
|
| 27 |
+
def __init__(self, config: Dict[str, Any]):
|
| 28 |
+
self.config = config
|
| 29 |
+
self.max_length = config.get("max_length", 2048)
|
| 30 |
+
self.device = config.get("device", "cpu")
|
| 31 |
+
|
| 32 |
+
# Token cache
|
| 33 |
+
self.token_cache = {}
|
| 34 |
+
self.cache_size = config.get("cache_size", 1000)
|
| 35 |
+
|
| 36 |
+
# Token istatistikleri
|
| 37 |
+
self.token_stats = {
|
| 38 |
+
"total_processed": 0,
|
| 39 |
+
"cache_hits": 0,
|
| 40 |
+
"cache_misses": 0,
|
| 41 |
+
"avg_token_length": 0
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
# Tokenizer havuzu
|
| 45 |
+
self.tokenizer_pool = {}
|
| 46 |
+
|
| 47 |
+
async def process_input(self, text: str, model_id: str, context: Dict[str, Any] = None) -> TokenCapsule:
|
| 48 |
+
"""Giriş metnini token kapsülüne çevirir"""
|
| 49 |
+
try:
|
| 50 |
+
# Cache kontrolü
|
| 51 |
+
cache_key = f"{model_id}:{hash(text)}"
|
| 52 |
+
if cache_key in self.token_cache:
|
| 53 |
+
self.token_stats["cache_hits"] += 1
|
| 54 |
+
return self.token_cache[cache_key]
|
| 55 |
+
|
| 56 |
+
# Tokenizer al
|
| 57 |
+
tokenizer = await self._get_tokenizer(model_id)
|
| 58 |
+
|
| 59 |
+
# Tokenize et
|
| 60 |
+
encoding = tokenizer(
|
| 61 |
+
text,
|
| 62 |
+
max_length=self.max_length,
|
| 63 |
+
padding=True,
|
| 64 |
+
truncation=True,
|
| 65 |
+
return_tensors="pt"
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
# Token kapsülü oluştur
|
| 69 |
+
capsule = TokenCapsule(
|
| 70 |
+
tokens=encoding["input_ids"].squeeze().tolist(),
|
| 71 |
+
attention_mask=encoding["attention_mask"].squeeze().tolist(),
|
| 72 |
+
token_type_ids=encoding.get("token_type_ids", []).squeeze().tolist() if encoding.get("token_type_ids") is not None else [],
|
| 73 |
+
metadata={
|
| 74 |
+
"model_id": model_id,
|
| 75 |
+
"original_text": text[:100], # İlk 100 karakter
|
| 76 |
+
"token_count": len(encoding["input_ids"].squeeze()),
|
| 77 |
+
"context": context
|
| 78 |
+
}
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
# Cache'e ekle
|
| 82 |
+
self._add_to_cache(cache_key, capsule)
|
| 83 |
+
|
| 84 |
+
# İstatistikleri güncelle
|
| 85 |
+
self.token_stats["total_processed"] += 1
|
| 86 |
+
self.token_stats["cache_misses"] += 1
|
| 87 |
+
self._update_avg_length(len(capsule.tokens))
|
| 88 |
+
|
| 89 |
+
return capsule
|
| 90 |
+
|
| 91 |
+
except Exception as e:
|
| 92 |
+
logger.error(f"Token processing error: {str(e)}")
|
| 93 |
+
raise
|
| 94 |
+
|
| 95 |
+
async def optimize_tokens(self, capsule: TokenCapsule, optimization_type: str = "standard") -> TokenCapsule:
|
| 96 |
+
"""Token optimizasyonu yapar"""
|
| 97 |
+
try:
|
| 98 |
+
if optimization_type == "compress":
|
| 99 |
+
return await self._compress_tokens(capsule)
|
| 100 |
+
elif optimization_type == "expand":
|
| 101 |
+
return await self._expand_tokens(capsule)
|
| 102 |
+
elif optimization_type == "filter":
|
| 103 |
+
return await self._filter_tokens(capsule)
|
| 104 |
+
else:
|
| 105 |
+
return capsule
|
| 106 |
+
|
| 107 |
+
except Exception as e:
|
| 108 |
+
logger.error(f"Token optimization error: {str(e)}")
|
| 109 |
+
return capsule
|
| 110 |
+
|
| 111 |
+
async def merge_capsules(self, capsules: List[TokenCapsule], strategy: str = "concat") -> TokenCapsule:
|
| 112 |
+
"""Birden fazla kapsülü birleştirir"""
|
| 113 |
+
try:
|
| 114 |
+
if strategy == "concat":
|
| 115 |
+
return await self._concat_capsules(capsules)
|
| 116 |
+
elif strategy == "interleave":
|
| 117 |
+
return await self._interleave_capsules(capsules)
|
| 118 |
+
elif strategy == "priority":
|
| 119 |
+
return await self._priority_merge_capsules(capsules)
|
| 120 |
+
else:
|
| 121 |
+
return capsules[0] if capsules else None
|
| 122 |
+
|
| 123 |
+
except Exception as e:
|
| 124 |
+
logger.error(f"Capsule merging error: {str(e)}")
|
| 125 |
+
return capsules[0] if capsules else None
|
| 126 |
+
|
| 127 |
+
async def extract_embeddings(self, capsule: TokenCapsule, model: Any) -> TokenCapsule:
|
| 128 |
+
"""Token embedding'lerini çıkarır"""
|
| 129 |
+
try:
|
| 130 |
+
if capsule.embeddings is not None:
|
| 131 |
+
return capsule
|
| 132 |
+
|
| 133 |
+
# Model'den embedding'leri al
|
| 134 |
+
input_ids = torch.tensor([capsule.tokens]).to(self.device)
|
| 135 |
+
attention_mask = torch.tensor([capsule.attention_mask]).to(self.device)
|
| 136 |
+
|
| 137 |
+
with torch.no_grad():
|
| 138 |
+
outputs = model(
|
| 139 |
+
input_ids=input_ids,
|
| 140 |
+
attention_mask=attention_mask,
|
| 141 |
+
output_hidden_states=True
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
# Son katman hidden state'ini al
|
| 145 |
+
embeddings = outputs.hidden_states[-1]
|
| 146 |
+
capsule.embeddings = embeddings.squeeze()
|
| 147 |
+
|
| 148 |
+
return capsule
|
| 149 |
+
|
| 150 |
+
except Exception as e:
|
| 151 |
+
logger.error(f"Embedding extraction error: {str(e)}")
|
| 152 |
+
return capsule
|
| 153 |
+
|
| 154 |
+
async def _get_tokenizer(self, model_id: str) -> AutoTokenizer:
|
| 155 |
+
"""Model için tokenizer alır"""
|
| 156 |
+
if model_id not in self.tokenizer_pool:
|
| 157 |
+
try:
|
| 158 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 159 |
+
model_id,
|
| 160 |
+
trust_remote_code=True,
|
| 161 |
+
token=self.config.get("hf_token")
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
# Pad token ayarı
|
| 165 |
+
if tokenizer.pad_token is None:
|
| 166 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 167 |
+
|
| 168 |
+
self.tokenizer_pool[model_id] = tokenizer
|
| 169 |
+
|
| 170 |
+
except Exception as e:
|
| 171 |
+
logger.error(f"Tokenizer loading error for {model_id}: {str(e)}")
|
| 172 |
+
raise
|
| 173 |
+
|
| 174 |
+
return self.tokenizer_pool[model_id]
|
| 175 |
+
|
| 176 |
+
async def _compress_tokens(self, capsule: TokenCapsule) -> TokenCapsule:
|
| 177 |
+
"""Token sıkıştırma"""
|
| 178 |
+
# Önemli token'ları tespit et ve gereksizleri çıkar
|
| 179 |
+
important_tokens = []
|
| 180 |
+
attention_mask = []
|
| 181 |
+
|
| 182 |
+
for i, token in enumerate(capsule.tokens):
|
| 183 |
+
# Özel tokenları koru
|
| 184 |
+
if token in [0, 1, 2, 3]: # [PAD], [UNK], [CLS], [SEP]
|
| 185 |
+
important_tokens.append(token)
|
| 186 |
+
attention_mask.append(capsule.attention_mask[i])
|
| 187 |
+
# Çok tekrarlanan tokenları atla
|
| 188 |
+
elif token not in important_tokens[-5:]: # Son 5 token içinde yoksa
|
| 189 |
+
important_tokens.append(token)
|
| 190 |
+
attention_mask.append(capsule.attention_mask[i])
|
| 191 |
+
|
| 192 |
+
compressed_capsule = TokenCapsule(
|
| 193 |
+
tokens=important_tokens,
|
| 194 |
+
attention_mask=attention_mask,
|
| 195 |
+
token_type_ids=capsule.token_type_ids[:len(important_tokens)],
|
| 196 |
+
embeddings=capsule.embeddings,
|
| 197 |
+
metadata={**capsule.metadata, "compressed": True}
|
| 198 |
+
)
|
| 199 |
+
|
| 200 |
+
return compressed_capsule
|
| 201 |
+
|
| 202 |
+
async def _expand_tokens(self, capsule: TokenCapsule) -> TokenCapsule:
|
| 203 |
+
"""Token genişletme"""
|
| 204 |
+
# Context token'ları ekle
|
| 205 |
+
expanded_tokens = [1] + capsule.tokens + [2] # [CLS] + tokens + [SEP]
|
| 206 |
+
expanded_attention = [1] + capsule.attention_mask + [1]
|
| 207 |
+
|
| 208 |
+
expanded_capsule = TokenCapsule(
|
| 209 |
+
tokens=expanded_tokens,
|
| 210 |
+
attention_mask=expanded_attention,
|
| 211 |
+
token_type_ids=capsule.token_type_ids,
|
| 212 |
+
embeddings=capsule.embeddings,
|
| 213 |
+
metadata={**capsule.metadata, "expanded": True}
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
return expanded_capsule
|
| 217 |
+
|
| 218 |
+
async def _filter_tokens(self, capsule: TokenCapsule) -> TokenCapsule:
|
| 219 |
+
"""Token filtreleme"""
|
| 220 |
+
# Gereksiz token'ları filtrele
|
| 221 |
+
filtered_tokens = []
|
| 222 |
+
filtered_attention = []
|
| 223 |
+
|
| 224 |
+
for i, token in enumerate(capsule.tokens):
|
| 225 |
+
# Padding token'ları atla
|
| 226 |
+
if token != 0:
|
| 227 |
+
filtered_tokens.append(token)
|
| 228 |
+
filtered_attention.append(capsule.attention_mask[i])
|
| 229 |
+
|
| 230 |
+
filtered_capsule = TokenCapsule(
|
| 231 |
+
tokens=filtered_tokens,
|
| 232 |
+
attention_mask=filtered_attention,
|
| 233 |
+
token_type_ids=capsule.token_type_ids[:len(filtered_tokens)],
|
| 234 |
+
embeddings=capsule.embeddings,
|
| 235 |
+
metadata={**capsule.metadata, "filtered": True}
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
return filtered_capsule
|
| 239 |
+
|
| 240 |
+
async def _concat_capsules(self, capsules: List[TokenCapsule]) -> TokenCapsule:
|
| 241 |
+
"""Kapsülleri ardışık olarak birleştirir"""
|
| 242 |
+
if not capsules:
|
| 243 |
+
return None
|
| 244 |
+
|
| 245 |
+
merged_tokens = []
|
| 246 |
+
merged_attention = []
|
| 247 |
+
merged_metadata = {"merged": True, "source_count": len(capsules)}
|
| 248 |
+
|
| 249 |
+
for capsule in capsules:
|
| 250 |
+
merged_tokens.extend(capsule.tokens)
|
| 251 |
+
merged_attention.extend(capsule.attention_mask)
|
| 252 |
+
|
| 253 |
+
# Metadata birleştir
|
| 254 |
+
if capsule.metadata:
|
| 255 |
+
for key, value in capsule.metadata.items():
|
| 256 |
+
if key not in merged_metadata:
|
| 257 |
+
merged_metadata[key] = []
|
| 258 |
+
merged_metadata[key].append(value)
|
| 259 |
+
|
| 260 |
+
# Maksimum uzunluk kontrolü
|
| 261 |
+
if len(merged_tokens) > self.max_length:
|
| 262 |
+
merged_tokens = merged_tokens[:self.max_length]
|
| 263 |
+
merged_attention = merged_attention[:self.max_length]
|
| 264 |
+
|
| 265 |
+
return TokenCapsule(
|
| 266 |
+
tokens=merged_tokens,
|
| 267 |
+
attention_mask=merged_attention,
|
| 268 |
+
token_type_ids=[],
|
| 269 |
+
metadata=merged_metadata
|
| 270 |
+
)
|
| 271 |
+
|
| 272 |
+
async def _interleave_capsules(self, capsules: List[TokenCapsule]) -> TokenCapsule:
|
| 273 |
+
"""Kapsülleri aralarında birleştirir"""
|
| 274 |
+
# Implement interleaving logic
|
| 275 |
+
return await self._concat_capsules(capsules)
|
| 276 |
+
|
| 277 |
+
async def _priority_merge_capsules(self, capsules: List[TokenCapsule]) -> TokenCapsule:
|
| 278 |
+
"""Öncelik sırasına göre birleştirir"""
|
| 279 |
+
# Öncelik skoruna göre sırala
|
| 280 |
+
sorted_capsules = sorted(capsules, key=lambda x: x.metadata.get("priority", 0), reverse=True)
|
| 281 |
+
return await self._concat_capsules(sorted_capsules)
|
| 282 |
+
|
| 283 |
+
def _add_to_cache(self, key: str, capsule: TokenCapsule):
|
| 284 |
+
"""Cache'e ekler"""
|
| 285 |
+
if len(self.token_cache) >= self.cache_size:
|
| 286 |
+
# En eski entry'yi sil
|
| 287 |
+
oldest_key = next(iter(self.token_cache))
|
| 288 |
+
del self.token_cache[oldest_key]
|
| 289 |
+
|
| 290 |
+
self.token_cache[key] = capsule
|
| 291 |
+
|
| 292 |
+
def _update_avg_length(self, length: int):
|
| 293 |
+
"""Ortalama token uzunluğunu günceller"""
|
| 294 |
+
current_avg = self.token_stats["avg_token_length"]
|
| 295 |
+
total_processed = self.token_stats["total_processed"]
|
| 296 |
+
|
| 297 |
+
# Yeni ortalama hesapla
|
| 298 |
+
new_avg = ((current_avg * (total_processed - 1)) + length) / total_processed
|
| 299 |
+
self.token_stats["avg_token_length"] = new_avg
|
| 300 |
+
|
| 301 |
+
def get_stats(self) -> Dict[str, Any]:
|
| 302 |
+
"""Token layer istatistikleri"""
|
| 303 |
+
cache_hit_rate = self.token_stats["cache_hits"] / max(self.token_stats["total_processed"], 1)
|
| 304 |
+
|
| 305 |
+
return {
|
| 306 |
+
"total_processed": self.token_stats["total_processed"],
|
| 307 |
+
"cache_hit_rate": cache_hit_rate,
|
| 308 |
+
"cache_size": len(self.token_cache),
|
| 309 |
+
"avg_token_length": self.token_stats["avg_token_length"],
|
| 310 |
+
"tokenizer_pool_size": len(self.tokenizer_pool)
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
def clear_cache(self):
|
| 314 |
+
"""Cache'i temizler"""
|
| 315 |
+
self.token_cache.clear()
|
| 316 |
+
logger.info("Token cache cleared")
|
download_models.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
CRANE AI - Model İndirme Script'i
|
| 4 |
+
HuggingFace'den modelleri önceden indirir
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
import logging
|
| 10 |
+
from typing import Dict, Any
|
| 11 |
+
import asyncio
|
| 12 |
+
import torch
|
| 13 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 14 |
+
from huggingface_hub import login
|
| 15 |
+
import gc
|
| 16 |
+
|
| 17 |
+
# Logging ayarları
|
| 18 |
+
logging.basicConfig(
|
| 19 |
+
level=logging.INFO,
|
| 20 |
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
| 21 |
+
)
|
| 22 |
+
logger = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
# HuggingFace Token
|
| 25 |
+
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
| 26 |
+
|
| 27 |
+
# İndirilecek modeller
|
| 28 |
+
MODELS_TO_DOWNLOAD = {
|
| 29 |
+
"deepseek-coder": {
|
| 30 |
+
"model_id": "deepseek-ai/deepseek-coder-1.3b-instruct",
|
| 31 |
+
"description": "Kod yazımı için DeepSeek Coder 1.3B",
|
| 32 |
+
"task": "code_generation"
|
| 33 |
+
},
|
| 34 |
+
"qwen-chat": {
|
| 35 |
+
"model_id": "Qwen/Qwen2.5-1.5B-Instruct",
|
| 36 |
+
"description": "Sohbet için Qwen2.5 1.5B",
|
| 37 |
+
"task": "chat"
|
| 38 |
+
},
|
| 39 |
+
"phi-reason": {
|
| 40 |
+
"model_id": "microsoft/Phi-3-mini-4k-instruct",
|
| 41 |
+
"description": "Mantık için Phi-3 Mini",
|
| 42 |
+
"task": "reasoning"
|
| 43 |
+
},
|
| 44 |
+
"tinyllama-fast": {
|
| 45 |
+
"model_id": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
|
| 46 |
+
"description": "Hızlı yanıt için TinyLlama 1.1B",
|
| 47 |
+
"task": "quick_response"
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
def get_device():
|
| 52 |
+
"""Cihaz tipini belirler"""
|
| 53 |
+
if torch.cuda.is_available():
|
| 54 |
+
return "cuda"
|
| 55 |
+
elif torch.backends.mps.is_available():
|
| 56 |
+
return "mps"
|
| 57 |
+
else:
|
| 58 |
+
return "cpu"
|
| 59 |
+
|
| 60 |
+
def setup_cache_dir():
|
| 61 |
+
"""Model cache dizinini ayarlar"""
|
| 62 |
+
cache_dir = os.path.join(os.getcwd(), "model_cache")
|
| 63 |
+
os.makedirs(cache_dir, exist_ok=True)
|
| 64 |
+
os.environ["TRANSFORMERS_CACHE"] = cache_dir
|
| 65 |
+
return cache_dir
|
| 66 |
+
|
| 67 |
+
def login_huggingface():
|
| 68 |
+
"""HuggingFace'e login ol"""
|
| 69 |
+
try:
|
| 70 |
+
login(token=HF_TOKEN)
|
| 71 |
+
logger.info("✅ HuggingFace login başarılı")
|
| 72 |
+
return True
|
| 73 |
+
except Exception as e:
|
| 74 |
+
logger.error(f"❌ HuggingFace login hatası: {str(e)}")
|
| 75 |
+
return False
|
| 76 |
+
|
| 77 |
+
def download_model(model_info: Dict[str, Any]) -> bool:
|
| 78 |
+
"""Tek bir modeli indir"""
|
| 79 |
+
model_id = model_info["model_id"]
|
| 80 |
+
description = model_info["description"]
|
| 81 |
+
|
| 82 |
+
try:
|
| 83 |
+
logger.info(f"📥 İndiriliyor: {description}")
|
| 84 |
+
logger.info(f" Model ID: {model_id}")
|
| 85 |
+
|
| 86 |
+
# Önce tokenizer'ı indir
|
| 87 |
+
logger.info(" 🔤 Tokenizer indiriliyor...")
|
| 88 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 89 |
+
model_id,
|
| 90 |
+
trust_remote_code=True,
|
| 91 |
+
token=HF_TOKEN
|
| 92 |
+
)
|
| 93 |
+
logger.info(" ✅ Tokenizer indirildi")
|
| 94 |
+
|
| 95 |
+
# Sonra modeli indir
|
| 96 |
+
logger.info(" 🤖 Model indiriliyor...")
|
| 97 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 98 |
+
model_id,
|
| 99 |
+
trust_remote_code=True,
|
| 100 |
+
torch_dtype=torch.float16 if get_device() != "cpu" else torch.float32,
|
| 101 |
+
token=HF_TOKEN
|
| 102 |
+
)
|
| 103 |
+
logger.info(" ✅ Model indirildi")
|
| 104 |
+
|
| 105 |
+
# Belleği temizle
|
| 106 |
+
del model
|
| 107 |
+
del tokenizer
|
| 108 |
+
gc.collect()
|
| 109 |
+
if torch.cuda.is_available():
|
| 110 |
+
torch.cuda.empty_cache()
|
| 111 |
+
|
| 112 |
+
logger.info(f"✅ {description} başarıyla indirildi!\n")
|
| 113 |
+
return True
|
| 114 |
+
|
| 115 |
+
except Exception as e:
|
| 116 |
+
logger.error(f"❌ {description} indirme hatası: {str(e)}\n")
|
| 117 |
+
return False
|
| 118 |
+
|
| 119 |
+
def main():
|
| 120 |
+
"""Ana fonksiyon"""
|
| 121 |
+
logger.info("🚀 CRANE AI Model İndirme Başlatılıyor...")
|
| 122 |
+
logger.info(f"🔧 Cihaz: {get_device()}")
|
| 123 |
+
|
| 124 |
+
# Cache dizini ayarla
|
| 125 |
+
cache_dir = setup_cache_dir()
|
| 126 |
+
logger.info(f"📁 Cache dizini: {cache_dir}")
|
| 127 |
+
|
| 128 |
+
# HuggingFace login
|
| 129 |
+
if not login_huggingface():
|
| 130 |
+
logger.error("❌ HuggingFace login başarısız. Çıkılıyor...")
|
| 131 |
+
sys.exit(1)
|
| 132 |
+
|
| 133 |
+
# Modelleri indir
|
| 134 |
+
logger.info(f"📦 {len(MODELS_TO_DOWNLOAD)} model indirilecek...\n")
|
| 135 |
+
|
| 136 |
+
successful_downloads = 0
|
| 137 |
+
failed_downloads = 0
|
| 138 |
+
|
| 139 |
+
for model_name, model_info in MODELS_TO_DOWNLOAD.items():
|
| 140 |
+
if download_model(model_info):
|
| 141 |
+
successful_downloads += 1
|
| 142 |
+
else:
|
| 143 |
+
failed_downloads += 1
|
| 144 |
+
|
| 145 |
+
# Özet
|
| 146 |
+
logger.info("="*50)
|
| 147 |
+
logger.info("📊 İNDİRME ÖZETİ")
|
| 148 |
+
logger.info("="*50)
|
| 149 |
+
logger.info(f"✅ Başarılı: {successful_downloads}")
|
| 150 |
+
logger.info(f"❌ Başarısız: {failed_downloads}")
|
| 151 |
+
logger.info(f"📁 Cache dizini: {cache_dir}")
|
| 152 |
+
|
| 153 |
+
if successful_downloads == len(MODELS_TO_DOWNLOAD):
|
| 154 |
+
logger.info("🎉 Tüm modeller başarıyla indirildi!")
|
| 155 |
+
else:
|
| 156 |
+
logger.warning("⚠️ Bazı modeller indirilemedi.")
|
| 157 |
+
|
| 158 |
+
logger.info("="*50)
|
| 159 |
+
|
| 160 |
+
if __name__ == "__main__":
|
| 161 |
+
main()
|
memory/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Memory Package
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .local_memory import LocalMemoryManager, MemorySlot
|
| 6 |
+
|
| 7 |
+
__all__ = ['LocalMemoryManager', 'MemorySlot']
|
memory/local_memory.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Local Memory Management
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any, List, Optional
|
| 6 |
+
import asyncio
|
| 7 |
+
import time
|
| 8 |
+
import json
|
| 9 |
+
from dataclasses import dataclass, asdict
|
| 10 |
+
from datetime import datetime, timedelta
|
| 11 |
+
import logging
|
| 12 |
+
|
| 13 |
+
logger = logging.getLogger(__name__)
|
| 14 |
+
|
| 15 |
+
@dataclass
|
| 16 |
+
class MemorySlot:
|
| 17 |
+
"""Bellek slot'u veri yapısı"""
|
| 18 |
+
id: str
|
| 19 |
+
content: Any
|
| 20 |
+
timestamp: float
|
| 21 |
+
ttl: float # Time to live (seconds)
|
| 22 |
+
access_count: int = 0
|
| 23 |
+
priority: int = 1
|
| 24 |
+
tags: List[str] = None
|
| 25 |
+
metadata: Dict[str, Any] = None
|
| 26 |
+
|
| 27 |
+
def __post_init__(self):
|
| 28 |
+
if self.tags is None:
|
| 29 |
+
self.tags = []
|
| 30 |
+
if self.metadata is None:
|
| 31 |
+
self.metadata = {}
|
| 32 |
+
|
| 33 |
+
def is_expired(self) -> bool:
|
| 34 |
+
"""Slot'un süresinin dolup dolmadığını kontrol eder"""
|
| 35 |
+
return time.time() > (self.timestamp + self.ttl)
|
| 36 |
+
|
| 37 |
+
def update_access(self):
|
| 38 |
+
"""Erişim sayısını günceller"""
|
| 39 |
+
self.access_count += 1
|
| 40 |
+
self.timestamp = time.time()
|
| 41 |
+
|
| 42 |
+
def to_dict(self) -> Dict[str, Any]:
|
| 43 |
+
"""Dictionary'e çevirir"""
|
| 44 |
+
return asdict(self)
|
| 45 |
+
|
| 46 |
+
class LocalMemoryManager:
|
| 47 |
+
"""Yerel bellek yönetimi sistemi"""
|
| 48 |
+
|
| 49 |
+
def __init__(self, config: Dict[str, Any]):
|
| 50 |
+
self.config = config
|
| 51 |
+
self.max_slots = config.get("max_slots", 10)
|
| 52 |
+
self.default_ttl = config.get("default_ttl", 3600) # 1 saat
|
| 53 |
+
self.cleanup_interval = config.get("cleanup_interval", 300) # 5 dakika
|
| 54 |
+
|
| 55 |
+
# Bellek slot'ları
|
| 56 |
+
self.slots: Dict[str, MemorySlot] = {}
|
| 57 |
+
|
| 58 |
+
# İstatistikler
|
| 59 |
+
self.stats = {
|
| 60 |
+
"total_writes": 0,
|
| 61 |
+
"total_reads": 0,
|
| 62 |
+
"cache_hits": 0,
|
| 63 |
+
"cache_misses": 0,
|
| 64 |
+
"evictions": 0,
|
| 65 |
+
"cleanups": 0
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
# Background cleanup task
|
| 69 |
+
self.cleanup_task = None
|
| 70 |
+
self.is_running = False
|
| 71 |
+
|
| 72 |
+
async def start(self):
|
| 73 |
+
"""Bellek yöneticisini başlatır"""
|
| 74 |
+
if not self.is_running:
|
| 75 |
+
self.is_running = True
|
| 76 |
+
self.cleanup_task = asyncio.create_task(self._cleanup_worker())
|
| 77 |
+
logger.info("Memory manager started")
|
| 78 |
+
|
| 79 |
+
async def stop(self):
|
| 80 |
+
"""Bellek yöneticisini durdurur"""
|
| 81 |
+
self.is_running = False
|
| 82 |
+
if self.cleanup_task:
|
| 83 |
+
self.cleanup_task.cancel()
|
| 84 |
+
try:
|
| 85 |
+
await self.cleanup_task
|
| 86 |
+
except asyncio.CancelledError:
|
| 87 |
+
pass
|
| 88 |
+
logger.info("Memory manager stopped")
|
| 89 |
+
|
| 90 |
+
async def store(self, key: str, content: Any, ttl: Optional[float] = None,
|
| 91 |
+
priority: int = 1, tags: List[str] = None, metadata: Dict[str, Any] = None) -> bool:
|
| 92 |
+
"""Bellek slot'una veri yazar"""
|
| 93 |
+
try:
|
| 94 |
+
# TTL ayarı
|
| 95 |
+
if ttl is None:
|
| 96 |
+
ttl = self.default_ttl
|
| 97 |
+
|
| 98 |
+
# Slot oluştur
|
| 99 |
+
slot = MemorySlot(
|
| 100 |
+
id=key,
|
| 101 |
+
content=content,
|
| 102 |
+
timestamp=time.time(),
|
| 103 |
+
ttl=ttl,
|
| 104 |
+
priority=priority,
|
| 105 |
+
tags=tags or [],
|
| 106 |
+
metadata=metadata or {}
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
# Yer kontrolü
|
| 110 |
+
if len(self.slots) >= self.max_slots and key not in self.slots:
|
| 111 |
+
await self._evict_slot()
|
| 112 |
+
|
| 113 |
+
# Slot'u kaydet
|
| 114 |
+
self.slots[key] = slot
|
| 115 |
+
self.stats["total_writes"] += 1
|
| 116 |
+
|
| 117 |
+
logger.debug(f"Stored in memory slot: {key}")
|
| 118 |
+
return True
|
| 119 |
+
|
| 120 |
+
except Exception as e:
|
| 121 |
+
logger.error(f"Memory store error: {str(e)}")
|
| 122 |
+
return False
|
| 123 |
+
|
| 124 |
+
async def retrieve(self, key: str) -> Optional[Any]:
|
| 125 |
+
"""Bellek slot'undan veri okur"""
|
| 126 |
+
try:
|
| 127 |
+
if key not in self.slots:
|
| 128 |
+
self.stats["cache_misses"] += 1
|
| 129 |
+
return None
|
| 130 |
+
|
| 131 |
+
slot = self.slots[key]
|
| 132 |
+
|
| 133 |
+
# Expire kontrolü
|
| 134 |
+
if slot.is_expired():
|
| 135 |
+
await self.remove(key)
|
| 136 |
+
self.stats["cache_misses"] += 1
|
| 137 |
+
return None
|
| 138 |
+
|
| 139 |
+
# Erişim güncelle
|
| 140 |
+
slot.update_access()
|
| 141 |
+
self.stats["total_reads"] += 1
|
| 142 |
+
self.stats["cache_hits"] += 1
|
| 143 |
+
|
| 144 |
+
logger.debug(f"Retrieved from memory slot: {key}")
|
| 145 |
+
return slot.content
|
| 146 |
+
|
| 147 |
+
except Exception as e:
|
| 148 |
+
logger.error(f"Memory retrieve error: {str(e)}")
|
| 149 |
+
return None
|
| 150 |
+
|
| 151 |
+
async def remove(self, key: str) -> bool:
|
| 152 |
+
"""Bellek slot'unu siler"""
|
| 153 |
+
try:
|
| 154 |
+
if key in self.slots:
|
| 155 |
+
del self.slots[key]
|
| 156 |
+
logger.debug(f"Removed memory slot: {key}")
|
| 157 |
+
return True
|
| 158 |
+
return False
|
| 159 |
+
|
| 160 |
+
except Exception as e:
|
| 161 |
+
logger.error(f"Memory remove error: {str(e)}")
|
| 162 |
+
return False
|
| 163 |
+
|
| 164 |
+
async def search_by_tags(self, tags: List[str]) -> List[MemorySlot]:
|
| 165 |
+
"""Tag'lere göre slot'ları arar"""
|
| 166 |
+
matching_slots = []
|
| 167 |
+
|
| 168 |
+
for slot in self.slots.values():
|
| 169 |
+
if not slot.is_expired():
|
| 170 |
+
if any(tag in slot.tags for tag in tags):
|
| 171 |
+
matching_slots.append(slot)
|
| 172 |
+
|
| 173 |
+
return matching_slots
|
| 174 |
+
|
| 175 |
+
async def get_active_slots(self) -> List[MemorySlot]:
|
| 176 |
+
"""Aktif slot'ları döndürür"""
|
| 177 |
+
active_slots = []
|
| 178 |
+
|
| 179 |
+
for slot in self.slots.values():
|
| 180 |
+
if not slot.is_expired():
|
| 181 |
+
active_slots.append(slot)
|
| 182 |
+
|
| 183 |
+
return active_slots
|
| 184 |
+
|
| 185 |
+
async def update_slot(self, key: str, content: Any = None, ttl: Optional[float] = None,
|
| 186 |
+
priority: Optional[int] = None, tags: Optional[List[str]] = None,
|
| 187 |
+
metadata: Optional[Dict[str, Any]] = None) -> bool:
|
| 188 |
+
"""Slot'u günceller"""
|
| 189 |
+
try:
|
| 190 |
+
if key not in self.slots:
|
| 191 |
+
return False
|
| 192 |
+
|
| 193 |
+
slot = self.slots[key]
|
| 194 |
+
|
| 195 |
+
# Expire kontrolü
|
| 196 |
+
if slot.is_expired():
|
| 197 |
+
await self.remove(key)
|
| 198 |
+
return False
|
| 199 |
+
|
| 200 |
+
# Güncellemeleri uygula
|
| 201 |
+
if content is not None:
|
| 202 |
+
slot.content = content
|
| 203 |
+
if ttl is not None:
|
| 204 |
+
slot.ttl = ttl
|
| 205 |
+
if priority is not None:
|
| 206 |
+
slot.priority = priority
|
| 207 |
+
if tags is not None:
|
| 208 |
+
slot.tags = tags
|
| 209 |
+
if metadata is not None:
|
| 210 |
+
slot.metadata.update(metadata)
|
| 211 |
+
|
| 212 |
+
slot.timestamp = time.time()
|
| 213 |
+
|
| 214 |
+
logger.debug(f"Updated memory slot: {key}")
|
| 215 |
+
return True
|
| 216 |
+
|
| 217 |
+
except Exception as e:
|
| 218 |
+
logger.error(f"Memory update error: {str(e)}")
|
| 219 |
+
return False
|
| 220 |
+
|
| 221 |
+
async def _evict_slot(self):
|
| 222 |
+
"""En az öncelikli slot'u çıkarır"""
|
| 223 |
+
if not self.slots:
|
| 224 |
+
return
|
| 225 |
+
|
| 226 |
+
# En az kullanılan ve en düşük öncelikli slot'u bul
|
| 227 |
+
candidates = []
|
| 228 |
+
for slot in self.slots.values():
|
| 229 |
+
if not slot.is_expired():
|
| 230 |
+
candidates.append(slot)
|
| 231 |
+
|
| 232 |
+
if not candidates:
|
| 233 |
+
return
|
| 234 |
+
|
| 235 |
+
# Skorlama: düşük priority + düşük access_count + eski timestamp
|
| 236 |
+
def eviction_score(slot):
|
| 237 |
+
age = time.time() - slot.timestamp
|
| 238 |
+
return (1 / slot.priority) + (1 / max(slot.access_count, 1)) + (age / 3600)
|
| 239 |
+
|
| 240 |
+
victim = max(candidates, key=eviction_score)
|
| 241 |
+
await self.remove(victim.id)
|
| 242 |
+
self.stats["evictions"] += 1
|
| 243 |
+
|
| 244 |
+
logger.debug(f"Evicted memory slot: {victim.id}")
|
| 245 |
+
|
| 246 |
+
async def _cleanup_worker(self):
|
| 247 |
+
"""Periyodik temizlik işlevi"""
|
| 248 |
+
while self.is_running:
|
| 249 |
+
try:
|
| 250 |
+
await asyncio.sleep(self.cleanup_interval)
|
| 251 |
+
await self._cleanup_expired()
|
| 252 |
+
except asyncio.CancelledError:
|
| 253 |
+
break
|
| 254 |
+
except Exception as e:
|
| 255 |
+
logger.error(f"Cleanup worker error: {str(e)}")
|
| 256 |
+
|
| 257 |
+
async def _cleanup_expired(self):
|
| 258 |
+
"""Süresi dolmuş slot'ları temizler"""
|
| 259 |
+
expired_keys = []
|
| 260 |
+
|
| 261 |
+
for key, slot in self.slots.items():
|
| 262 |
+
if slot.is_expired():
|
| 263 |
+
expired_keys.append(key)
|
| 264 |
+
|
| 265 |
+
for key in expired_keys:
|
| 266 |
+
await self.remove(key)
|
| 267 |
+
|
| 268 |
+
if expired_keys:
|
| 269 |
+
self.stats["cleanups"] += 1
|
| 270 |
+
logger.debug(f"Cleaned up {len(expired_keys)} expired slots")
|
| 271 |
+
|
| 272 |
+
async def export_memory(self, include_expired: bool = False) -> Dict[str, Any]:
|
| 273 |
+
"""Belleği dışa aktarır"""
|
| 274 |
+
export_data = {
|
| 275 |
+
"timestamp": datetime.now().isoformat(),
|
| 276 |
+
"slots": [],
|
| 277 |
+
"stats": self.stats
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
for slot in self.slots.values():
|
| 281 |
+
if include_expired or not slot.is_expired():
|
| 282 |
+
export_data["slots"].append(slot.to_dict())
|
| 283 |
+
|
| 284 |
+
return export_data
|
| 285 |
+
|
| 286 |
+
async def import_memory(self, data: Dict[str, Any]) -> bool:
|
| 287 |
+
"""Belleği içe aktarır"""
|
| 288 |
+
try:
|
| 289 |
+
slots_data = data.get("slots", [])
|
| 290 |
+
|
| 291 |
+
for slot_data in slots_data:
|
| 292 |
+
slot = MemorySlot(**slot_data)
|
| 293 |
+
if not slot.is_expired():
|
| 294 |
+
self.slots[slot.id] = slot
|
| 295 |
+
|
| 296 |
+
logger.info(f"Imported {len(slots_data)} memory slots")
|
| 297 |
+
return True
|
| 298 |
+
|
| 299 |
+
except Exception as e:
|
| 300 |
+
logger.error(f"Memory import error: {str(e)}")
|
| 301 |
+
return False
|
| 302 |
+
|
| 303 |
+
def get_stats(self) -> Dict[str, Any]:
|
| 304 |
+
"""Bellek istatistikleri"""
|
| 305 |
+
total_requests = self.stats["total_reads"]
|
| 306 |
+
hit_rate = self.stats["cache_hits"] / max(total_requests, 1)
|
| 307 |
+
|
| 308 |
+
active_slots = sum(1 for slot in self.slots.values() if not slot.is_expired())
|
| 309 |
+
|
| 310 |
+
return {
|
| 311 |
+
"total_slots": len(self.slots),
|
| 312 |
+
"active_slots": active_slots,
|
| 313 |
+
"max_slots": self.max_slots,
|
| 314 |
+
"hit_rate": hit_rate,
|
| 315 |
+
"total_writes": self.stats["total_writes"],
|
| 316 |
+
"total_reads": self.stats["total_reads"],
|
| 317 |
+
"evictions": self.stats["evictions"],
|
| 318 |
+
"cleanups": self.stats["cleanups"]
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
async def clear_all(self):
|
| 322 |
+
"""Tüm belleği temizler"""
|
| 323 |
+
self.slots.clear()
|
| 324 |
+
logger.info("All memory slots cleared")
|
modules/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Modüller
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .code_module import CodeModule
|
| 6 |
+
from .chat_module import ChatModule
|
| 7 |
+
from .reason_module import ReasonModule
|
| 8 |
+
from .fast_module import FastModule
|
| 9 |
+
|
| 10 |
+
__all__ = [
|
| 11 |
+
'CodeModule',
|
| 12 |
+
'ChatModule',
|
| 13 |
+
'ReasonModule',
|
| 14 |
+
'FastModule'
|
| 15 |
+
]
|
modules/chat_module.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Sohbet Modülü
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any
|
| 6 |
+
from core.base_module import BaseMicroModule
|
| 7 |
+
import logging
|
| 8 |
+
|
| 9 |
+
logger = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
class ChatModule(BaseMicroModule):
|
| 12 |
+
"""Genel sohbet için özelleşmiş modül"""
|
| 13 |
+
|
| 14 |
+
def __init__(self, config: Dict[str, Any]):
|
| 15 |
+
super().__init__(
|
| 16 |
+
model_id="Qwen/Qwen2.5-1.5B-Instruct",
|
| 17 |
+
config=config
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
# Sohbet anahtar kelimeleri
|
| 21 |
+
self.chat_keywords = {
|
| 22 |
+
"merhaba", "selam", "nasılsın", "naber", "günaydın",
|
| 23 |
+
"iyi akşamlar", "hoş geldin", "sohbet", "konuş",
|
| 24 |
+
"anlat", "düşün", "fikir", "görüş", "yardım",
|
| 25 |
+
"açıkla", "izah", "detay", "örnek", "hikaye"
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
# Genel konular
|
| 29 |
+
self.general_topics = {
|
| 30 |
+
"hava", "spor", "müzik", "film", "kitap", "yemek",
|
| 31 |
+
"seyahat", "hobiler", "oyun", "teknoloji", "tarih",
|
| 32 |
+
"kültür", "sanat", "bilim", "doğa", "eğitim"
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
def can_handle(self, query: str, context: Dict[str, Any]) -> float:
|
| 36 |
+
"""Sohbet sorguları için uygunluk skoru"""
|
| 37 |
+
query_lower = query.lower()
|
| 38 |
+
|
| 39 |
+
# Sohbet anahtar kelimelerini kontrol et
|
| 40 |
+
chat_score = 0
|
| 41 |
+
for keyword in self.chat_keywords:
|
| 42 |
+
if keyword in query_lower:
|
| 43 |
+
chat_score += 0.15
|
| 44 |
+
|
| 45 |
+
# Genel konuları kontrol et
|
| 46 |
+
for topic in self.general_topics:
|
| 47 |
+
if topic in query_lower:
|
| 48 |
+
chat_score += 0.1
|
| 49 |
+
|
| 50 |
+
# Soru işaretleri ve konuşma ifadeleri
|
| 51 |
+
if "?" in query or "nedir" in query_lower or "nasıl" in query_lower:
|
| 52 |
+
chat_score += 0.2
|
| 53 |
+
|
| 54 |
+
# Uzun açıklama gerektiren sorular
|
| 55 |
+
if any(word in query_lower for word in ["açıkla", "anlat", "detay", "neden"]):
|
| 56 |
+
chat_score += 0.25
|
| 57 |
+
|
| 58 |
+
# Kısa ve basit sorular için yüksek skor
|
| 59 |
+
if len(query.split()) <= 10:
|
| 60 |
+
chat_score += 0.1
|
| 61 |
+
|
| 62 |
+
# Maksimum 1.0 skor
|
| 63 |
+
return min(chat_score, 1.0)
|
| 64 |
+
|
| 65 |
+
async def process(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 66 |
+
"""Sohbet işlemi"""
|
| 67 |
+
try:
|
| 68 |
+
# Sohbet için özel prompt
|
| 69 |
+
prompt = self._build_chat_prompt(query, context)
|
| 70 |
+
|
| 71 |
+
# Yanıt üretimi
|
| 72 |
+
response = await self.generate_response(
|
| 73 |
+
prompt,
|
| 74 |
+
max_tokens=self.config.get("max_tokens", 1024),
|
| 75 |
+
temperature=0.7 # Sohbet için orta temperature
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
return {
|
| 79 |
+
"response": response,
|
| 80 |
+
"module": "chat_module",
|
| 81 |
+
"confidence": self.can_handle(query, context),
|
| 82 |
+
"conversation_type": self._detect_conversation_type(query)
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
except Exception as e:
|
| 86 |
+
logger.error(f"Chat processing error: {str(e)}")
|
| 87 |
+
return {
|
| 88 |
+
"error": str(e),
|
| 89 |
+
"module": "chat_module"
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
def _build_chat_prompt(self, query: str, context: Dict[str, Any]) -> str:
|
| 93 |
+
"""Sohbet için prompt hazırlar"""
|
| 94 |
+
|
| 95 |
+
# Konuşma geçmişi
|
| 96 |
+
history = context.get("history", [])
|
| 97 |
+
|
| 98 |
+
# Temel prompt
|
| 99 |
+
prompt = f"""Sen yardımsever, dostane ve zeki bir asistansın. Kullanıcılarla doğal bir şekilde sohbet ediyorsun.
|
| 100 |
+
|
| 101 |
+
Özellikler:
|
| 102 |
+
- Türkçe konuşuyorsun
|
| 103 |
+
- Samimi ve dostane bir ton kullanıyorsun
|
| 104 |
+
- Bilgilendirici ama sıkıcı olmayan yanıtlar veriyorsun
|
| 105 |
+
- Kullanıcının duygusal durumunu anlıyorsun
|
| 106 |
+
|
| 107 |
+
"""
|
| 108 |
+
|
| 109 |
+
# Konuşma geçmişi varsa ekle
|
| 110 |
+
if history:
|
| 111 |
+
prompt += "Önceki konuşma:\n"
|
| 112 |
+
for i, msg in enumerate(history[-3:]): # Son 3 mesajı al
|
| 113 |
+
prompt += f"{'Kullanıcı' if i % 2 == 0 else 'Asistan'}: {msg}\n"
|
| 114 |
+
prompt += "\n"
|
| 115 |
+
|
| 116 |
+
# Mevcut soru
|
| 117 |
+
prompt += f"Kullanıcı: {query}\nAsistan:"
|
| 118 |
+
|
| 119 |
+
return prompt
|
| 120 |
+
|
| 121 |
+
def _detect_conversation_type(self, query: str) -> str:
|
| 122 |
+
"""Konuşma türünü tespit eder"""
|
| 123 |
+
query_lower = query.lower()
|
| 124 |
+
|
| 125 |
+
# Selamlama
|
| 126 |
+
if any(word in query_lower for word in ["merhaba", "selam", "günaydın"]):
|
| 127 |
+
return "greeting"
|
| 128 |
+
|
| 129 |
+
# Soru
|
| 130 |
+
if "?" in query or any(word in query_lower for word in ["nedir", "nasıl", "neden"]):
|
| 131 |
+
return "question"
|
| 132 |
+
|
| 133 |
+
# Duygusal
|
| 134 |
+
if any(word in query_lower for word in ["üzgün", "mutlu", "kızgın", "heyecanlı"]):
|
| 135 |
+
return "emotional"
|
| 136 |
+
|
| 137 |
+
# Bilgi arama
|
| 138 |
+
if any(word in query_lower for word in ["açıkla", "anlat", "öğren", "bilgi"]):
|
| 139 |
+
return "information"
|
| 140 |
+
|
| 141 |
+
# Varsayılan
|
| 142 |
+
return "general"
|
modules/code_module.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Kod Yazım Modülü
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import re
|
| 6 |
+
from typing import Dict, Any
|
| 7 |
+
from core.base_module import BaseMicroModule
|
| 8 |
+
import logging
|
| 9 |
+
|
| 10 |
+
logger = logging.getLogger(__name__)
|
| 11 |
+
|
| 12 |
+
class CodeModule(BaseMicroModule):
|
| 13 |
+
"""Kod yazımı için özelleşmiş modül"""
|
| 14 |
+
|
| 15 |
+
def __init__(self, config: Dict[str, Any]):
|
| 16 |
+
super().__init__(
|
| 17 |
+
model_id="deepseek-ai/deepseek-coder-1.3b-instruct",
|
| 18 |
+
config=config
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
# Kod kelime anahtar kelimeleri
|
| 22 |
+
self.code_keywords = {
|
| 23 |
+
"function", "class", "def", "import", "from", "return",
|
| 24 |
+
"if", "else", "for", "while", "try", "except", "with",
|
| 25 |
+
"python", "javascript", "java", "c++", "html", "css",
|
| 26 |
+
"kod", "kodu", "script", "fonksiyon", "sınıf", "algoritma",
|
| 27 |
+
"program", "yazılım", "debug", "hata", "fix", "düzelt"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
# Programlama dilleri
|
| 31 |
+
self.programming_languages = {
|
| 32 |
+
"python", "javascript", "java", "c++", "c#", "php", "ruby",
|
| 33 |
+
"go", "rust", "kotlin", "swift", "typescript", "html", "css",
|
| 34 |
+
"sql", "bash", "powershell", "r", "matlab", "scala"
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
def can_handle(self, query: str, context: Dict[str, Any]) -> float:
|
| 38 |
+
"""Kod yazımı sorguları için uygunluk skoru"""
|
| 39 |
+
query_lower = query.lower()
|
| 40 |
+
|
| 41 |
+
# Kod anahtar kelimelerini kontrol et
|
| 42 |
+
code_score = 0
|
| 43 |
+
for keyword in self.code_keywords:
|
| 44 |
+
if keyword in query_lower:
|
| 45 |
+
code_score += 0.15
|
| 46 |
+
|
| 47 |
+
# Programlama dili belirtilmişse
|
| 48 |
+
for lang in self.programming_languages:
|
| 49 |
+
if lang in query_lower:
|
| 50 |
+
code_score += 0.3
|
| 51 |
+
|
| 52 |
+
# Kod yazımı action kelimeleri
|
| 53 |
+
action_keywords = ["yaz", "oluştur", "geliştir", "kur", "hazırla", "tasarla"]
|
| 54 |
+
for action in action_keywords:
|
| 55 |
+
if action in query_lower:
|
| 56 |
+
code_score += 0.2
|
| 57 |
+
|
| 58 |
+
# Kod karakteristik işaretlerini kontrol et
|
| 59 |
+
if any(char in query for char in ["()", "{}", "[]", "==", "!=", "<=", ">="]):
|
| 60 |
+
code_score += 0.15
|
| 61 |
+
|
| 62 |
+
# Kod blokları varsa
|
| 63 |
+
if "```" in query or "def " in query or "class " in query:
|
| 64 |
+
code_score += 0.3
|
| 65 |
+
|
| 66 |
+
# Spesifik kod türleri
|
| 67 |
+
code_types = ["hesap", "makinesi", "calculator", "app", "uygulama", "website", "site"]
|
| 68 |
+
for code_type in code_types:
|
| 69 |
+
if code_type in query_lower:
|
| 70 |
+
code_score += 0.25
|
| 71 |
+
|
| 72 |
+
# Maksimum 1.0 skor
|
| 73 |
+
return min(code_score, 1.0)
|
| 74 |
+
|
| 75 |
+
async def process(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 76 |
+
"""Kod yazımı işlemi"""
|
| 77 |
+
try:
|
| 78 |
+
# Kod yazımı için özel prompt
|
| 79 |
+
prompt = self._build_code_prompt(query, context)
|
| 80 |
+
|
| 81 |
+
# Kod üretimi
|
| 82 |
+
response = await self.generate_response(
|
| 83 |
+
prompt,
|
| 84 |
+
max_tokens=self.config.get("max_tokens", 2048),
|
| 85 |
+
temperature=0.1 # Kod için düşük temperature
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
# Kod bloklarını ayıkla
|
| 89 |
+
code_blocks = self._extract_code_blocks(response)
|
| 90 |
+
|
| 91 |
+
return {
|
| 92 |
+
"response": response,
|
| 93 |
+
"code_blocks": code_blocks,
|
| 94 |
+
"language": self._detect_language(query),
|
| 95 |
+
"module": "code_module",
|
| 96 |
+
"confidence": self.can_handle(query, context)
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
except Exception as e:
|
| 100 |
+
logger.error(f"Code processing error: {str(e)}")
|
| 101 |
+
return {
|
| 102 |
+
"error": str(e),
|
| 103 |
+
"module": "code_module"
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
def _build_code_prompt(self, query: str, context: Dict[str, Any]) -> str:
|
| 107 |
+
"""Kod yazımı için prompt hazırlar"""
|
| 108 |
+
|
| 109 |
+
# Dil tespiti
|
| 110 |
+
language = self._detect_language(query)
|
| 111 |
+
|
| 112 |
+
# Temel prompt
|
| 113 |
+
prompt = f"""Sen bir uzman programcısın. Kullanıcının sorusunu anla ve en iyi kodu yaz.
|
| 114 |
+
|
| 115 |
+
Kullanıcı sorusu: {query}
|
| 116 |
+
|
| 117 |
+
Lütfen:
|
| 118 |
+
1. Temiz, okunabilir kod yaz
|
| 119 |
+
2. Kod açıklamalarını Türkçe yap
|
| 120 |
+
3. En iyi pratikleri kullan
|
| 121 |
+
4. Gerekirse örnek kullanımı göster
|
| 122 |
+
|
| 123 |
+
"""
|
| 124 |
+
|
| 125 |
+
# Dil özelinde ekleme
|
| 126 |
+
if language:
|
| 127 |
+
prompt += f"Programlama dili: {language}\n"
|
| 128 |
+
|
| 129 |
+
# Bağlam varsa ekle
|
| 130 |
+
if context.get("history"):
|
| 131 |
+
prompt += f"Önceki konuşma: {context['history'][-1]}\n"
|
| 132 |
+
|
| 133 |
+
return prompt
|
| 134 |
+
|
| 135 |
+
def _detect_language(self, query: str) -> str:
|
| 136 |
+
"""Sorgudan programlama dilini tespit eder"""
|
| 137 |
+
query_lower = query.lower()
|
| 138 |
+
|
| 139 |
+
for lang in self.programming_languages:
|
| 140 |
+
if lang in query_lower:
|
| 141 |
+
return lang
|
| 142 |
+
|
| 143 |
+
# Varsayılan dil
|
| 144 |
+
return "python"
|
| 145 |
+
|
| 146 |
+
def _extract_code_blocks(self, response: str) -> list:
|
| 147 |
+
"""Yanıttan kod bloklarını ayıklar"""
|
| 148 |
+
code_blocks = []
|
| 149 |
+
|
| 150 |
+
# Markdown kod blokları
|
| 151 |
+
pattern = r'```(\w+)?\n(.*?)\n```'
|
| 152 |
+
matches = re.findall(pattern, response, re.DOTALL)
|
| 153 |
+
|
| 154 |
+
for match in matches:
|
| 155 |
+
lang, code = match
|
| 156 |
+
code_blocks.append({
|
| 157 |
+
"language": lang or "text",
|
| 158 |
+
"code": code.strip()
|
| 159 |
+
})
|
| 160 |
+
|
| 161 |
+
# Tek satır kod blokları
|
| 162 |
+
inline_pattern = r'`([^`]+)`'
|
| 163 |
+
inline_matches = re.findall(inline_pattern, response)
|
| 164 |
+
|
| 165 |
+
for code in inline_matches:
|
| 166 |
+
if len(code) > 5: # Çok kısa olanları atla
|
| 167 |
+
code_blocks.append({
|
| 168 |
+
"language": "inline",
|
| 169 |
+
"code": code.strip()
|
| 170 |
+
})
|
| 171 |
+
|
| 172 |
+
return code_blocks
|
modules/fast_module.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Fast Response Modülü
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any
|
| 6 |
+
from core.base_module import BaseMicroModule
|
| 7 |
+
import logging
|
| 8 |
+
import asyncio
|
| 9 |
+
|
| 10 |
+
# Weather tool import
|
| 11 |
+
try:
|
| 12 |
+
from tools.weather_tool import WeatherTool
|
| 13 |
+
WEATHER_TOOL_AVAILABLE = True
|
| 14 |
+
except ImportError:
|
| 15 |
+
WEATHER_TOOL_AVAILABLE = False
|
| 16 |
+
WeatherTool = None
|
| 17 |
+
|
| 18 |
+
logger = logging.getLogger(__name__)
|
| 19 |
+
|
| 20 |
+
class FastModule(BaseMicroModule):
|
| 21 |
+
"""Hızlı yanıt için özelleşmiş modül"""
|
| 22 |
+
|
| 23 |
+
def __init__(self, config: Dict[str, Any]):
|
| 24 |
+
super().__init__(
|
| 25 |
+
model_id="TinyLlama/TinyLlama-1.1B-Chat-v1.0",
|
| 26 |
+
config=config
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
# Weather tool initialize
|
| 30 |
+
if WEATHER_TOOL_AVAILABLE:
|
| 31 |
+
self.weather_tool = WeatherTool()
|
| 32 |
+
else:
|
| 33 |
+
self.weather_tool = None
|
| 34 |
+
|
| 35 |
+
# Hızlı yanıt anahtar kelimeleri
|
| 36 |
+
self.quick_keywords = {
|
| 37 |
+
"hızlı", "kısa", "özet", "basit", "kolay",
|
| 38 |
+
"evet", "hayır", "doğru", "yanlış", "kim",
|
| 39 |
+
"ne", "nerede", "ne zaman", "kaç", "hangi",
|
| 40 |
+
"merhaba", "selam", "teşekkür", "tamam"
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
# Basit soru türleri
|
| 44 |
+
self.simple_patterns = {
|
| 45 |
+
"greeting": ["merhaba", "selam", "günaydın", "iyi akşam"],
|
| 46 |
+
"thanks": ["teşekkür", "sağol", "merci"],
|
| 47 |
+
"simple_question": ["kim", "ne", "nerede", "kaç"],
|
| 48 |
+
"yes_no": ["mı", "mi", "mu", "mü"],
|
| 49 |
+
"time": ["saat", "tarih", "zaman"],
|
| 50 |
+
"weather": ["hava", "sıcaklık", "yağmur"]
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
# Hazır yanıtlar
|
| 54 |
+
self.quick_responses = {
|
| 55 |
+
"greeting": [
|
| 56 |
+
"Merhaba! Size nasıl yardımcı olabilirim?",
|
| 57 |
+
"Selam! Bugün nasılsınız?",
|
| 58 |
+
"Günaydın! Ne yapmak istiyorsunuz?"
|
| 59 |
+
],
|
| 60 |
+
"thanks": [
|
| 61 |
+
"Rica ederim! Başka bir konuda yardımcı olabilir miyim?",
|
| 62 |
+
"Bir şey değil! Başka sorunuz var mı?",
|
| 63 |
+
"Memnun oldum! Size daha nasıl yardımcı olabilirim?"
|
| 64 |
+
],
|
| 65 |
+
"unknown": [
|
| 66 |
+
"Bu konuda daha detaylı bilgi verebilir miyim?",
|
| 67 |
+
"Sorunuzu biraz daha açabilir misiniz?",
|
| 68 |
+
"Bu konuda size yardımcı olmak istiyorum."
|
| 69 |
+
]
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
def can_handle(self, query: str, context: Dict[str, Any]) -> float:
|
| 73 |
+
"""Hızlı yanıt sorguları için uygunluk skoru"""
|
| 74 |
+
query_lower = query.lower()
|
| 75 |
+
|
| 76 |
+
# Kod anahtar kelimelerini kontrol et (negatif skor)
|
| 77 |
+
code_keywords = {
|
| 78 |
+
"function", "class", "def", "import", "from", "return",
|
| 79 |
+
"if", "else", "for", "while", "try", "except", "with",
|
| 80 |
+
"python", "javascript", "java", "c++", "html", "css",
|
| 81 |
+
"kod", "kodu", "script", "fonksiyon", "sınıf", "algoritma",
|
| 82 |
+
"program", "yazılım", "debug", "hata", "fix", "düzelt",
|
| 83 |
+
"yaz", "oluştur", "geliştir", "hesap", "makinesi"
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
# Kod soruları için düşük skor
|
| 87 |
+
for keyword in code_keywords:
|
| 88 |
+
if keyword in query_lower:
|
| 89 |
+
return 0.1 # Çok düşük skor
|
| 90 |
+
|
| 91 |
+
# Hızlı yanıt anahtar kelimelerini kontrol et
|
| 92 |
+
quick_score = 0
|
| 93 |
+
for keyword in self.quick_keywords:
|
| 94 |
+
if keyword in query_lower:
|
| 95 |
+
quick_score += 0.15
|
| 96 |
+
|
| 97 |
+
# Basit soru pattern'larını kontrol et
|
| 98 |
+
for pattern_type, patterns in self.simple_patterns.items():
|
| 99 |
+
for pattern in patterns:
|
| 100 |
+
if pattern in query_lower:
|
| 101 |
+
quick_score += 0.2
|
| 102 |
+
|
| 103 |
+
# Kısa sorular için yüksek skor
|
| 104 |
+
word_count = len(query.split())
|
| 105 |
+
if word_count <= 5:
|
| 106 |
+
quick_score += 0.3
|
| 107 |
+
elif word_count <= 10:
|
| 108 |
+
quick_score += 0.2
|
| 109 |
+
|
| 110 |
+
# Selamlama ve teşekkür ifadeleri
|
| 111 |
+
if any(word in query_lower for word in ["merhaba", "selam", "teşekkür", "sağol"]):
|
| 112 |
+
quick_score += 0.4
|
| 113 |
+
|
| 114 |
+
# Evet/hayır soruları
|
| 115 |
+
if any(ending in query_lower for ending in ["mı?", "mi?", "mu?", "mü?"]):
|
| 116 |
+
quick_score += 0.25
|
| 117 |
+
|
| 118 |
+
# Hava durumu soruları için yüksek skor
|
| 119 |
+
if self.weather_tool and self.weather_tool.can_handle(query):
|
| 120 |
+
quick_score += 0.6
|
| 121 |
+
|
| 122 |
+
# Maksimum 1.0 skor
|
| 123 |
+
return min(quick_score, 1.0)
|
| 124 |
+
|
| 125 |
+
async def process(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 126 |
+
"""Hızlı yanıt işlemi"""
|
| 127 |
+
try:
|
| 128 |
+
# Weather tool kontrolü
|
| 129 |
+
if self.weather_tool and self.weather_tool.can_handle(query):
|
| 130 |
+
weather_response = await self.weather_tool.process_weather_query(query)
|
| 131 |
+
return {
|
| 132 |
+
"response": weather_response,
|
| 133 |
+
"module": "fast_module",
|
| 134 |
+
"confidence": self.can_handle(query, context),
|
| 135 |
+
"response_type": "weather_tool",
|
| 136 |
+
"cached": False,
|
| 137 |
+
"tool_used": "weather_api"
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
# Önce hazır yanıt kontrolü
|
| 141 |
+
quick_response = self._check_quick_response(query)
|
| 142 |
+
if quick_response:
|
| 143 |
+
return {
|
| 144 |
+
"response": quick_response,
|
| 145 |
+
"module": "fast_module",
|
| 146 |
+
"confidence": self.can_handle(query, context),
|
| 147 |
+
"response_type": "quick",
|
| 148 |
+
"cached": True
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
# Hızlı yanıt için özel prompt
|
| 152 |
+
prompt = self._build_fast_prompt(query, context)
|
| 153 |
+
|
| 154 |
+
# Yanıt üretimi (düşük token limit)
|
| 155 |
+
response = await self.generate_response(
|
| 156 |
+
prompt,
|
| 157 |
+
max_tokens=min(self.config.get("max_tokens", 512), 256), # Maksimum 256 token
|
| 158 |
+
temperature=0.8 # Hızlı yanıt için yüksek temperature
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
return {
|
| 162 |
+
"response": response,
|
| 163 |
+
"module": "fast_module",
|
| 164 |
+
"confidence": self.can_handle(query, context),
|
| 165 |
+
"response_type": "generated",
|
| 166 |
+
"cached": False
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
except Exception as e:
|
| 170 |
+
logger.error(f"Fast processing error: {str(e)}")
|
| 171 |
+
return {
|
| 172 |
+
"error": str(e),
|
| 173 |
+
"module": "fast_module"
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
def _check_quick_response(self, query: str) -> str:
|
| 177 |
+
"""Hazır yanıtları kontrol eder"""
|
| 178 |
+
query_lower = query.lower()
|
| 179 |
+
|
| 180 |
+
# Selamlama kontrolü
|
| 181 |
+
if any(word in query_lower for word in self.simple_patterns["greeting"]):
|
| 182 |
+
import random
|
| 183 |
+
return random.choice(self.quick_responses["greeting"])
|
| 184 |
+
|
| 185 |
+
# Teşekkür kontrolü
|
| 186 |
+
if any(word in query_lower for word in self.simple_patterns["thanks"]):
|
| 187 |
+
import random
|
| 188 |
+
return random.choice(self.quick_responses["thanks"])
|
| 189 |
+
|
| 190 |
+
# Basit evet/hayır soruları
|
| 191 |
+
if len(query.split()) <= 3:
|
| 192 |
+
if any(ending in query_lower for ending in ["mı?", "mi?", "mu?", "mü?"]):
|
| 193 |
+
return "Bu konuda kesin bir yanıt verebilmek için biraz daha detay gerekiyor."
|
| 194 |
+
|
| 195 |
+
return None
|
| 196 |
+
|
| 197 |
+
def _build_fast_prompt(self, query: str, context: Dict[str, Any]) -> str:
|
| 198 |
+
"""Hızlı yanıt için prompt hazırlar"""
|
| 199 |
+
|
| 200 |
+
# Sorgu türünü belirle
|
| 201 |
+
query_type = self._detect_query_type(query)
|
| 202 |
+
|
| 203 |
+
# Temel prompt
|
| 204 |
+
prompt = f"""Sen hızlı ve özlü yanıtlar veren bir asistansın. Kısa ve net cevaplar veriyorsun.
|
| 205 |
+
|
| 206 |
+
Kullanıcı sorusu: {query}
|
| 207 |
+
|
| 208 |
+
Lütfen:
|
| 209 |
+
1. Kısa ve net yanıt ver
|
| 210 |
+
2. Gereksiz detaylara girme
|
| 211 |
+
3. Doğrudan soruyu yanıtla
|
| 212 |
+
4. Maksimum 2-3 cümle kullan
|
| 213 |
+
|
| 214 |
+
Soru türü: {query_type}
|
| 215 |
+
"""
|
| 216 |
+
|
| 217 |
+
# Bağlam varsa kısaca ekle
|
| 218 |
+
if context.get("history"):
|
| 219 |
+
last_msg = context["history"][-1]
|
| 220 |
+
if len(last_msg) < 100: # Sadece kısa geçmişi ekle
|
| 221 |
+
prompt += f"\nÖnceki: {last_msg}\n"
|
| 222 |
+
|
| 223 |
+
return prompt
|
| 224 |
+
|
| 225 |
+
def _detect_query_type(self, query: str) -> str:
|
| 226 |
+
"""Sorgu türünü tespit eder"""
|
| 227 |
+
query_lower = query.lower()
|
| 228 |
+
|
| 229 |
+
# Selamlama
|
| 230 |
+
if any(word in query_lower for word in self.simple_patterns["greeting"]):
|
| 231 |
+
return "greeting"
|
| 232 |
+
|
| 233 |
+
# Teşekkür
|
| 234 |
+
if any(word in query_lower for word in self.simple_patterns["thanks"]):
|
| 235 |
+
return "thanks"
|
| 236 |
+
|
| 237 |
+
# Basit soru
|
| 238 |
+
if any(word in query_lower for word in self.simple_patterns["simple_question"]):
|
| 239 |
+
return "simple_question"
|
| 240 |
+
|
| 241 |
+
# Evet/hayır
|
| 242 |
+
if any(ending in query_lower for ending in ["mı?", "mi?", "mu?", "mü?"]):
|
| 243 |
+
return "yes_no"
|
| 244 |
+
|
| 245 |
+
# Zaman
|
| 246 |
+
if any(word in query_lower for word in self.simple_patterns["time"]):
|
| 247 |
+
return "time"
|
| 248 |
+
|
| 249 |
+
# Hava
|
| 250 |
+
if any(word in query_lower for word in self.simple_patterns["weather"]):
|
| 251 |
+
return "weather"
|
| 252 |
+
|
| 253 |
+
# Kısa soru
|
| 254 |
+
if len(query.split()) <= 5:
|
| 255 |
+
return "short_question"
|
| 256 |
+
|
| 257 |
+
# Varsayılan
|
| 258 |
+
return "general"
|
modules/reason_module.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Reasoning Modülü
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any
|
| 6 |
+
from core.base_module import BaseMicroModule
|
| 7 |
+
import logging
|
| 8 |
+
|
| 9 |
+
logger = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
class ReasonModule(BaseMicroModule):
|
| 12 |
+
"""Mantık yürütme için özelleşmiş modül"""
|
| 13 |
+
|
| 14 |
+
def __init__(self, config: Dict[str, Any]):
|
| 15 |
+
super().__init__(
|
| 16 |
+
model_id="microsoft/Phi-3-mini-4k-instruct",
|
| 17 |
+
config=config
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
# Mantık yürütme anahtar kelimeleri
|
| 21 |
+
self.reasoning_keywords = {
|
| 22 |
+
"çünkü", "neden", "sebep", "niye", "nasıl", "analiz",
|
| 23 |
+
"karşılaştır", "değerlendir", "açıkla", "kanıtla",
|
| 24 |
+
"sonuç", "çıkarım", "mantık", "düşünce", "fikir",
|
| 25 |
+
"strateji", "plan", "çözüm", "problem", "sorun",
|
| 26 |
+
"avantaj", "dezavantaj", "fark", "benzerlik"
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
# Analiz türleri
|
| 30 |
+
self.analysis_types = {
|
| 31 |
+
"problem_solving", "comparison", "evaluation",
|
| 32 |
+
"cause_effect", "strategy", "pros_cons"
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
def can_handle(self, query: str, context: Dict[str, Any]) -> float:
|
| 36 |
+
"""Mantık yürütme sorguları için uygunluk skoru"""
|
| 37 |
+
query_lower = query.lower()
|
| 38 |
+
|
| 39 |
+
# Mantık yürütme anahtar kelimelerini kontrol et
|
| 40 |
+
reasoning_score = 0
|
| 41 |
+
for keyword in self.reasoning_keywords:
|
| 42 |
+
if keyword in query_lower:
|
| 43 |
+
reasoning_score += 0.12
|
| 44 |
+
|
| 45 |
+
# Soru türlerini kontrol et
|
| 46 |
+
if "neden" in query_lower or "çünkü" in query_lower:
|
| 47 |
+
reasoning_score += 0.25
|
| 48 |
+
|
| 49 |
+
# Karşılaştırma ifadeleri
|
| 50 |
+
if any(word in query_lower for word in ["karşılaştır", "fark", "benzer", "hangisi"]):
|
| 51 |
+
reasoning_score += 0.2
|
| 52 |
+
|
| 53 |
+
# Analiz gerektiren ifadeler
|
| 54 |
+
if any(word in query_lower for word in ["analiz", "değerlendir", "incele", "araştır"]):
|
| 55 |
+
reasoning_score += 0.2
|
| 56 |
+
|
| 57 |
+
# Problem çözme ifadeleri
|
| 58 |
+
if any(word in query_lower for word in ["problem", "sorun", "çözüm", "nasıl"]):
|
| 59 |
+
reasoning_score += 0.15
|
| 60 |
+
|
| 61 |
+
# Uzun ve karmaşık sorular
|
| 62 |
+
if len(query.split()) > 15:
|
| 63 |
+
reasoning_score += 0.1
|
| 64 |
+
|
| 65 |
+
# Maksimum 1.0 skor
|
| 66 |
+
return min(reasoning_score, 1.0)
|
| 67 |
+
|
| 68 |
+
async def process(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 69 |
+
"""Mantık yürütme işlemi"""
|
| 70 |
+
try:
|
| 71 |
+
# Analiz türünü belirle
|
| 72 |
+
analysis_type = self._detect_analysis_type(query)
|
| 73 |
+
|
| 74 |
+
# Mantık yürütme için özel prompt
|
| 75 |
+
prompt = self._build_reasoning_prompt(query, context, analysis_type)
|
| 76 |
+
|
| 77 |
+
# Yanıt üretimi
|
| 78 |
+
response = await self.generate_response(
|
| 79 |
+
prompt,
|
| 80 |
+
max_tokens=self.config.get("max_tokens", 1024),
|
| 81 |
+
temperature=0.3 # Mantık yürütme için düşük temperature
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
return {
|
| 85 |
+
"response": response,
|
| 86 |
+
"module": "reason_module",
|
| 87 |
+
"confidence": self.can_handle(query, context),
|
| 88 |
+
"analysis_type": analysis_type,
|
| 89 |
+
"reasoning_steps": self._extract_reasoning_steps(response)
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
except Exception as e:
|
| 93 |
+
logger.error(f"Reasoning processing error: {str(e)}")
|
| 94 |
+
return {
|
| 95 |
+
"error": str(e),
|
| 96 |
+
"module": "reason_module"
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
def _build_reasoning_prompt(self, query: str, context: Dict[str, Any], analysis_type: str) -> str:
|
| 100 |
+
"""Mantık yürütme için prompt hazırlar"""
|
| 101 |
+
|
| 102 |
+
# Analiz türüne göre özel prompt
|
| 103 |
+
if analysis_type == "problem_solving":
|
| 104 |
+
system_prompt = """Sen bir problem çözme uzmanısın. Sorunları adım adım analiz edip mantıklı çözümler üretiyorsun."""
|
| 105 |
+
elif analysis_type == "comparison":
|
| 106 |
+
system_prompt = """Sen bir karşılaştırma uzmanısın. Farklı seçenekleri objektif bir şekilde karşılaştırıyorsun."""
|
| 107 |
+
elif analysis_type == "evaluation":
|
| 108 |
+
system_prompt = """Sen bir değerlendirme uzmanısın. Durumları kapsamlı bir şekilde analiz ediyorsun."""
|
| 109 |
+
elif analysis_type == "cause_effect":
|
| 110 |
+
system_prompt = """Sen bir sebep-sonuç analizi uzmanısın. Olaylar arasındaki ilişkileri açıklıyorsun."""
|
| 111 |
+
else:
|
| 112 |
+
system_prompt = """Sen bir mantık yürütme uzmanısın. Karmaşık konuları açık ve anlaşılır şekilde analiz ediyorsun."""
|
| 113 |
+
|
| 114 |
+
# Temel prompt
|
| 115 |
+
prompt = f"""{system_prompt}
|
| 116 |
+
|
| 117 |
+
Kullanıcı sorusu: {query}
|
| 118 |
+
|
| 119 |
+
Lütfen:
|
| 120 |
+
1. Konuyu kapsamlı analiz et
|
| 121 |
+
2. Mantık zincirini açıkla
|
| 122 |
+
3. Somut örnekler ver
|
| 123 |
+
4. Sonuçları net bir şekilde özetle
|
| 124 |
+
|
| 125 |
+
Analiz türü: {analysis_type}
|
| 126 |
+
"""
|
| 127 |
+
|
| 128 |
+
# Bağlam varsa ekle
|
| 129 |
+
if context.get("history"):
|
| 130 |
+
prompt += f"\nÖnceki konuşma: {context['history'][-1]}\n"
|
| 131 |
+
|
| 132 |
+
return prompt
|
| 133 |
+
|
| 134 |
+
def _detect_analysis_type(self, query: str) -> str:
|
| 135 |
+
"""Sorgudan analiz türünü tespit eder"""
|
| 136 |
+
query_lower = query.lower()
|
| 137 |
+
|
| 138 |
+
# Problem çözme
|
| 139 |
+
if any(word in query_lower for word in ["problem", "sorun", "çöz", "nasıl"]):
|
| 140 |
+
return "problem_solving"
|
| 141 |
+
|
| 142 |
+
# Karşılaştırma
|
| 143 |
+
if any(word in query_lower for word in ["karşılaştır", "fark", "hangisi", "seç"]):
|
| 144 |
+
return "comparison"
|
| 145 |
+
|
| 146 |
+
# Değerlendirme
|
| 147 |
+
if any(word in query_lower for word in ["değerlendir", "incele", "analiz"]):
|
| 148 |
+
return "evaluation"
|
| 149 |
+
|
| 150 |
+
# Sebep-sonuç
|
| 151 |
+
if any(word in query_lower for word in ["neden", "çünkü", "sebep", "sonuç"]):
|
| 152 |
+
return "cause_effect"
|
| 153 |
+
|
| 154 |
+
# Strateji
|
| 155 |
+
if any(word in query_lower for word in ["strateji", "plan", "yaklaşım"]):
|
| 156 |
+
return "strategy"
|
| 157 |
+
|
| 158 |
+
# Avantaj-dezavantaj
|
| 159 |
+
if any(word in query_lower for word in ["avantaj", "dezavantaj", "artı", "eksi"]):
|
| 160 |
+
return "pros_cons"
|
| 161 |
+
|
| 162 |
+
# Varsayılan
|
| 163 |
+
return "general_reasoning"
|
| 164 |
+
|
| 165 |
+
def _extract_reasoning_steps(self, response: str) -> list:
|
| 166 |
+
"""Yanıttan mantık yürütme adımlarını çıkarır"""
|
| 167 |
+
steps = []
|
| 168 |
+
|
| 169 |
+
# Numaralı adımları bul
|
| 170 |
+
import re
|
| 171 |
+
numbered_steps = re.findall(r'(\d+[\.\)])\s*([^\n]+)', response)
|
| 172 |
+
|
| 173 |
+
for num, step in numbered_steps:
|
| 174 |
+
steps.append({
|
| 175 |
+
"step": num,
|
| 176 |
+
"description": step.strip()
|
| 177 |
+
})
|
| 178 |
+
|
| 179 |
+
# Anahtar kelimelerle adımları bul
|
| 180 |
+
key_phrases = [
|
| 181 |
+
"ilk olarak", "öncelikle", "birincisi",
|
| 182 |
+
"ikincisi", "üçüncüsü", "son olarak",
|
| 183 |
+
"sonuç olarak", "özetle", "bu nedenle"
|
| 184 |
+
]
|
| 185 |
+
|
| 186 |
+
sentences = response.split('.')
|
| 187 |
+
for sentence in sentences:
|
| 188 |
+
sentence = sentence.strip()
|
| 189 |
+
if any(phrase in sentence.lower() for phrase in key_phrases):
|
| 190 |
+
if len(sentence) > 10: # Çok kısa olanları atla
|
| 191 |
+
steps.append({
|
| 192 |
+
"step": "auto",
|
| 193 |
+
"description": sentence
|
| 194 |
+
})
|
| 195 |
+
|
| 196 |
+
return steps[:10] # Maksimum 10 adım
|
requirements.txt
CHANGED
|
@@ -1,10 +1,18 @@
|
|
| 1 |
torch>=2.0.0
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
spaces>=0.19.0
|
|
|
|
|
|
|
| 7 |
numpy>=1.24.0
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
safetensors>=0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
torch>=2.0.0
|
| 2 |
+
transformers==4.41.0
|
| 3 |
+
accelerate>=0.28.0
|
| 4 |
+
tokenizers>=0.19.0
|
| 5 |
+
gradio==4.29.0
|
| 6 |
spaces>=0.19.0
|
| 7 |
+
requests>=2.31.0
|
| 8 |
+
aiohttp>=3.9.0
|
| 9 |
numpy>=1.24.0
|
| 10 |
+
psutil>=5.9.0
|
| 11 |
+
huggingface_hub>=0.20.0
|
| 12 |
+
safetensors>=0.4.0
|
| 13 |
+
peft==0.10.0
|
| 14 |
+
bitsandbytes==0.43.0
|
| 15 |
+
pydantic>=2.6.0
|
| 16 |
+
python-multipart>=0.0.9
|
| 17 |
+
aiofiles>=23.2.0
|
| 18 |
+
jinja2>=3.1.3
|
router/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Router Package
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .intelligent_router import IntelligentRouter
|
| 6 |
+
|
| 7 |
+
__all__ = ['IntelligentRouter']
|
router/intelligent_router.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Intelligent Router Layer
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict, Any, List, Optional
|
| 6 |
+
import asyncio
|
| 7 |
+
import logging
|
| 8 |
+
from dataclasses import dataclass
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
import json
|
| 11 |
+
|
| 12 |
+
logger = logging.getLogger(__name__)
|
| 13 |
+
|
| 14 |
+
@dataclass
|
| 15 |
+
class RoutingDecision:
|
| 16 |
+
"""Routing kararı için veri sınıfı"""
|
| 17 |
+
module_name: str
|
| 18 |
+
confidence: float
|
| 19 |
+
priority: int
|
| 20 |
+
reasoning: str
|
| 21 |
+
estimated_time: float
|
| 22 |
+
|
| 23 |
+
class IntelligentRouter:
|
| 24 |
+
"""Sorguları en uygun modüllere yönlendiren router"""
|
| 25 |
+
|
| 26 |
+
def __init__(self, modules: Dict[str, Any], config: Dict[str, Any]):
|
| 27 |
+
self.modules = modules
|
| 28 |
+
self.config = config
|
| 29 |
+
self.routing_history = []
|
| 30 |
+
self.performance_stats = {}
|
| 31 |
+
|
| 32 |
+
# Routing parametreleri
|
| 33 |
+
self.confidence_threshold = config.get("confidence_threshold", 0.7)
|
| 34 |
+
self.max_concurrent = config.get("max_concurrent_requests", 4)
|
| 35 |
+
self.timeout = config.get("timeout", 30)
|
| 36 |
+
self.fallback_module = config.get("fallback_module", "fast_module")
|
| 37 |
+
|
| 38 |
+
# Performans takibi
|
| 39 |
+
self.total_requests = 0
|
| 40 |
+
self.successful_routings = 0
|
| 41 |
+
self.failed_routings = 0
|
| 42 |
+
|
| 43 |
+
async def route_query(self, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 44 |
+
"""Ana routing fonksiyonu"""
|
| 45 |
+
try:
|
| 46 |
+
start_time = datetime.now()
|
| 47 |
+
|
| 48 |
+
# Routing kararı al
|
| 49 |
+
routing_decisions = await self._analyze_query(query, context)
|
| 50 |
+
|
| 51 |
+
# En iyi modülü seç
|
| 52 |
+
best_module = self._select_best_module(routing_decisions)
|
| 53 |
+
|
| 54 |
+
if not best_module:
|
| 55 |
+
# Fallback modülü kullan
|
| 56 |
+
best_module = RoutingDecision(
|
| 57 |
+
module_name=self.fallback_module,
|
| 58 |
+
confidence=0.5,
|
| 59 |
+
priority=999,
|
| 60 |
+
reasoning="Fallback module used",
|
| 61 |
+
estimated_time=2.0
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
# Modülü çalıştır
|
| 65 |
+
result = await self._execute_module(
|
| 66 |
+
best_module.module_name,
|
| 67 |
+
query,
|
| 68 |
+
context
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
# Performans güncelle
|
| 72 |
+
execution_time = (datetime.now() - start_time).total_seconds()
|
| 73 |
+
self._update_performance_stats(
|
| 74 |
+
best_module.module_name,
|
| 75 |
+
execution_time,
|
| 76 |
+
True
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
# Routing geçmişini güncelle
|
| 80 |
+
self._update_routing_history(query, best_module, result, execution_time)
|
| 81 |
+
|
| 82 |
+
# Sonuç ekle
|
| 83 |
+
result["routing_info"] = {
|
| 84 |
+
"selected_module": best_module.module_name,
|
| 85 |
+
"confidence": best_module.confidence,
|
| 86 |
+
"reasoning": best_module.reasoning,
|
| 87 |
+
"execution_time": execution_time,
|
| 88 |
+
"all_candidates": [
|
| 89 |
+
{
|
| 90 |
+
"module": decision.module_name,
|
| 91 |
+
"confidence": decision.confidence,
|
| 92 |
+
"priority": decision.priority
|
| 93 |
+
}
|
| 94 |
+
for decision in routing_decisions
|
| 95 |
+
]
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
return result
|
| 99 |
+
|
| 100 |
+
except Exception as e:
|
| 101 |
+
logger.error(f"Routing error: {str(e)}")
|
| 102 |
+
self.failed_routings += 1
|
| 103 |
+
|
| 104 |
+
# Hata durumunda fallback
|
| 105 |
+
return await self._execute_fallback(query, context, str(e))
|
| 106 |
+
|
| 107 |
+
async def _analyze_query(self, query: str, context: Dict[str, Any]) -> List[RoutingDecision]:
|
| 108 |
+
"""Sorguyu analiz eder ve tüm modüllerin skorlarını hesaplar"""
|
| 109 |
+
decisions = []
|
| 110 |
+
|
| 111 |
+
# Tüm modülleri paralel olarak test et
|
| 112 |
+
tasks = []
|
| 113 |
+
for module_name, module in self.modules.items():
|
| 114 |
+
if hasattr(module, 'can_handle'):
|
| 115 |
+
task = asyncio.create_task(
|
| 116 |
+
self._evaluate_module(module_name, module, query, context)
|
| 117 |
+
)
|
| 118 |
+
tasks.append(task)
|
| 119 |
+
|
| 120 |
+
# Sonuçları topla
|
| 121 |
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
| 122 |
+
|
| 123 |
+
for result in results:
|
| 124 |
+
if isinstance(result, RoutingDecision):
|
| 125 |
+
decisions.append(result)
|
| 126 |
+
elif isinstance(result, Exception):
|
| 127 |
+
logger.warning(f"Module evaluation error: {str(result)}")
|
| 128 |
+
|
| 129 |
+
# Confidence'a göre sırala
|
| 130 |
+
decisions.sort(key=lambda x: x.confidence, reverse=True)
|
| 131 |
+
|
| 132 |
+
return decisions
|
| 133 |
+
|
| 134 |
+
async def _evaluate_module(self, module_name: str, module: Any, query: str, context: Dict[str, Any]) -> RoutingDecision:
|
| 135 |
+
"""Tek bir modülü değerlendirir"""
|
| 136 |
+
try:
|
| 137 |
+
# Can_handle skorunu al
|
| 138 |
+
confidence = module.can_handle(query, context)
|
| 139 |
+
|
| 140 |
+
# Modül performansını kontrol et
|
| 141 |
+
performance = self.performance_stats.get(module_name, {})
|
| 142 |
+
avg_time = performance.get("avg_execution_time", 2.0)
|
| 143 |
+
success_rate = performance.get("success_rate", 0.8)
|
| 144 |
+
|
| 145 |
+
# Confidence'ı performansa göre ayarla
|
| 146 |
+
adjusted_confidence = confidence * success_rate
|
| 147 |
+
|
| 148 |
+
# Priority'yi config'den al
|
| 149 |
+
priority = module.config.get("priority", 1)
|
| 150 |
+
|
| 151 |
+
# Reasoning oluştur
|
| 152 |
+
reasoning = self._generate_reasoning(
|
| 153 |
+
module_name, confidence, performance, query
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
return RoutingDecision(
|
| 157 |
+
module_name=module_name,
|
| 158 |
+
confidence=adjusted_confidence,
|
| 159 |
+
priority=priority,
|
| 160 |
+
reasoning=reasoning,
|
| 161 |
+
estimated_time=avg_time
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
except Exception as e:
|
| 165 |
+
logger.error(f"Error evaluating module {module_name}: {str(e)}")
|
| 166 |
+
return RoutingDecision(
|
| 167 |
+
module_name=module_name,
|
| 168 |
+
confidence=0.0,
|
| 169 |
+
priority=999,
|
| 170 |
+
reasoning=f"Evaluation error: {str(e)}",
|
| 171 |
+
estimated_time=10.0
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
def _select_best_module(self, decisions: List[RoutingDecision]) -> Optional[RoutingDecision]:
|
| 175 |
+
"""En iyi modülü seçer"""
|
| 176 |
+
if not decisions:
|
| 177 |
+
return None
|
| 178 |
+
|
| 179 |
+
# Confidence threshold'u geçenleri filtrele
|
| 180 |
+
qualified = [d for d in decisions if d.confidence >= self.confidence_threshold]
|
| 181 |
+
|
| 182 |
+
if not qualified:
|
| 183 |
+
# Eğer hiçbiri threshold'u geçmiyorsa en yüksek skorluyu al
|
| 184 |
+
qualified = [decisions[0]]
|
| 185 |
+
|
| 186 |
+
# Priority ve confidence'a göre sırala
|
| 187 |
+
qualified.sort(key=lambda x: (x.priority, -x.confidence))
|
| 188 |
+
|
| 189 |
+
return qualified[0]
|
| 190 |
+
|
| 191 |
+
async def _execute_module(self, module_name: str, query: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
| 192 |
+
"""Seçilen modülü çalıştırır"""
|
| 193 |
+
try:
|
| 194 |
+
module = self.modules.get(module_name)
|
| 195 |
+
if not module:
|
| 196 |
+
raise Exception(f"Module {module_name} not found")
|
| 197 |
+
|
| 198 |
+
# Timeout ile çalıştır
|
| 199 |
+
result = await asyncio.wait_for(
|
| 200 |
+
module.process(query, context),
|
| 201 |
+
timeout=self.timeout
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
self.successful_routings += 1
|
| 205 |
+
return result
|
| 206 |
+
|
| 207 |
+
except asyncio.TimeoutError:
|
| 208 |
+
logger.error(f"Module {module_name} timed out")
|
| 209 |
+
raise Exception(f"Module {module_name} execution timeout")
|
| 210 |
+
except Exception as e:
|
| 211 |
+
logger.error(f"Module {module_name} execution error: {str(e)}")
|
| 212 |
+
raise
|
| 213 |
+
|
| 214 |
+
async def _execute_fallback(self, query: str, context: Dict[str, Any], error: str) -> Dict[str, Any]:
|
| 215 |
+
"""Fallback modülü çalıştırır"""
|
| 216 |
+
try:
|
| 217 |
+
fallback_module = self.modules.get(self.fallback_module)
|
| 218 |
+
if fallback_module:
|
| 219 |
+
result = await fallback_module.process(query, context)
|
| 220 |
+
result["fallback_used"] = True
|
| 221 |
+
result["original_error"] = error
|
| 222 |
+
return result
|
| 223 |
+
else:
|
| 224 |
+
return {
|
| 225 |
+
"error": f"Routing failed and no fallback available: {error}",
|
| 226 |
+
"fallback_used": True
|
| 227 |
+
}
|
| 228 |
+
except Exception as e:
|
| 229 |
+
return {
|
| 230 |
+
"error": f"Both routing and fallback failed: {error}, {str(e)}",
|
| 231 |
+
"fallback_used": True
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
def _update_performance_stats(self, module_name: str, execution_time: float, success: bool):
|
| 235 |
+
"""Performans istatistiklerini günceller"""
|
| 236 |
+
if module_name not in self.performance_stats:
|
| 237 |
+
self.performance_stats[module_name] = {
|
| 238 |
+
"total_requests": 0,
|
| 239 |
+
"successful_requests": 0,
|
| 240 |
+
"total_time": 0,
|
| 241 |
+
"avg_execution_time": 0,
|
| 242 |
+
"success_rate": 0
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
stats = self.performance_stats[module_name]
|
| 246 |
+
stats["total_requests"] += 1
|
| 247 |
+
stats["total_time"] += execution_time
|
| 248 |
+
|
| 249 |
+
if success:
|
| 250 |
+
stats["successful_requests"] += 1
|
| 251 |
+
|
| 252 |
+
# Ortalama süre & başarı oranı
|
| 253 |
+
stats["avg_execution_time"] = stats["total_time"] / max(stats["total_requests"], 1)
|
| 254 |
+
stats["success_rate"] = stats["successful_requests"] / max(stats["total_requests"], 1)
|
| 255 |
+
|
| 256 |
+
self.total_requests += 1
|
| 257 |
+
|
| 258 |
+
def _update_routing_history(self, query: str, decision: RoutingDecision, result: Dict[str, Any], execution_time: float):
|
| 259 |
+
"""Routing geçmişini günceller"""
|
| 260 |
+
entry = {
|
| 261 |
+
"timestamp": datetime.now().isoformat(),
|
| 262 |
+
"query": query[:100], # İlk 100 karakter
|
| 263 |
+
"selected_module": decision.module_name,
|
| 264 |
+
"confidence": decision.confidence,
|
| 265 |
+
"execution_time": execution_time,
|
| 266 |
+
"success": "error" not in result
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
self.routing_history.append(entry)
|
| 270 |
+
|
| 271 |
+
# Geçmişi sınırla (son 1000 entry)
|
| 272 |
+
if len(self.routing_history) > 1000:
|
| 273 |
+
self.routing_history = self.routing_history[-1000:]
|
| 274 |
+
|
| 275 |
+
def _generate_reasoning(self, module_name: str, confidence: float, performance: Dict[str, Any], query: str) -> str:
|
| 276 |
+
"""Routing kararı için açıklama oluşturur"""
|
| 277 |
+
reasons = []
|
| 278 |
+
|
| 279 |
+
if confidence > 0.8:
|
| 280 |
+
reasons.append(f"Yüksek confidence skoru ({confidence:.2f})")
|
| 281 |
+
elif confidence > 0.6:
|
| 282 |
+
reasons.append(f"Orta confidence skoru ({confidence:.2f})")
|
| 283 |
+
else:
|
| 284 |
+
reasons.append(f"Düşük confidence skoru ({confidence:.2f})")
|
| 285 |
+
|
| 286 |
+
if performance:
|
| 287 |
+
success_rate = performance.get("success_rate", 0)
|
| 288 |
+
if success_rate > 0.9:
|
| 289 |
+
reasons.append("Yüksek başarı oranı")
|
| 290 |
+
elif success_rate > 0.7:
|
| 291 |
+
reasons.append("Orta başarı oranı")
|
| 292 |
+
else:
|
| 293 |
+
reasons.append("Düşük başarı oranı")
|
| 294 |
+
|
| 295 |
+
return ", ".join(reasons)
|
| 296 |
+
|
| 297 |
+
def get_stats(self) -> Dict[str, Any]:
|
| 298 |
+
"""Router istatistiklerini döndürür"""
|
| 299 |
+
return {
|
| 300 |
+
"total_requests": self.total_requests,
|
| 301 |
+
"successful_routings": self.successful_routings,
|
| 302 |
+
"failed_routings": self.failed_routings,
|
| 303 |
+
"success_rate": self.successful_routings / max(self.total_requests, 1),
|
| 304 |
+
"module_performance": self.performance_stats,
|
| 305 |
+
"recent_history": self.routing_history[-10:] # Son 10 routing
|
| 306 |
+
}
|
setup.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Kurulum Scripti
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import asyncio
|
| 6 |
+
import logging
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
# Logging ayarları
|
| 12 |
+
logging.basicConfig(
|
| 13 |
+
level=logging.INFO,
|
| 14 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| 15 |
+
)
|
| 16 |
+
logger = logging.getLogger(__name__)
|
| 17 |
+
|
| 18 |
+
class CRANESetup:
|
| 19 |
+
"""CRANE AI kurulum sınıfı"""
|
| 20 |
+
|
| 21 |
+
def __init__(self):
|
| 22 |
+
self.project_root = Path(__file__).parent
|
| 23 |
+
self.required_dirs = [
|
| 24 |
+
"logs",
|
| 25 |
+
"models",
|
| 26 |
+
"cache",
|
| 27 |
+
"data",
|
| 28 |
+
"exports"
|
| 29 |
+
]
|
| 30 |
+
|
| 31 |
+
async def setup_system(self):
|
| 32 |
+
"""Sistemi kurar"""
|
| 33 |
+
try:
|
| 34 |
+
logger.info("🏗️ CRANE AI Kurulumu Başlatılıyor...")
|
| 35 |
+
|
| 36 |
+
# Dizinleri oluştur
|
| 37 |
+
await self._create_directories()
|
| 38 |
+
|
| 39 |
+
# Paketleri kontrol et
|
| 40 |
+
await self._check_packages()
|
| 41 |
+
|
| 42 |
+
# Hugging Face token'ını kontrol et
|
| 43 |
+
await self._check_hf_token()
|
| 44 |
+
|
| 45 |
+
# Modelleri hazırla
|
| 46 |
+
await self._prepare_models()
|
| 47 |
+
|
| 48 |
+
# Test çalıştır
|
| 49 |
+
await self._run_tests()
|
| 50 |
+
|
| 51 |
+
logger.info("✅ CRANE AI Kurulumu Başarıyla Tamamlandı!")
|
| 52 |
+
logger.info("🚀 Sistemi başlatmak için: python main.py")
|
| 53 |
+
|
| 54 |
+
except Exception as e:
|
| 55 |
+
logger.error(f"❌ Kurulum hatası: {str(e)}")
|
| 56 |
+
sys.exit(1)
|
| 57 |
+
|
| 58 |
+
async def _create_directories(self):
|
| 59 |
+
"""Gerekli dizinleri oluşturur"""
|
| 60 |
+
logger.info("📁 Dizinler oluşturuluyor...")
|
| 61 |
+
|
| 62 |
+
for dir_name in self.required_dirs:
|
| 63 |
+
dir_path = self.project_root / dir_name
|
| 64 |
+
dir_path.mkdir(exist_ok=True)
|
| 65 |
+
logger.info(f" ✅ {dir_name}/ oluşturuldu")
|
| 66 |
+
|
| 67 |
+
# __init__.py dosyalarını oluştur
|
| 68 |
+
init_files = [
|
| 69 |
+
"core/__init__.py",
|
| 70 |
+
"router/__init__.py",
|
| 71 |
+
"memory/__init__.py",
|
| 72 |
+
"config/__init__.py"
|
| 73 |
+
]
|
| 74 |
+
|
| 75 |
+
for init_file in init_files:
|
| 76 |
+
init_path = self.project_root / init_file
|
| 77 |
+
init_path.parent.mkdir(exist_ok=True)
|
| 78 |
+
if not init_path.exists():
|
| 79 |
+
init_path.write_text('"""Package initialization"""')
|
| 80 |
+
logger.info(f" ✅ {init_file} oluşturuldu")
|
| 81 |
+
|
| 82 |
+
async def _check_packages(self):
|
| 83 |
+
"""Gerekli paketleri kontrol eder"""
|
| 84 |
+
logger.info("📦 Paketler kontrol ediliyor...")
|
| 85 |
+
|
| 86 |
+
required_packages = [
|
| 87 |
+
"torch",
|
| 88 |
+
"transformers",
|
| 89 |
+
"fastapi",
|
| 90 |
+
"uvicorn",
|
| 91 |
+
"gradio",
|
| 92 |
+
"numpy",
|
| 93 |
+
"requests",
|
| 94 |
+
"psutil"
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
missing_packages = []
|
| 98 |
+
|
| 99 |
+
for package in required_packages:
|
| 100 |
+
try:
|
| 101 |
+
__import__(package)
|
| 102 |
+
logger.info(f" ✅ {package} mevcut")
|
| 103 |
+
except ImportError:
|
| 104 |
+
missing_packages.append(package)
|
| 105 |
+
logger.warning(f" ❌ {package} eksik")
|
| 106 |
+
|
| 107 |
+
if missing_packages:
|
| 108 |
+
logger.error(f"❌ Eksik paketler: {', '.join(missing_packages)}")
|
| 109 |
+
logger.info("💡 Çözüm: pip install -r requirements.txt")
|
| 110 |
+
raise Exception("Eksik paketler var")
|
| 111 |
+
|
| 112 |
+
async def _check_hf_token(self):
|
| 113 |
+
"""Hugging Face token'ını kontrol eder"""
|
| 114 |
+
logger.info("🔑 Hugging Face token kontrol ediliyor...")
|
| 115 |
+
|
| 116 |
+
from config.settings import HF_TOKEN
|
| 117 |
+
|
| 118 |
+
if not HF_TOKEN or HF_TOKEN == "YOUR_TOKEN_HERE":
|
| 119 |
+
logger.error("❌ Hugging Face token bulunamadı")
|
| 120 |
+
logger.info("💡 config/settings.py dosyasında HF_TOKEN'ı ayarlayın")
|
| 121 |
+
raise Exception("Hugging Face token gerekli")
|
| 122 |
+
|
| 123 |
+
# Token'ın geçerli olup olmadığını kontrol et
|
| 124 |
+
try:
|
| 125 |
+
from huggingface_hub import HfApi
|
| 126 |
+
api = HfApi()
|
| 127 |
+
user_info = api.whoami(token=HF_TOKEN)
|
| 128 |
+
logger.info(f" ✅ Token geçerli: {user_info.get('name', 'Unknown')}")
|
| 129 |
+
except Exception as e:
|
| 130 |
+
logger.error(f"❌ Token geçersiz: {str(e)}")
|
| 131 |
+
raise Exception("Hugging Face token geçersiz")
|
| 132 |
+
|
| 133 |
+
async def _prepare_models(self):
|
| 134 |
+
"""Modelleri hazırlar"""
|
| 135 |
+
logger.info("🤖 Modeller hazırlanıyor...")
|
| 136 |
+
|
| 137 |
+
from config.settings import MODELS, DEVICE
|
| 138 |
+
|
| 139 |
+
# Cihaz bilgisini göster
|
| 140 |
+
logger.info(f" 🖥️ Cihaz: {DEVICE}")
|
| 141 |
+
|
| 142 |
+
# Model bilgilerini göster
|
| 143 |
+
for model_name, model_config in MODELS.items():
|
| 144 |
+
model_id = model_config["model_id"]
|
| 145 |
+
logger.info(f" 📋 {model_name}: {model_id}")
|
| 146 |
+
|
| 147 |
+
# Model cache'ini kontrol et
|
| 148 |
+
cache_dir = self.project_root / "cache" / model_name
|
| 149 |
+
cache_dir.mkdir(exist_ok=True)
|
| 150 |
+
|
| 151 |
+
logger.info(" ✅ Modeller hazırlandı")
|
| 152 |
+
|
| 153 |
+
async def _run_tests(self):
|
| 154 |
+
"""Basit testler çalıştırır"""
|
| 155 |
+
logger.info("🧪 Testler çalıştırılıyor...")
|
| 156 |
+
|
| 157 |
+
try:
|
| 158 |
+
# Router testi
|
| 159 |
+
from router.intelligent_router import IntelligentRouter
|
| 160 |
+
logger.info(" ✅ Router importu başarılı")
|
| 161 |
+
|
| 162 |
+
# Modül testleri
|
| 163 |
+
from modules import CodeModule, ChatModule, ReasonModule, FastModule
|
| 164 |
+
logger.info(" ✅ Modül importları başarılı")
|
| 165 |
+
|
| 166 |
+
# Memory testi
|
| 167 |
+
from memory.local_memory import LocalMemoryManager
|
| 168 |
+
logger.info(" ✅ Memory Manager importu başarılı")
|
| 169 |
+
|
| 170 |
+
# Token layer testi
|
| 171 |
+
from core.token_capsule import TokenCapsuleLayer
|
| 172 |
+
logger.info(" ✅ Token Capsule Layer importu başarılı")
|
| 173 |
+
|
| 174 |
+
logger.info(" ✅ Tüm testler başarılı")
|
| 175 |
+
|
| 176 |
+
except Exception as e:
|
| 177 |
+
logger.error(f"❌ Test hatası: {str(e)}")
|
| 178 |
+
raise Exception("Sistem testleri başarısız")
|
| 179 |
+
|
| 180 |
+
def main():
|
| 181 |
+
"""Ana kurulum fonksiyonu"""
|
| 182 |
+
setup = CRANESetup()
|
| 183 |
+
asyncio.run(setup.setup_system())
|
| 184 |
+
|
| 185 |
+
if __name__ == "__main__":
|
| 186 |
+
main()
|
tools/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - External Tools Package
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .weather_tool import WeatherTool
|
| 6 |
+
|
| 7 |
+
__all__ = ['WeatherTool']
|
tools/weather_tool.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
CRANE AI - Weather Tool
|
| 3 |
+
Gerçek zamanlı hava durumu verisi için tool
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import asyncio
|
| 7 |
+
import json
|
| 8 |
+
from typing import Dict, Any, Optional
|
| 9 |
+
import logging
|
| 10 |
+
|
| 11 |
+
try:
|
| 12 |
+
import aiohttp
|
| 13 |
+
AIOHTTP_AVAILABLE = True
|
| 14 |
+
except ImportError:
|
| 15 |
+
import requests
|
| 16 |
+
AIOHTTP_AVAILABLE = False
|
| 17 |
+
|
| 18 |
+
logger = logging.getLogger(__name__)
|
| 19 |
+
|
| 20 |
+
class WeatherTool:
|
| 21 |
+
"""Hava durumu sorguları için external tool"""
|
| 22 |
+
|
| 23 |
+
def __init__(self):
|
| 24 |
+
# Ücretsiz OpenWeatherMap API kullanabiliriz
|
| 25 |
+
self.base_url = "http://api.openweathermap.org/data/2.5/weather"
|
| 26 |
+
self.api_key = None # API key gerekirse eklenebilir
|
| 27 |
+
|
| 28 |
+
# Alternatif olarak wttr.in kullanabiliriz (ücretsiz)
|
| 29 |
+
self.wttr_url = "http://wttr.in/{city}?format=j1"
|
| 30 |
+
|
| 31 |
+
def can_handle(self, query: str) -> bool:
|
| 32 |
+
"""Bu tool'un handle edebileceği sorguları tespit eder"""
|
| 33 |
+
weather_keywords = [
|
| 34 |
+
"hava", "weather", "sıcaklık", "temperature", "yağmur", "rain",
|
| 35 |
+
"kar", "snow", "rüzgar", "wind", "nem", "humidity", "güneş", "sun",
|
| 36 |
+
"bulut", "cloud", "fırtına", "storm", "bugün", "today", "yarın", "tomorrow"
|
| 37 |
+
]
|
| 38 |
+
|
| 39 |
+
query_lower = query.lower()
|
| 40 |
+
return any(keyword in query_lower for keyword in weather_keywords)
|
| 41 |
+
|
| 42 |
+
async def get_weather(self, city: str = "Istanbul") -> Dict[str, Any]:
|
| 43 |
+
"""Belirtilen şehir için hava durumu bilgisi alır"""
|
| 44 |
+
try:
|
| 45 |
+
# wttr.in API kullan (ücretsiz ve API key gerektirmez)
|
| 46 |
+
url = f"http://wttr.in/{city}?format=j1"
|
| 47 |
+
|
| 48 |
+
if AIOHTTP_AVAILABLE:
|
| 49 |
+
# Async aiohttp kullan
|
| 50 |
+
async with aiohttp.ClientSession() as session:
|
| 51 |
+
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
|
| 52 |
+
if response.status == 200:
|
| 53 |
+
data = await response.json()
|
| 54 |
+
else:
|
| 55 |
+
return {
|
| 56 |
+
"error": f"API response error: {response.status}",
|
| 57 |
+
"status": "error"
|
| 58 |
+
}
|
| 59 |
+
else:
|
| 60 |
+
# Fallback to sync requests
|
| 61 |
+
import requests
|
| 62 |
+
response = requests.get(url, timeout=10)
|
| 63 |
+
if response.status_code == 200:
|
| 64 |
+
data = response.json()
|
| 65 |
+
else:
|
| 66 |
+
return {
|
| 67 |
+
"error": f"API response error: {response.status_code}",
|
| 68 |
+
"status": "error"
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
# Veriyi parse et
|
| 72 |
+
current = data.get("current_condition", [{}])[0]
|
| 73 |
+
weather_desc = current.get("weatherDesc", [{}])[0].get("value", "Bilinmiyor")
|
| 74 |
+
temp_c = current.get("temp_C", "N/A")
|
| 75 |
+
humidity = current.get("humidity", "N/A")
|
| 76 |
+
wind_speed = current.get("windspeedKmph", "N/A")
|
| 77 |
+
|
| 78 |
+
return {
|
| 79 |
+
"city": city,
|
| 80 |
+
"temperature": f"{temp_c}°C",
|
| 81 |
+
"description": weather_desc,
|
| 82 |
+
"humidity": f"{humidity}%",
|
| 83 |
+
"wind_speed": f"{wind_speed} km/h",
|
| 84 |
+
"status": "success"
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
except Exception as e:
|
| 88 |
+
logger.error(f"Weather API error: {str(e)}")
|
| 89 |
+
return {
|
| 90 |
+
"error": str(e),
|
| 91 |
+
"status": "error"
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
def extract_city(self, query: str) -> str:
|
| 95 |
+
"""Sorgudan şehir adını çıkarır"""
|
| 96 |
+
# Türk şehirleri
|
| 97 |
+
turkish_cities = [
|
| 98 |
+
"istanbul", "ankara", "izmir", "bursa", "antalya", "adana",
|
| 99 |
+
"konya", "gaziantep", "mersin", "diyarbakır", "kayseri", "eskişehir"
|
| 100 |
+
]
|
| 101 |
+
|
| 102 |
+
query_lower = query.lower()
|
| 103 |
+
|
| 104 |
+
# Şehir adı geçiyorsa onu al
|
| 105 |
+
for city in turkish_cities:
|
| 106 |
+
if city in query_lower:
|
| 107 |
+
return city.title()
|
| 108 |
+
|
| 109 |
+
# Şehir belirtilmemişse İstanbul default
|
| 110 |
+
return "Istanbul"
|
| 111 |
+
|
| 112 |
+
async def process_weather_query(self, query: str) -> str:
|
| 113 |
+
"""Hava durumu sorgusunu işler ve yanıt oluşturur"""
|
| 114 |
+
try:
|
| 115 |
+
# Şehri tespit et
|
| 116 |
+
city = self.extract_city(query)
|
| 117 |
+
|
| 118 |
+
# Hava durumu bilgisini al
|
| 119 |
+
weather_data = await self.get_weather(city)
|
| 120 |
+
|
| 121 |
+
if weather_data.get("status") == "success":
|
| 122 |
+
return f"""🌤️ **{city} Hava Durumu:**
|
| 123 |
+
|
| 124 |
+
🌡️ **Sıcaklık:** {weather_data['temperature']}
|
| 125 |
+
☁️ **Durum:** {weather_data['description']}
|
| 126 |
+
💧 **Nem:** {weather_data['humidity']}
|
| 127 |
+
💨 **Rüzgar:** {weather_data['wind_speed']}
|
| 128 |
+
|
| 129 |
+
*Güncel bilgi - API üzerinden alındı*"""
|
| 130 |
+
else:
|
| 131 |
+
return f"❌ Hava durumu bilgisi alınamadı: {weather_data.get('error', 'Bilinmeyen hata')}"
|
| 132 |
+
|
| 133 |
+
except Exception as e:
|
| 134 |
+
logger.error(f"Weather query processing error: {str(e)}")
|
| 135 |
+
return f"❌ Hava durumu servisi şu anda kullanılamıyor: {str(e)}"
|
training/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
training/fine_tune.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Fine-tune CRANE AI modelleri (LoRA/QLoRA).
|
| 2 |
+
|
| 3 |
+
Kullanım:
|
| 4 |
+
python training/fine_tune.py --module code_module --data data/code_train.jsonl --output adapters/code_module
|
| 5 |
+
|
| 6 |
+
Varsayılan hiper-parametreler configte yer alır; CLI arg'ları ile override edilebilir.
|
| 7 |
+
"""
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import argparse
|
| 11 |
+
import os
|
| 12 |
+
import json
|
| 13 |
+
import logging
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
from datasets import load_dataset
|
| 18 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 19 |
+
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
|
| 20 |
+
from trl import SFTTrainer
|
| 21 |
+
|
| 22 |
+
MODEL_MAP = {
|
| 23 |
+
"code_module": "deepseek-ai/deepseek-coder-1.3b-instruct",
|
| 24 |
+
"chat_module": "Qwen/Qwen2.5-1.5B-Instruct",
|
| 25 |
+
"reason_module": "microsoft/Phi-3-mini-4k-instruct",
|
| 26 |
+
"fast_module": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
| 30 |
+
log = logging.getLogger(__name__)
|
| 31 |
+
|
| 32 |
+
def parse_args():
|
| 33 |
+
p = argparse.ArgumentParser(description="CRANE AI Fine-Tuner")
|
| 34 |
+
p.add_argument("--module", choices=list(MODEL_MAP.keys()))
|
| 35 |
+
p.add_argument("--data", required=True, help="JSONL veya HuggingFace dataset yolu")
|
| 36 |
+
p.add_argument("--output", default="adapters", help="Çıktı klasörü (LoRA adaptörü)")
|
| 37 |
+
p.add_argument("--epochs", type=int, default=3)
|
| 38 |
+
p.add_argument("--lr", type=float, default=2e-4)
|
| 39 |
+
p.add_argument("--batch", type=int, default=16)
|
| 40 |
+
p.add_argument("--r", type=int, default=16)
|
| 41 |
+
p.add_argument("--alpha", type=int, default=32)
|
| 42 |
+
p.add_argument("--bits4", action="store_true", help="QLoRA (4-bit) kullan")
|
| 43 |
+
return p.parse_args()
|
| 44 |
+
|
| 45 |
+
def main():
|
| 46 |
+
args = parse_args()
|
| 47 |
+
|
| 48 |
+
model_id = MODEL_MAP[args.module]
|
| 49 |
+
log.info(f"Model: {model_id}")
|
| 50 |
+
|
| 51 |
+
# Dataset
|
| 52 |
+
if os.path.isfile(args.data):
|
| 53 |
+
ds = load_dataset("json", data_files=args.data)["train"]
|
| 54 |
+
else:
|
| 55 |
+
ds = load_dataset(args.data)["train"]
|
| 56 |
+
|
| 57 |
+
tok = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
|
| 58 |
+
tok.pad_token = tok.eos_token if tok.pad_token is None else tok.pad_token
|
| 59 |
+
|
| 60 |
+
if args.bits4:
|
| 61 |
+
model = AutoModelForCausalLM.from_pretrained(model_id, load_in_4bit=True, device_map="auto")
|
| 62 |
+
model = prepare_model_for_kbit_training(model)
|
| 63 |
+
else:
|
| 64 |
+
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16, device_map="auto")
|
| 65 |
+
|
| 66 |
+
peft_cfg = LoraConfig(
|
| 67 |
+
r=args.r,
|
| 68 |
+
lora_alpha=args.alpha,
|
| 69 |
+
lora_dropout=0.05,
|
| 70 |
+
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
|
| 71 |
+
bias="none",
|
| 72 |
+
task_type="CAUSAL_LM",
|
| 73 |
+
)
|
| 74 |
+
model = get_peft_model(model, peft_cfg)
|
| 75 |
+
|
| 76 |
+
trainer = SFTTrainer(
|
| 77 |
+
model=model,
|
| 78 |
+
tokenizer=tok,
|
| 79 |
+
train_dataset=ds,
|
| 80 |
+
max_seq_length=4096,
|
| 81 |
+
gradient_accumulation_steps=max(1, 32 // args.batch),
|
| 82 |
+
learning_rate=args.lr,
|
| 83 |
+
num_train_epochs=args.epochs,
|
| 84 |
+
per_device_train_batch_size=args.batch,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
trainer.train()
|
| 88 |
+
|
| 89 |
+
out_dir = Path(args.output) / args.module
|
| 90 |
+
out_dir.mkdir(parents=True, exist_ok=True)
|
| 91 |
+
model.save_pretrained(out_dir)
|
| 92 |
+
tok.save_pretrained(out_dir)
|
| 93 |
+
log.info(f"LoRA adaptörü kaydedildi → {out_dir}")
|
| 94 |
+
|
| 95 |
+
if __name__ == "__main__":
|
| 96 |
+
main()
|