Spaces:
Sleeping
Sleeping
| import os | |
| import io | |
| import gradio as gr | |
| import pandas as pd | |
| import requests | |
| import datetime | |
| import time | |
| import base64 | |
| import json | |
| import logging | |
| import tempfile | |
| from typing import List, Tuple, Dict, Any | |
| # Set logging level for debugging | |
| logging.basicConfig(level=logging.INFO) | |
| # ----------------------------------------------------------------- | |
| # 1. API CLIENT INITIALIZATION | |
| # ----------------------------------------------------------------- | |
| GEMINI_CLIENT = None | |
| API_STATUSES = {} | |
| def initialize_api(name, env_key, client_class=None): | |
| key = os.environ.get(env_key) | |
| status = "❌" | |
| client = None | |
| if not key or "YOUR_" in key.upper() or len(key) < 10: | |
| status = "⚠️ (Кілт Жоқ/Жарамсыз)" | |
| API_STATUSES[name] = status | |
| return None, status | |
| try: | |
| if client_class: | |
| from google import genai | |
| client = genai.Client(api_key=key) | |
| status = "✅" | |
| except Exception as e: | |
| status = f"❌ (Қате: {e.__class__.__name__})" | |
| API_STATUSES[name] = status | |
| return client, status | |
| # Gemini Initialization | |
| try: | |
| from google import genai | |
| GEMINI_CLIENT, status = initialize_api('Gemini', 'GEMINI_API_KEY', genai.Client) | |
| except Exception: | |
| API_STATUSES['Gemini'] = "❌ (genai пакеті жоқ)" | |
| # Non-client Keys | |
| NEWS_API_KEY = os.environ.get('NEWS_API_KEY') | |
| OPENWEATHER_API_KEY = os.environ.get('OPENWEATHER_API_KEY') | |
| OPENAI_KEY = os.environ.get('OPENAI_API_KEY') | |
| STABILITY_API_KEY = os.environ.get('STABILITY_API_KEY') | |
| initialize_api('OpenAI Mod', 'OPENAI_API_KEY') | |
| initialize_api('News', 'NEWS_API_KEY') | |
| initialize_api('Weather', 'OPENWEATHER_API_KEY') | |
| initialize_api('Stability (SDXL)', 'STABILITY_API_KEY') | |
| API_STATUS_NOTE = " | ".join([f"{k} {v}" for k, v in API_STATUSES.items()]) | |
| print(f"[{datetime.datetime.now().strftime('%H:%M:%S')}] API Status: {API_STATUS_NOTE}") | |
| # ----------------------------------------------------------------- | |
| # 2. CORE FUNCTIONS (V59.0 - Modern Chat Implementation) | |
| # ----------------------------------------------------------------- | |
| # 2.1. Direct Gemini Text Chat (FIXED for 'messages' type) | |
| def text_chat_gemini(message: str, chat_history: List[Dict[str, Any]]): | |
| """ | |
| Handles the modern Gradio ChatInterface (list of dicts format). | |
| e.g., history = [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}] | |
| """ | |
| if not message: | |
| return "" | |
| if GEMINI_CLIENT is None or API_STATUSES.get('Gemini') != "✅": | |
| return "❌ Gemini API кілті орнатылмаған немесе жарамсыз. Қызметті Hugging Face Secrets-те тексеріңіз." | |
| try: | |
| # Convert Gradio 'messages' format to Gemini 'contents' format | |
| contents = [] | |
| for entry in chat_history: | |
| # Map Gradio 'assistant' role to Gemini 'model' role | |
| role = "model" if entry["role"] == "assistant" else entry["role"] | |
| contents.append({"role": role, "parts": [{"text": entry["content"]}]}) | |
| # Add the current user message | |
| contents.append({"role": "user", "parts": [{"text": message}]}) | |
| system_instruction = "Сіз 'SQG Quantum Leap AI' атты интеллектуалды порталсыз. Жауаптарыңызды толығымен қазақ тілінде беріңіз. Достық, ақпараттық және кәсіби тонды сақтаңыз. Сіз Баян-Өлгий аймағына бағытталған ақпараттық орталықсыз." | |
| response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', | |
| contents=contents, | |
| system_instruction=system_instruction | |
| ) | |
| return response.text.strip() | |
| except Exception as e: | |
| return f"❌ Gemini Чат Қатесі: {e.__class__.__name__}. API кілтін тексеріңіз немесе лимит туралы ақпаратты қараңыз." | |
| # 2.2. Weather Prediction | |
| def get_weather_and_prediction(): | |
| lat, lon = 48.97, 89.97 | |
| output = "OpenWeatherMap Қатесі ❌." | |
| prediction_output = "Gemini болжамы жоқ." | |
| if not OPENWEATHER_API_KEY or API_STATUSES.get('Weather') != "✅": | |
| return "OpenWeatherMap Key орнатылмаған немесе қате ❌", prediction_output | |
| forecast_url = f"https://api.openweathermap.org/data/2.5/forecast?lat={lat}&lon={lon}&appid={OPENWEATHER_API_KEY}&units=metric&lang=kz" | |
| try: | |
| response = requests.get(forecast_url, timeout=5) | |
| response.raise_for_status() | |
| forecast_data = response.json() | |
| current_data = forecast_data['list'][0] | |
| temp = current_data['main']['temp'] | |
| wind_speed = current_data['wind']['speed'] | |
| desc = current_data['weather'][0]['description'].capitalize() | |
| output = f"⛈️ Өлгий Ауа Райы (OpenWeatherMap)\n\n* Температура: **{temp} °C**\n* Жағдайы: **{desc}**\n* Жел: **{wind_speed} м/с**" | |
| prediction_points = forecast_data['list'][1:4] | |
| if GEMINI_CLIENT and API_STATUSES.get('Gemini') == "✅": | |
| weather_text = json.dumps(prediction_points) | |
| prompt = f""" | |
| Сіз ауа райын талдаушысыз. Келесі JSON деректері Өлгий қаласының алдағы 9 сағаттағы ауа райы болжамдарын көрсетеді. | |
| Толығымен қазақ тілінде, қарапайым сөздермен түсіндіріп беріңіз. | |
| JSON деректері: {weather_text} | |
| """ | |
| gemini_response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', contents=prompt | |
| ) | |
| prediction_output = gemini_response.text.strip() | |
| return output, prediction_output | |
| except Exception as e: | |
| return f"Белгісіз Қате: {e.__class__.__name__}", prediction_output | |
| # 2.3. Image Generation (Stability AI SDXL-Turbo) | |
| def generate_image_sdxl(prompt): | |
| if not STABILITY_API_KEY or API_STATUSES.get('Stability (SDXL)') != "✅": | |
| return None, "Stability API Key орнатылмаған немесе қате ❌" | |
| if not prompt: | |
| return None, "Мәтінді енгізіңіз." | |
| url = "https://api.stability.ai/v2beta/stable-image/generate/sd3" | |
| headers = { "authorization": f"Bearer {STABILITY_API_KEY}", "accept": "image/*" } | |
| data = { | |
| "prompt": f"Detailed cinematic photo, Kazakh culture theme, high resolution, soft lighting, 8k, {prompt}", | |
| "output_format": "jpeg", "aspect_ratio": "1:1", "model": "sd3-medium" | |
| } | |
| try: | |
| response = requests.post(url, headers=headers, files={'none': ''}, data=data, timeout=30) | |
| response.raise_for_status() | |
| if response.status_code == 200: | |
| base64_img = base64.b64encode(response.content).decode("utf-8") | |
| return f"data:image/jpeg;base64,{base64_img}", "Сурет сәтті жасалды ✅" | |
| else: | |
| return None, f"SDXL Қатесі: {response.status_code} - {response.text[:100]}" | |
| except Exception as e: | |
| return None, f"Сурет Генерациялау Қатесі: {e.__class__.__name__}" | |
| # 2.4. AI Voice Chat (Gemini) | |
| def process_voice_chat(audio_path): | |
| if not audio_path or GEMINI_CLIENT is None or API_STATUSES.get('Gemini') != "✅": | |
| return "Дауыс жазбасы жоқ", "Gemini API Қатесі ❌" | |
| audio_file = None | |
| try: | |
| transcribe_prompt = "Transcribe the audio and provide ONLY the text in the original language. Do not add any extra commentary." | |
| audio_file = GEMINI_CLIENT.upload_file(file=audio_path) | |
| transcribe_response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', contents=[transcribe_prompt, audio_file] | |
| ) | |
| original_text = transcribe_response.text.strip() | |
| chat_prompt = f"Сіз 'SQG Quantum Leap AI'-сіз. Сізге келесі сұрақ қойылды. Жауабыңызды толығымен **қазақ тілінде** беріңіз:\n\nСұрақ: {original_text}" | |
| chat_response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', contents=chat_prompt | |
| ) | |
| GEMINI_CLIENT.delete_file(audio_file.name) | |
| ai_response_text = chat_response.text.strip() | |
| return original_text, ai_response_text | |
| except Exception as e: | |
| if audio_file: | |
| try: | |
| GEMINI_CLIENT.delete_file(audio_file.name) | |
| except: | |
| pass | |
| return "Түпнұсқа мәтін қатесі", f"ЖИ Сөйлесу Қатесі: {e.__class__.__name__}. Gemini-ге аудио жіберу қатесі." | |
| # 2.5. Vision (Image Analysis) | |
| def analyze_vision_gemini(img): | |
| if img is None or GEMINI_CLIENT is None or API_STATUSES.get('Gemini') != "✅": | |
| df = pd.DataFrame({"Нәтиже": ["Қате"], "Сенімділік": ["-"]}) | |
| return df, "Gemini API Қатесі ❌" | |
| vision_file = None | |
| temp_img_path = None | |
| try: | |
| with tempfile.NamedTemporaryFile(suffix=".jpeg", delete=False) as tmp: | |
| img.save(tmp.name, format="JPEG") | |
| temp_img_path = tmp.name | |
| vision_file = GEMINI_CLIENT.upload_file(file=temp_img_path) | |
| prompt = "Analyze this image in detail and provide ONLY the analysis in fluent Kazakh. Start with a short, encouraging greeting." | |
| response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', contents=[prompt, vision_file] | |
| ) | |
| GEMINI_CLIENT.delete_file(vision_file.name) | |
| os.unlink(temp_img_path) | |
| full_text = response.text.strip() | |
| df = pd.DataFrame([["Жасанды Интеллект Талдауы", "Жоғары"]], columns=["Нәтиже", "Сенімділік"]) | |
| return df, f"Талдау Ескертпесі: {full_text}" | |
| except Exception as e: | |
| if vision_file: | |
| try: GEMINI_CLIENT.delete_file(vision_file.name) | |
| except: pass | |
| if temp_img_path and os.path.exists(temp_img_path): | |
| os.unlink(temp_img_path) | |
| df = pd.DataFrame({"Нәтиже": ["Қате"], "Сенімділік": ["-"]}) | |
| return df, f"Gemini Vision Қатесі: {e.__class__.__name__}" | |
| # 2.6. News and Moderation | |
| def get_latest_news(query): | |
| if not NEWS_API_KEY or API_STATUSES.get('News') != "✅": return "NewsAPI Key орнатылмаған немесе қате ❌." | |
| if not query: query = "Kazakhstan OR Mongolia OR Kazakh Diaspora" | |
| url = f"https://newsapi.org/v2/everything?q={query}&language=en&sortBy=publishedAt&apiKey={NEWS_API_KEY}&pageSize=5" | |
| try: | |
| response = requests.get(url, timeout=10) | |
| response.raise_for_status() | |
| data = response.json() | |
| articles = data.get('articles', []) | |
| if not articles: return f"Табылған жаңалықтар жоқ: '{query}'" | |
| article_summaries = "\n---\n".join([f"Атауы: {a.get('title')}. Қысқаша: {a.get('description') or 'N/A'}" for a in articles]) | |
| prompt = f""" | |
| Төмендегі 5 жаңалықтың атаулары мен қысқаша сипаттамалары берілген. | |
| Оларды 1-ден 5-ке дейін нөмірлеп, әрқайсысын 1 сөйлеммен толығымен қазақ тілінде түсіндіріп беріңіз. | |
| Жауапты '🚨 Соңғы Жаңалықтар:' деген сөзбен бастаңыз. | |
| Мәтін: | |
| {article_summaries} | |
| """ | |
| if GEMINI_CLIENT and API_STATUSES.get('Gemini') == "✅": | |
| summary_response = GEMINI_CLIENT.models.generate_content( | |
| model='gemini-2.5-flash', contents=prompt | |
| ) | |
| return summary_response.text.strip() | |
| else: | |
| output = "🚨 Соңғы Жаңалықтар (Gemini қорытындысы жоқ. Ағылшын тіліндегі деректер):\n\n" | |
| for i, article in enumerate(articles): | |
| title = article.get('title', 'Атауы жоқ') | |
| source = article.get('source', {}).get('name', 'Белгісіз') | |
| output += f"{i+1}. **{title}**\n(Дереккөз: {source})\n\n" | |
| return output.strip() | |
| except Exception as e: | |
| return f"Жаңалықтар Қатесі: {e.__class__.__name__}" | |
| def add_post_with_moderation(current_state, new_message): | |
| if not new_message: return current_state, "\n\n---\n\n".join(current_state), time.time(), "Модерация ✅" | |
| is_toxic, ai_note = False, "Модерация ✅" | |
| if OPENAI_KEY and API_STATUSES.get('OpenAI Mod') == "✅": | |
| try: | |
| mod_response = requests.post( | |
| "https://api.openai.com/v1/moderations", | |
| headers={"Authorization": f"Bearer {OPENAI_KEY}", "Content-Type": "application/json"}, | |
| json={"input": new_message} | |
| ) | |
| mod_response.raise_for_status() | |
| data = mod_response.json() | |
| if data["results"][0]["flagged"]: | |
| is_toxic = True | |
| ai_note = "🛡️ Қабылданбады (Токсикалық Контент)" | |
| except Exception: | |
| ai_note = "Модерация Қатесі ⚠️" | |
| if is_toxic: | |
| return current_state, "\n\n---\n\n".join(current_state), time.time(), ai_note | |
| now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime('%H:%M') | |
| formatted_msg = "[{}] Хабарлама: {}".format(now, new_message) | |
| updated_state = [formatted_msg] + current_state | |
| return updated_state[:10], "\n\n---\n\n".join(updated_state[:10]), time.time(), ai_note | |
| def get_local_time_and_holiday(last_active): | |
| now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))) | |
| time_str = now.strftime('%Y жылғы %B айының %d күні, сағат %H:%M') | |
| holiday_note = "" | |
| # Example holidays for Bayan-Olgii/Mongolia | |
| if now.month == 7 and now.day in [11, 12, 13, 14, 15]: | |
| holiday_note = "Бүгін - Наадам Мерекесі (Ұлттық Мереке) 🇲🇳" | |
| elif now.month == 12 and now.day == 29: | |
| holiday_note = "Бүгін - Тәуелсіздік Күні 🇲🇳" | |
| return f"⏱️ Өлгий (Моңғолия) Уақыты:\n\n**{time_str}**\n\n{holiday_note}" | |
| # ----------------------------------------------------------------- | |
| # 3. GRADIO INTERFACE (V59.0 - Starry Night Theme & Modern Chat) | |
| # ----------------------------------------------------------------- | |
| # (V59.0) ҚАЙТАРУ: Сізге ұнаған 'Жұлдызды Түн' тақырыбы (Dark Mode) | |
| # Бұл CSS 'style.css' файлын қажет етпейді, кодтың өзіне енгізілген. | |
| css_style = """ | |
| /* V59.0: Vincent Van Gogh Starry Night Theme (Fixed) */ | |
| body { | |
| background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Van_Gogh_Starry_Night_-_Restored.jpg/2560px-Van_Gogh_Starry_Night_-_Restored.jpg') !important; | |
| background-size: cover !important; | |
| background-attachment: fixed !important; | |
| background-position: center !important; | |
| color: #f0f0f0 !important; | |
| } | |
| .gradio-container { | |
| background: rgba(0, 0, 0, 0.8) !important; /* Қараңғы фон (80%) */ | |
| border-radius: 20px !important; | |
| padding: 20px !important; | |
| color: #f0f0f0 !important; | |
| box-shadow: 0 0 40px rgba(255, 215, 0, 0.5); /* Gold shadow for contrast */ | |
| } | |
| h1, h3 { color: #ffd700 !important; font-family: sans-serif; } | |
| /* Input and text boxes styling */ | |
| .gradio-box, .gr-box, .gr-form, .gr-input, .gr-textarea { | |
| background: rgba(40, 40, 40, 0.9) !important; | |
| color: #f0f0f0 !important; | |
| border: 1px solid #1a4d95 !important; | |
| border-radius: 8px !important; | |
| } | |
| /* Button styling (Gold/Navy contrast) */ | |
| .gr-button { | |
| background: #ffd700 !important; | |
| color: #1a4d95 !important; | |
| font-weight: bold !important; | |
| border-radius: 12px !important; | |
| transition: all 0.2s; | |
| } | |
| .gr-button:hover { | |
| background: #ffc400 !important; | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 10px rgba(255, 215, 0, 0.5); | |
| } | |
| /* Active Tab styling */ | |
| .gr-tab-button.selected { | |
| background: #1a4d95 !important; | |
| color: #ffd700 !important; | |
| border-top-left-radius: 10px; | |
| border-top-right-radius: 10px; | |
| } | |
| /* Chatbot styling (Dark mode) */ | |
| .gradio-chatbot { | |
| border: 1px solid #ffd700 !important; | |
| border-radius: 10px !important; | |
| background-color: rgba(0, 0, 0, 0.5) !important; | |
| padding: 10px; | |
| } | |
| /* Custom class for the status note */ | |
| .status-note { | |
| font-size: 1.1em; | |
| font-weight: bold; | |
| padding: 10px; | |
| border-radius: 10px; | |
| background-color: rgba(255, 243, 205, 0.9); /* Ашық сары фон */ | |
| color: #856404; /* Қою сары мәтін */ | |
| text-align: center; | |
| border: 1px solid #ffeeba; | |
| } | |
| """ | |
| with gr.Blocks(theme=gr.themes.Soft(), css=css_style, title="SQG Quantum Leap AI V59.0") as interface: | |
| # State variables | |
| message_state = gr.State([]) | |
| last_active = gr.State(0) | |
| # Header | |
| gr.Markdown(f"<h1><center>🌌 SQG Quantum Leap AI: Баян-Өлгий</center></h1>") | |
| gr.Markdown(f"<div class='status-note'>Мультимодалды ЖИ-қызметтердің КҮЙІ: {API_STATUS_NOTE}</div>") | |
| # Removed the clunky "Welcome" text | |
| with gr.Tabs(): | |
| # 1. DEDICATED GEMINI TEXT CHAT (V59.0 - Modern 'messages' type) | |
| with gr.TabItem("💬 Gemini Чат"): | |
| gr.Markdown("## Gemini - Тікелей Сұрақ-Жауап (Қазақ тілінде)") | |
| gr.Markdown("Сұрағыңызды енгізіңіз. Gemini-2.5 Flash моделі сізге қазақ тіліндегі ең жылдам және дәл жауаптарды ұсынады.") | |
| # FIX: Added type='messages' to fix the UserWarning and ensure compatibility | |
| gr.ChatInterface( | |
| fn=text_chat_gemini, | |
| chatbot=gr.Chatbot(height=550, type="messages"), # This is the critical fix | |
| textbox=gr.Textbox(placeholder="Сұрағыңызды енгізіңіз...", container=False, scale=7), | |
| title="Gemini-мен Сөйлесу", | |
| ) | |
| # 2. VOICE CHAT (Дауыс арқылы енгізу) | |
| with gr.TabItem("🎙️ AI Сөйлесу"): | |
| gr.Markdown("## Gemini - Дауыстық Интеллект (STT & LLM)") | |
| gr.Markdown("Микрофонға сөйлеңіз. ЖИ дауысыңызды мәтінге аударып, сұраққа жауап береді.") | |
| audio_input = gr.Audio(sources=["microphone"], type="filepath", label="Сұрағыңызды айтыңыз (аудио жазба)", autoplay=False) | |
| voice_btn = gr.Button("🗣️ Сөйлесуді Бастау") | |
| with gr.Row(): | |
| user_text_output = gr.Textbox(label="Сіздің Сөзіңіз (Gemini Аудармасы)", lines=2, interactive=False) | |
| ai_text_output = gr.Textbox(label="ЖИ Жауабы (Мәтін)", lines=4, interactive=False) | |
| voice_btn.click(fn=process_voice_chat, inputs=[audio_input], outputs=[user_text_output, ai_text_output]) | |
| # 3. IMAGE GENERATION | |
| with gr.TabItem("✨ Сурет Жасау"): | |
| gr.Markdown("## Stability AI - Генеративті Кескін (SDXL-Turbo)") | |
| gr.Markdown("Қазақ мәдениетіне немесе сіз қалаған тақырыпқа сәйкес сипаттама беріңіз, сонда ЖИ бірегей сурет жасайды.") | |
| prompt_input = gr.Textbox(label="Сурет Идеясын Енгізіңіз (ағылшынша немесе қазақша)", lines=2, placeholder="Мысалы: 'Көшпенділер даладағы жылқыларды айдап барады, күн батуы'") | |
| gen_btn = gr.Button("🖼️ Сурет Жасауды Бастау") | |
| with gr.Row(): | |
| image_output = gr.Image(label="Генерацияланған Сурет", type="filepath", height=450) | |
| status_output = gr.Textbox(label="Күйі", lines=2, interactive=False) | |
| gen_btn.click(fn=generate_image_sdxl, inputs=[prompt_input], outputs=[image_output, status_output]) | |
| # 4. VISION (Image Analysis) | |
| with gr.TabItem("🖼️ Сурет Талдау"): | |
| gr.Markdown("## Gemini Vision - Кескінді Аналитикалық Талдау") | |
| gr.Markdown("Кез келген суретті жүктеңіз. Gemini оның ішіндегі мазмұнды толығымен қазақ тілінде талдап береді.") | |
| with gr.Row(): | |
| img_input = gr.Image(type="pil", label="Сурет Жүктеу немесе Түсіру", height=350) | |
| with gr.Column(): | |
| output_table = gr.Dataframe(headers=["Нәтиже", "Сенімділік"], label="ЖИ Нәтижесі (Қазақша)", row_count=1, col_count=(2, 'fixed')) | |
| qazaq_note_output = gr.Textbox(label="Талдау Ескертпесі (Толық Қазақша Сипаттама)", lines=6, interactive=False) | |
| submit_btn = gr.Button("▶️ Талдауды Бастау") | |
| submit_btn.click(fn=analyze_vision_gemini, inputs=[img_input], outputs=[output_table, qazaq_note_output]) | |
| # 5. WEATHER & PREDICTION (Fixed NameError) | |
| with gr.TabItem("🗺️ Ауа Райы & Болжам"): | |
| gr.Markdown("## OpenWeatherMap & Gemini - Өлгийдің Ауа Райы") | |
| initial_weather, initial_prediction = get_weather_and_prediction() | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| # 1. Define weather_output | |
| weather_output = gr.Markdown(value=initial_weather) | |
| gr.Markdown("### Уақыт") | |
| # 2. Define time_output | |
| time_output = gr.Markdown(get_local_time_and_holiday(0)) | |
| # 3. Define time_refresh_btn | |
| time_refresh_btn = gr.Button("⏱️ Уақытты Жаңарту") | |
| # 4. Define weather_refresh_btn | |
| refresh_btn = gr.Button("🔄 Ауа Райын Жаңарту") | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Gemini Болжамы (3-9 сағат)") | |
| # 5. Define prediction_output | |
| prediction_output = gr.Textbox( | |
| value=initial_prediction, | |
| label="Жақын 3-9 Сағатқа Арналған Болжам (Gemini Талдауы)", | |
| lines=5, | |
| interactive=False | |
| ) | |
| gr.HTML(value='<iframe src="http://googleusercontent.com/maps/google.com/1" width="100%" height="300" style="border:0; border-radius: 10px;"></iframe>', label="Карта") | |
| # 6. Attach click handlers *after* all components are defined | |
| time_refresh_btn.click(fn=get_local_time_and_holiday, inputs=last_active, outputs=time_output) | |
| refresh_btn.click(fn=get_weather_and_prediction, outputs=[weather_output, prediction_output]) | |
| # 6. NEWS | |
| with gr.TabItem("📰 Жаңалықтар & Ақпарат"): | |
| gr.Markdown("## NewsAPI & Gemini - Әлемдік Жаңалықтарға Шолу") | |
| news_query = gr.Textbox(label="Тақырып бойынша іздеу", placeholder="Мысалы: 'Қазақ музыкасы' немесе 'Моңғолия экономикасы'", lines=1) | |
| news_btn = gr.Button("🔎 Жаңалықтарды Көру & Қазақша Түсіндіру") | |
| news_output = gr.Textbox(label="Gemini Талдаған Жаңалықтар Қорытындысы", lines=10, interactive=False) | |
| news_btn.click(fn=get_latest_news, inputs=[news_query], outputs=news_output) | |
| # 7. HUB (Moderation Chat) | |
| with gr.TabItem("📢 Хабарламалар (AI Модерация)"): | |
| gr.Markdown("## OpenAI - Қауіпсіз Коммуникация Хабы") | |
| gr.Markdown("Хабарлама жіберіңіз. OpenAI модерациясы оны жарияламас бұрын токсикалық мазмұнға тексереді.") | |
| moderation_status = gr.Markdown("🛡️ Модерация Күйі (OpenAI)", elem_id="mod_status") | |
| message_display = gr.Markdown(value="Ешқандай хабарлама жоқ...", label="Соңғы 10 Хабарлама Тарихы") | |
| with gr.Row(): | |
| message_input = gr.Textbox(label="Жаңа Хабарлама", placeholder="Хабарлама енгізіңіз...", lines=2) | |
| send_button = gr.Button("Жіберу (AI Тексереді)") | |
| send_button.click( | |
| fn=add_post_with_moderation, inputs=[message_state, message_input], outputs=[message_state, message_display, last_active, moderation_status] | |
| ) | |
| # ----------------------------------------------------------------- | |
| # 4. LAUNCH INTERFACE | |
| # ----------------------------------------------------------------- | |
| if __name__ == "__main__": | |
| interface.launch() |