File size: 14,436 Bytes
12efb2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# app.py (QUANTUM FINAL: Қарапайым, Әдемі & Нақты)

import gradio as gr
import requests
import pandas as pd
from openmeteo_requests import Client
import openmeteo_requests
from PIL import Image
import torch
import timm 
from torchvision import transforms
from datetime import datetime
import pytz 
import numpy as np 

# --- 0. Қазақша Классификация Сөздігі (Өсімдіктерге басымдықпен) ---
# Бұл ImageNet-ке негізделген, бірақ қазақшаға бейімделген
KZ_LABELS = {
    0: "Ауылшаруашылық техникасы", 
    1: "Мал (Жылқы/Сиыр)", 
    2: "Ит / Қасқыр", 
    3: "Құс", 
    4: "Қоқыс (Пластик/Қағаз)", 
    5: "Шыны / Металл қалдықтары", 
    6: "Өсімдік Ауруы (Шіріген)", # Өсімдік ауруларына нақтырақ
    7: "Өсімдік (Дені сау)",
    10: "Көлік / Жүк машинасы", 
    12: "Қой/Ешкі", 
    16: "Дәнді дақылдар", 
    20: "Ағаш / Орман", 
    25: "Шөп / Жайылым",
}

# --- 1. Тұрақты Параметрлер & Геодеректер ---
BAYAN_ULGII_LAT = 48.97
BAYAN_ULGII_LON = 89.97
DEVICE = "cpu" 
TIMEZONE = "Asia/Ulaanbaatar" 

# --- 2. Ауа Райы Кодтарының Қазақша Аудармасы ---
def translate_weather_code(code):
    if code in [0]: return "Күн ашық ☀️"
    if code in [1, 2]: return "Аздаған бұлт 🌤️"
    if code in [3]: return "Бұлтты ☁️"
    if code in [45, 48]: return "Тұман 🌫️"
    if code in [51, 53, 55, 61, 63]: return "Аздаған жаңбыр 🌧️"
    if code in [65, 80, 81, 82]: return "Нөсер/Қатты жаңбыр ⛈️"
    if code in [56, 57, 66, 67, 71, 73]: return "Қар/Аязды жаңбыр 🌨️"
    if code in [75, 77, 85, 86]: return "Қалың қар ❄️"
    if code in [95, 96, 99]: return "Найзағай ⚡"
    return "Белгісіз"

# --- 3. Модельдерді Жүктеу (Тұрақтылықты күшейту) ---
TRASH_AVAILABLE = False
ANIMAL_PLANT_AVAILABLE = False
try:
    # Ең жеңіл ML моделі (Мал/Өсімдік)
    animal_plant_model = timm.create_model('shufflenet_v2_x0_5', pretrained=True).to(DEVICE).eval()
    # Жақсы дәлдікті ML моделі (Қоқыс)
    trash_model = timm.create_model('efficientnet_b0', pretrained=True).to(DEVICE).eval()
    
    transform_common = transforms.Compose([
        transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ])
    
    ANIMAL_PLANT_AVAILABLE = True
    TRASH_AVAILABLE = True
    print("✅ Барлық жеңіл модельдер сәтті жүктелді.")
except Exception as e:
    print(f"❌ Модельдерді жүктеу кезінде қате: {e}. ML функциялары іске қосылмайды.")


# --- 4. Ауа Райы Логикасы ---

def get_weather_data():
    lat, lon = BAYAN_ULGII_LAT, BAYAN_ULGII_LON
    try:
        openmeteo = Client(requests)
        url = "https://api.open-meteo.com/v1/forecast"
        params = {
            "latitude": lat, "longitude": lon,
            "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "precipitation_sum", "wind_speed_10m_max"],
            "timezone": "auto", "forecast_days": 7
        }
        responses = openmeteo.weather_api(url, params=params)
        response = responses[0]
        daily = response.Daily()
        
        time_stamps = daily.Time()
        time_series = pd.to_datetime(time_stamps, unit="s").tz_localize(pytz.utc).tz_convert(TIMEZONE)
        
        # Деректерді алу және дөңгелектеу
        temp_max = daily.Variables(1).ValuesAsNumpy()
        temp_min = daily.Variables(2).ValuesAsNumpy()
        precip_sum = daily.Variables(3).ValuesAsNumpy()
        wind_speed = daily.Variables(4).ValuesAsNumpy()
        weather_code = daily.Variables(0).ValuesAsNumpy() 
        
        daily_data = {
            "Күн": time_series.strftime('%d.%m'), 
            "Сипаттама": [translate_weather_code(code) for code in weather_code],
            "Макс. Темп (°C)": temp_max.round(1),
            "Мин. Темп (°C)": temp_min.round(1),
            "Жауын-шашын (мм)": precip_sum.round(1),
            "Жел Жылдамдығы (км/сағ)": wind_speed.round(1)
        }
        df = pd.DataFrame(daily_data)
        
        # 4.1.1. ⚠️ Ерекше Экологиялық Ескертулер (Бас интерфейске шығатын)
        warnings = []
        if np.any(wind_speed > 45): warnings.append("🚨 **ҚАТТЫ ЖЕЛ:** Жел 45 км/сағ-тан асады. Мал бағуға қауіпті.")
        if np.any(temp_min < -20): warnings.append("❄️ **ӨТЕ ҚАТТЫ АЯЗ:** -20°C төмен. Жылытуды күшейтіңіз.")
        if np.any(np.isin(weather_code, [75, 85, 86])): warnings.append("🌨️ **ЫҚТИМАЛ ҚАЛЫҢ ҚАР:** Қалың қар күтілуде. Жолдарға назар аударыңыз.")
        if np.any(precip_sum > 10): warnings.append("💧 **СУ ТАСҚЫНЫ ҚАУПІ:** Жауын-шашын күшті. Су басу қаупі бар.")
             
        warning_message = "✅ Қауіпсіздік ескертулері жоқ. Ауа райы тұрақты." if not warnings else "⚠️ **МАҢЫЗДЫ ҚАУІПСІЗДІК ЕСКЕРТУЛЕРІ:**\n- " + "\n- ".join(warnings)

        # 4.1.2. 🧠 Қазақша Болжам/Талдау 
        analysis = []
        if np.any(temp_max > 15): analysis.append("Алдағы күндері **күн жылы** болады.")
        if np.any(np.isin(weather_code, [0, 1])): analysis.append("Көп күндері **күн ашық** болады.")
        
        analysis_text = "✨ **Апталық Болжам Талдауы:**\n- " + ("\n- ".join(analysis) if analysis else "Жалпы алғанда ауа райы айтарлықтай өзгеріссіз.")
            
        return warning_message, df, analysis_text
    
    except Exception as e:
        return f"❌ Ауа райы деректерін алу қатесі: {e}", pd.DataFrame(), "Талдау қолжетімсіз."

# 4.2. ML Жіктеу (Өзгеріссіз)
def classify_image(image, task):
    if (task in ["animal", "plant"] and not ANIMAL_PLANT_AVAILABLE) or (task == "trash" and not TRASH_AVAILABLE):
        return "❌ Суретті жіктеу моделі іске қосылмады. Серверді қайта жүктеңіз немесе 'requirements' тексеріңіз."

    try:
        model, model_name = (
            (trash_model, "EfficientNet B0 (5.3M)") if task == "trash"
            else (animal_plant_model, "ShuffleNet V2 (1.3M)")
        )
        
        input_tensor = transform_common(image).unsqueeze(0).to(DEVICE)
        
        with torch.no_grad():
            outputs = model(input_tensor)
            _, predicted = torch.max(outputs.data, 1)
            predicted_index = predicted.item()
            
        predicted_kz_label = KZ_LABELS.get(predicted_index, f"Белгісіз Код #{predicted_index}")
            
        if task == "trash": type_kz = "Қоқыс түрі"
        elif task == "animal": type_kz = "Мал Ауруы"
        else: type_kz = "Өсімдік Түрі / Ауруы"

        kz_response = f"**{type_kz}** болжамды нәтиже:\nБолжам: **{predicted_kz_label}**.\n\n"
        kz_response += f"✅ **Қолданылған Жеңіл Модель:** {model_name}.\n"
        kz_response += "❗ **Ескерту:** Бұл модельдер жалпы деректерде оқытылған. Дәл диагноз үшін **жергілікті маманға** жүгініңіз."
        return kz_response

    except Exception as e:
        return f"❌ Суретті жіктеу қатесі: {e}"

# 4.3. Уақытты жаңарту (Әр минут сайын)
def get_current_time():
    try:
        tz = pytz.timezone(TIMEZONE)
        now = datetime.now(tz)
        return now.strftime("⌚ %H:%M:%S (%d.%m.%Y)")
    except Exception:
        return "⌚ Уақыт дерегі қолжетімсіз"


# Қосымша іске қосылғанда деректерді алдын ала жүктеу
initial_warning, initial_df, initial_analysis = get_weather_data()


# --- 5. Ғажап Интерфейс (Gradio) ---

# Әдемі, қарапайым және түсінікті тақырыпты таңдаймыз
with gr.Blocks(title="Quantum FINAL: Баян-Өлгий AI", theme=gr.themes.Soft()) as demo:
    
    current_time_display = gr.Textbox(label=f"Баян-Өлгий Уақыты", value=get_current_time(), interactive=False, container=False)

    # 5.1. Басты HTML блок (Қарапайым және таза дизайн)
    header_html = gr.HTML(
        f"""
        <div style="text-align: center; padding: 10px; background-color: #4CAF50; color: white; border-radius: 10px;">
            <h1 style="margin: 0;">⚛️ QUANTUM FINAL: Баян-Өлгий AI Кеңесшісі ⛰️</h1>
        </div>
        <div style="margin: 15px 0; padding: 10px; border: 2px solid {'#FF5733' if 'ҚАУІПСІЗДІК' in initial_warning else '#33FF57'}; border-radius: 5px; background-color: #f0f0f0;">
             <h3 style="margin: 0; color: #333;">{initial_warning.split(':')[0]}</h3>
             <p style="white-space: pre-wrap; margin: 5px 0 0 0; color: #555;">{initial_warning.split(':')[1] if len(initial_warning.split(':')) > 1 else initial_warning}</p>
        </div>
        """
    )
    
    with gr.Tabs():
        # --- 1. Ауа Райы & Карта ---
        with gr.TabItem("🌤️ Ауа Райы, Талдау & Карта"):
            gr.Markdown(f"### Баян-Өлгий үшін ең сенімді 7 күндік болжам")
            
            # Толық деректер кестесі
            gr.DataFrame(
                value=initial_df,
                headers=list(initial_df.columns),
                row_count="dynamic", 
                interactive=False,
                label="Ауа Райының Толық Деректері (Жел, Қар, Аяз)",
                wrap=True,
                type="pandas"
            )
            
            # Қазақша Болжам/Талдауды көрсету
            gr.Markdown("### 🧠 Quantum Талдауы (Қазақша)")
            gr.Markdown(initial_analysis)

            gr.Markdown("### 🗺️ Баян-Өлгий Картасы")
            gr.HTML(f"""
                <iframe 
                    width="100%" height="300" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" 
                    src="http://maps.google.com/maps?q=48.97,89.97&z=10&output=embed0{BAYAN_ULGII_LAT},{BAYAN_ULGII_LON}&z=10&output=embed">
                </iframe>
            """)

        # --- 2. ML Қолданбалары (Мамандандырылған Болжамдар) ---
        with gr.TabItem("🔬 ML Болжамдары (Өсімдік, Мал, Қоқыс)"):
            gr.Markdown("### 🔬 Мамандандырылған Модельдермен Талдау (Қазақша)")
            
            with gr.Row():
                # Мал Ауруын Анықтау
                with gr.Column():
                    gr.Markdown("#### 🐑 Мал Ауруын Анықтау (ShuffleNet V2)")
                    input_image_animal = gr.Image(type="pil", label="Мал суретін жүктеу")
                    output_text_animal = gr.Textbox(label="БОЛЖАМДЫ НӘТИЖЕ", interactive=False)
                    classify_btn_animal = gr.Button("Ауруды Анықтау")
                    classify_btn_animal.click(fn=lambda img: classify_image(img, task="animal"), inputs=input_image_animal, outputs=output_text_animal)

                # Өсімдік Түрін/Ауруын Анықтау
                with gr.Column():
                    gr.Markdown("#### 🌱 Өсімдік Түрін/Ауруын Анықтау (ShuffleNet V2)")
                    input_image_plant = gr.Image(type="pil", label="Өсімдік суретін жүктеу")
                    output_text_plant = gr.Textbox(label="БОЛЖАМДЫ НӘТИЖЕ", interactive=False)
                    classify_btn_plant = gr.Button("Түрін/Ауруын Анықтау")
                    classify_btn_plant.click(fn=lambda img: classify_image(img, task="plant"), inputs=input_image_plant, outputs=output_text_plant)

            gr.Markdown("---")
            
            # Қоқыс Түрін Анықтау
            gr.Markdown("#### 🗑️ Қоқыс Түрін Анықтау (EfficientNet B0)")
            with gr.Row():
                input_image_trash = gr.Image(type="pil", label="Қоқыс суретін жүктеу")
                output_text_trash = gr.Textbox(label="БОЛЖАМДЫ НӘТИЖЕ", interactive=False)
            classify_btn_trash = gr.Button("Түрін Анықтау")
            classify_btn_trash.click(fn=lambda img: classify_image(img, task="trash"), inputs=input_image_trash, outputs=output_text_trash)


        # --- 3. Анықтамалық Сөздік ---
        with gr.TabItem("📚 Анықтамалық Сөздік"):
            gr.Markdown("### 📚 Ауылшаруашылық Терминдері")
            gr.Markdown("""
            * **Жайлау:** Жыл мезгіліне байланысты мал жайылатын жер.
            * **Қыстақ:** Қысқы уақытта малды ұстайтын жылы жер.
            * **Күйіс қайыру:** Малдың жеген шөбін қайта ауызға шығарып шайнауы.
            """)

    # Уақытты әр минут сайын жаңарту (Ауа райы емес, тек сағат)
    demo.load(get_current_time, None, current_time_display, every=60) 

demo.launch()