File size: 9,124 Bytes
7c634d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666c090
7c634d8
 
666c090
7c634d8
 
666c090
7c634d8
666c090
 
7c634d8
666c090
 
 
7c634d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666c090
7c634d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2d4c3e5
7c634d8
 
2d4c3e5
7c634d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2d4c3e5
7c634d8
 
 
2d4c3e5
7c634d8
2d4c3e5
7c634d8
 
 
 
 
 
bfb910e
7c634d8
2d4c3e5
7c634d8
2d4c3e5
 
7c634d8
2d4c3e5
 
bfb910e
7c634d8
2d4c3e5
 
bfb910e
2d4c3e5
7c634d8
 
 
bfb910e
 
 
7c634d8
 
 
af5afb9
bfb910e
 
7c634d8
 
bfb910e
 
7c634d8
 
bfb910e
 
2d4c3e5
bfb910e
7c634d8
 
860b2f2
7c634d8
bfb910e
 
 
 
 
 
 
 
 
 
 
 
 
860b2f2
2d4c3e5
7c634d8
860b2f2
 
7c634d8
 
 
 
 
55fa371
7c634d8
 
2d4c3e5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import gradio as gr
import spaces
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
import requests
import json
import re
from datetime import datetime, timedelta

# ==========================================
# 1. API Fonksiyonları (Tools)
# ==========================================
def get_earthquakes(start_date: str, end_date: str, min_magnitude: float):
    """
    Belirli tarihler arasında ve minimum büyüklükte olan depremleri getirir.
    """
    try:
        url = f"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime={start_date}&endtime={end_date}&minmagnitude={min_magnitude}"
        res = requests.get(url, timeout=10)
        data = res.json()
        count = data.get('metadata', {}).get('count', 0)
        features = data.get('features', [])[:5] # limit to 5 to avoid huge responses
        results = []
        for f in features:
            props = f.get('properties', {})
            results.append({
                "place": props.get('place'),
                "magnitude": props.get('mag'),
                "time": props.get('time')
            })
        return {"count": count, "top_earthquakes": results}
    except Exception as e:
        return {"error": str(e)}

def get_wildfires(limit: int = 5):
    """
    Dünya genelindeki son aktif orman yangınlarını (NASA EONET üzerinden) getirir.
    """
    try:
        url = "https://eonet.gsfc.nasa.gov/api/v3/events?category=wildfires&status=open"
        res = requests.get(url, timeout=10)
        data = res.json()
        events = data.get('events', [])[:limit]
        results = []
        for e in events:
            geom = e.get('geometry', [{}])[0]
            results.append({
                "title": e.get('title'),
                "date": geom.get('date'),
                "coordinates": geom.get('coordinates')
            })
        return {"count": len(results), "wildfires": results}
    except Exception as e:
        return {"error": str(e)}

available_functions = {
    "get_earthquakes": get_earthquakes,
    "get_wildfires": get_wildfires
}

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_earthquakes",
            "description": "Belirli tarihler arasında meydana gelen depremleri getirir (USGS API).",
            "parameters": {
                "type": "object",
                "properties": {
                    "start_date": {"type": "string", "description": "Başlangıç tarihi (YYYY-MM-DD)"},
                    "end_date": {"type": "string", "description": "Bitiş tarihi (YYYY-MM-DD)"},
                    "min_magnitude": {"type": "number", "description": "Minimum deprem büyüklüğü (örn: 5.0)"}
                },
                "required": ["start_date", "end_date", "min_magnitude"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_wildfires",
            "description": "Güncel aktif orman yangınlarını NASA EONET üzerinden getirir.",
            "parameters": {
                "type": "object",
                "properties": {
                    "limit": {"type": "integer", "description": "Getirilecek maksimum yangın sayısı"}
                },
                "required": ["limit"]
            }
        }
    }
]

# ==========================================
# 2. Model Yükleme (ZeroGPU Uyumluluğu)
# ==========================================
model_id = "Qwen/Qwen2.5-7B-Instruct"

print(f"Model yükleniyor: {model_id}...")
try:
    tokenizer = AutoTokenizer.from_pretrained(model_id)
    model = AutoModelForCausalLM.from_pretrained(
        model_id,
        torch_dtype=torch.bfloat16,
        device_map="auto"
    )
    print("Model başarıyla yüklendi!")
except Exception as e:
    print(f"Model yüklenirken hata oluştu: {e}")
    model = None
    tokenizer = None

# ==========================================
# 3. Agentic Loop & Tool Execution
# ==========================================
@spaces.GPU(duration=60)
def generate_step(messages):
    """
    Modeli bir adım çalıştırır ve üretilen metni döndürür.
    ZeroGPU ortamında GPU'yu kullanarak çalışır.
    """
    text = tokenizer.apply_chat_template(messages, tools=tools, tokenize=False, add_generation_prompt=True)
    inputs = tokenizer(text, return_tensors="pt").to(model.device)

    outputs = model.generate(**inputs, max_new_tokens=1024, temperature=0.3)
    response_text = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=False)

    # Qwen2.5 tool call formatında bitiş token'larını temizleme
    response_text = response_text.replace("<|im_end|>", "")
    return response_text

def parse_tool_calls(text):
    """
    Qwen2.5 formatındaki tool call etiketlerini parse eder.
    <tool_call>
    {"name": "...", "arguments": {...}}
    </tool_call>
    """
    pattern = r"<tool_call>\s*(.*?)\s*</tool_call>"
    matches = re.findall(pattern, text, re.DOTALL)
    calls = []
    for match in matches:
        try:
            calls.append(json.loads(match))
        except Exception as e:
            print(f"Tool parse hatası: {e} - Veri: {match}")
    return calls

def chat_interface(user_input, history):
    if not model:
        yield "Model yüklenemediği için yanıt verilemiyor."
        return

    # Sistem mesajı ve geçmişi hazırlama
    messages = [
        {"role": "system", "content": "Sen yetenekli bir afet takip asistanısın. Kullanıcı sorularına cevap verirken gerektiğinde 'get_earthquakes' ve 'get_wildfires' araçlarını kullan. Araçların sonuçlarını inceleyerek doğal dilde cevap ver. Bugünkü tarih: " + datetime.now().strftime("%Y-%m-%d")}
    ]

    for user_msg, asst_msg in history:
        messages.append({"role": "user", "content": user_msg})
        messages.append({"role": "assistant", "content": asst_msg})

    messages.append({"role": "user", "content": user_input})

    final_output = ""
    for _ in range(5):
        try:
            response_text = generate_step(messages)
            messages.append({"role": "assistant", "content": response_text})
        except Exception as e:
            yield final_output + f"\n[Hata]: {str(e)}"
            break

        tool_calls = parse_tool_calls(response_text)
        reasoning_text = re.sub(r"<tool_call>.*?</tool_call>", "", response_text, flags=re.DOTALL).strip()

        if not tool_calls:
            if reasoning_text:
                final_output += f"\n\n{reasoning_text}"
            yield final_output.strip()
            break

        if reasoning_text:
            final_output += f"\n\n🤔 *Düşünce: {reasoning_text}*"

        for call in tool_calls:
            func_name = call.get("name")
            args = call.get("arguments", {})
            
            final_output += f"\n\n🛠️ **Araç Kullanılıyor:** `{func_name}` \n📥 **Girdi:** `{args}`"
            
            if func_name in available_functions:
                try:
                    result = available_functions[func_name](**args)
                    res_json = json.dumps(result, ensure_ascii=False)
                    final_output += f"\n✅ **Çıktı:** `{res_json[:300]}...`"
                    messages.append({"role": "tool", "name": func_name, "content": res_json})
                except Exception as e:
                    error_msg = {"error": str(e)}
                    final_output += f"\n⚠️ **Hata:** `{str(e)}`"
                    messages.append({"role": "tool", "name": func_name, "content": json.dumps(error_msg, ensure_ascii=False)})
            else:
                error_msg = {"error": f"Bilinmeyen fonksiyon: {func_name}"}
                final_output += f"\n⚠️ **Hata:** Bilinmeyen araç"
                messages.append({"role": "tool", "name": func_name, "content": json.dumps(error_msg, ensure_ascii=False)})

        yield final_output + "\n\n*(Araç sonuçları işleniyor...)*"

# ==========================================
# 4. Gradio UI
# ==========================================
with gr.Blocks() as demo:
    gr.Markdown("# 🌍 Afet Takip Asistanı")
    
    chatbot = gr.Chatbot(height=500)
    msg = gr.Textbox(label="Mesajınız", placeholder="Örn: Aktif yangınları listele")
    
    gr.Examples(
        examples=[
            "2026-07-25 ile 2026-07-30 tarihleri arasındaki 5.5 üzeri depremleri listele.",
            "Şu anki aktif büyük orman yangınları hangileri? 3 tanesini getir.",
            "Son 7 günde (2026-07-23 ile 2026-07-30) 6.0'dan büyük deprem oldu mu? Ayrıca şu an aktif orman yangını var mı?"
        ],
        inputs=msg
    )

    def respond(user_message, chat_history):
        if not user_message.strip():
            return chat_history, ""
        chat_history.append((user_message, ""))
        for bot_message in chat_interface(user_message, chat_history[:-1]):
            chat_history[-1] = (user_message, bot_message)
            yield chat_history, ""

    msg.submit(respond, [msg, chatbot], [chatbot, msg], api_name=False)

if __name__ == "__main__":
    demo.launch()