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, Dict, Any
import sys
# Set logging level
logging.basicConfig(level=logging.INFO)
# -----------------------------------------------------------------
# 0. OPEN SOURCE LLM SETUP (Llama 3 8B Reserve)
# -----------------------------------------------------------------
LLM_AVAILABLE = False
LLM_STATUS = "❌ Llama 3 (Сөндірулі)"
LLM_MODEL = None
LLM_TOKENIZER = None
try:
# Requires: torch, transformers, accelerate, bitsandbytes
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# Initialization check (This step can be slow and memory intensive)
LLM_MODEL_NAME = "meta-llama/Meta-Llama-3-8B-Instruct"
LLM_TOKENIZER = AutoTokenizer.from_pretrained(LLM_MODEL_NAME)
# Load model using 8-bit quantization to save RAM (Crucial for 16GB RAM)
LLM_MODEL = AutoModelForCausalLM.from_pretrained(
LLM_MODEL_NAME,
device_map="auto",
torch_dtype=torch.bfloat16,
load_in_8bit=True # Important for memory efficiency on CPU/low-VRAM GPU
)
LLM_AVAILABLE = True
LLM_STATUS = "✅ Llama 3 8B (Резерв)"
except ImportError:
LLM_STATUS = "❌ Llama 3 (Пакет жоқ)"
except Exception as e:
LLM_STATUS = f"❌ Llama 3 (Қате: {e.__class__.__name__})"
# -----------------------------------------------------------------
# 1. API CLIENT INITIALIZATION (Standardized)
# -----------------------------------------------------------------
GEMINI_CLIENT = None
API_STATUSES = {'OpenLLM': LLM_STATUS}
def initialize_api(name, env_key, client_class=None):
key = os.environ.get(env_key)
status = "❌"
client = None
# 1. Key Presence Check
if not key or "YOUR_" in key.upper() or len(key) < 10:
status = "⚠️ (Кілт Жоқ/Жарамсыз)"
return None, status
try:
# 2. Client Initialization Check
if client_class:
from google import genai
client = genai.Client(api_key=key)
status = "✅"
except Exception as e:
status = f"❌ (Қате: {e.__class__.__name__})"
return client, status
# Initialize Gemini Client (Primary AI)
try:
from google import genai
GEMINI_CLIENT, status = initialize_api('Gemini', 'GEMINI_API_KEY', genai.Client)
API_STATUSES['Gemini'] = status
except Exception:
API_STATUSES['Gemini'] = "❌ (genai пакеті жоқ)"
# Check and store status for other APIs
_, API_STATUSES['OpenAI Mod'] = initialize_api('OpenAI Mod', 'OPENAI_API_KEY')
_, API_STATUSES['News'] = initialize_api('News', 'NEWS_API_KEY')
_, API_STATUSES['Weather'] = initialize_api('Weather', 'OPENWEATHER_API_KEY')
_, API_STATUSES['Stability (SDXL)'] = initialize_api('Stability (SDXL)', 'STABILITY_API_KEY')
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')
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}")
LAST_AI_RESPONSE = ""
# -----------------------------------------------------------------
# 2. CORE FUNCTIONS
# -----------------------------------------------------------------
# 190-жолдағы қатенің шығуын болдырмау үшін 'global' бірінші тұр.
def text_to_speech_html(text):
global LAST_AI_RESPONSE # <--- МІНДЕТТІ ТҮРДЕ БІРІНШІ ОПЕРАТОР
LAST_AI_RESPONSE = text
return f"""
🗣️ Ауызша оқуға дайын. Түймені басыңыз.
"""
def play_last_response():
global LAST_AI_RESPONSE # <--- МІНДЕТТІ ТҮРДЕ БІРІНШІ ОПЕРАТОР
if not LAST_AI_RESPONSE:
return f"""❌ Оқылатын мәтін жоқ.
"""
clean_text = LAST_AI_RESPONSE[:500].replace('"', "'").replace('\n', ' ')
js_script = f"""
"""
return f"""🎧 Оқылуда...
{js_script}"""
# 2.1. PRIMARY CHAT FUNCTION (Gemini OR Llama 3 Fallback)
def text_chat_gemini_or_llama(message: str, chat_history: List[List[str]]):
if not message: return ""
# 1. --- Try Gemini (Primary) ---
if GEMINI_CLIENT and API_STATUSES.get('Gemini') == "✅":
try:
contents = []
for user_msg, model_msg in chat_history:
if user_msg:
contents.append({"role": "user", "parts": [{"text": user_msg}]})
if model_msg:
contents.append({"role": "model", "parts": [{"text": model_msg}]})
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
)
ai_text = response.text.strip()
global LAST_AI_RESPONSE
LAST_AI_RESPONSE = ai_text
return ai_text
except Exception as e:
logging.error(f"Gemini API Error: {e}")
# Fall through to Llama 3 if Gemini fails
pass
# 2. --- Fallback to Llama 3 (Backup) ---
if LLM_AVAILABLE:
try:
system_prompt = "Сіз 'SQG Quantum Leap AI' атты интеллект. Жауапты тек қазақ тілінде, достық тонмен беріңіз."
messages = [{"role": "system", "content": system_prompt}]
for user_msg, model_msg in chat_history:
if user_msg:
messages.append({"role": "user", "content": user_msg})
if model_msg:
messages.append({"role": "assistant", "content": model_msg})
messages.append({"role": "user", "content": message})
prompt = LLM_TOKENIZER.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = LLM_TOKENIZER(prompt, return_tensors="pt").to(LLM_MODEL.device)
outputs = LLM_MODEL.generate(
**inputs, max_new_tokens=256, temperature=0.7, do_sample=True
)
ai_text = LLM_TOKENIZER.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True).strip()
global LAST_AI_RESPONSE
LAST_AI_RESPONSE = ai_text
return ai_text + "\n\n(🌐 Llama 3 8B арқылы жауап берілді - Резерв)"
except Exception as e:
logging.error(f"Llama 3 LLM Error: {e}")
return f"❌ Gemini API Қатесі және Llama 3 Резерві де істен шықты: {e.__class__.__name__}. Ресурстарды тексеріңіз."
# 3. --- Total Failure ---
return "❌ API Қатесі. Gemini API кілтін тексеріңіз немесе Llama 3 резерві іске қосылмаған."
# 2.2. Weather Prediction (Only uses Gemini for prediction, will show basic weather if Gemini fails)
def get_weather_and_prediction():
lat, lon = 48.97, 89.97
output = "OpenWeatherMap Қатесі ❌."
prediction_output = "Gemini болжамы жоқ. (LLM резерві бұл функцияға қолдау көрсетпейді)"
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"⛈️ Өлгий (Ағымдағы)\n\n* Температура: **{temp} °C**\n* Жағдайы: **{desc}**\n* Жел: **{wind_speed} м/с**"
prediction_points = [forecast_data['list'][i] for i in range(0, min(len(forecast_data['list']), 40), 8)]
if GEMINI_CLIENT and API_STATUSES.get('Gemini') == "✅":
weather_text = json.dumps(prediction_points)
prompt = f"Сіз ауа райын талдаушысыз. Келесі JSON деректері Өлгий қаласының алдағы 5 күндегі ауа райы болжамдарын көрсетеді. Толығымен қазақ тілінде, қарапайым 5 күндік шолу жасап беріңіз. 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 (API Dependent - No LLM reserve for this)
def generate_image_sdxl(prompt):
if not STABILITY_API_KEY or API_STATUSES.get('Stability (SDXL)') != "✅":
return None, "Stability Key Қате ❌. Немесе API-ға қолжетімділік жоқ."
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}. API лимит."
except Exception as e:
return None, f"Сурет Қатесі: {e.__class__.__name__}. API байланысын тексеріңіз."
# 2.4. AI Voice Chat (API Dependent - Uses Gemini for both ASR and Chat)
def process_voice_chat(audio_path):
if not audio_path: return "Дауыс жазбасы жоқ", "Gemini API Қатесі ❌"
if 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)
return original_text, chat_response.text.strip()
except Exception as e:
if audio_file:
try: GEMINI_CLIENT.delete_file(audio_file.name)
except: pass
return "Түпнұсқа мәтін қатесі", f"ЖИ Сөйлесу Қатесі: {e.__class__.__name__}."
# 2.5. Vision (Image Analysis - API Dependent)
def analyze_vision_gemini(img):
if img is None:
df = pd.DataFrame({"Нәтиже": ["Сурет жоқ"], "Сенімділік": ["-"]})
return df, "Сурет жүктеңіз."
if 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 (Strong key check)
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:
return "🚨 Жаңалықтар (Gemini жоқ): Қорытындылау мүмкін емес."
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, "Модерация ✅ (OpenAI)"
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-%m-%d, %H:%M')
holiday_note = ""
if now.month == 7 and now.day in [11, 12, 13]:
holiday_note = "Бүгін - Наадам Мерекесі 🇲🇳"
return f"⏱️ Өлгий Уақыты: **{time_str}**\n\n{holiday_note}"
def translate_text_gemini(text, source_lang, target_lang="Қазақ"):
if not text: return "Мәтін енгізіңіз."
if GEMINI_CLIENT is None or API_STATUSES.get('Gemini') != "✅":
return "❌ Gemini API Қатесі."
prompt = f"Сіз жоғары дәлдіктегі аудармашысыз. Түпнұсқа тіл '{source_lang}' тілінен '{target_lang}' тіліне аударыңыз. Тек аударма мәтінін ғана беріңіз. Мәтін: '{text}'"
try:
response = GEMINI_CLIENT.models.generate_content(
model='gemini-2.5-flash', contents=prompt
)
return response.text.strip()
except Exception as e:
return f"❌ Аударма Қатесі: {e.__class__.__name__}"
def get_map_ai_analysis():
if GEMINI_CLIENT is None or API_STATUSES.get('Gemini') != "✅":
return "❌ Gemini API Қатесі."
prompt = "Баян-Өлгий аймағының географиялық ерекшеліктері, климаты және осы аймақтың қазақ халқы үшін маңыздылығы туралы 5 қысқа фактіні толығымен қазақ тілінде, таза тілмен сипаттаңыз. Жауапты '🌐 Гео-Талдау:' деп бастаңыз."
try:
response = GEMINI_CLIENT.models.generate_content(
model='gemini-2.5-flash', contents=prompt
)
return response.text.strip()
except Exception as e:
return f"❌ Карта Талдауы Қатесі: {e.__class__.__name__}"
# -----------------------------------------------------------------
# 3. GRADIO INTERFACE (Finalized Design)
# -----------------------------------------------------------------
# Finalized CSS for stability and readability
css_style = """
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.95) !important;
border-radius: 15px !important;
padding: 20px !important;
box-shadow: 0 0 30px rgba(70, 130, 180, 0.5);
}
h1, h3 { color: #ffd700 !important; font-family: sans-serif; }
.gr-box, .gr-input, .gr-textarea {
background: rgba(30, 30, 30, 0.9) !important;
color: #f0f0f0 !important;
border: 1px solid #4682b4 !important;
border-radius: 6px !important;
}
.gr-button {
background: #4682b4 !important;
color: #ffffff !important;
font-weight: bold !important;
border-radius: 8px !important;
}
.gr-tab-button.selected {
background: #1a4d95 !important;
color: #ffd700 !important;
}
.status-note {
background-color: rgba(255, 243, 205, 0.9);
color: #856404;
text-align: center;
padding: 5px;
border-radius: 5px;
}
.gradio-chatbot {
background-color: rgba(255, 255, 255, 0.05) !important;
}
"""
with gr.Blocks(theme=gr.themes.Soft(), css=css_style, title="SQG Quantum Leap AI V69.0") as interface:
# State variables
message_state = gr.State([])
last_active = gr.State(0)
# Header
gr.Markdown(f"🌌 SQG Quantum Leap AI: Баян-Өлгий
")
gr.Markdown(f"ЖИ Қызметтер Күйі: {API_STATUS_NOTE}
")
with gr.Tabs():
# 1. DEDICATED HYBRID CHAT (Uses Gemini, falls back to Llama 3)
with gr.TabItem("💬 Чат & 🔊"):
gr.Markdown("## Гибридті ЖИ Чат (Gemini + Llama 3 Резерві)")
tts_status_output = gr.HTML(value="Оқылатын мәтін жоқ.", visible=True)
tts_btn = gr.Button("🔊 Соңғы Жауапты Оқыту (TTS)")
chat_interface = gr.ChatInterface(
fn=text_chat_gemini_or_llama, # <-- USING THE HYBRID FUNCTION
textbox=gr.Textbox(placeholder="Сұрағыңызды енгізіңіз...", container=False),
title="",
submit_btn="Жіберу"
)
tts_btn.click(
fn=play_last_response,
outputs=tts_status_output,
queue=False
)
# 2. VOICE CHAT
with gr.TabItem("🎙️ Дауыс"):
gr.Markdown("## Дауыстық Сөйлесу")
audio_input = gr.Audio(sources=["microphone"], type="filepath", label="Дауыс жазба")
voice_btn = gr.Button("🗣️ Сөйлесуді Бастау")
with gr.Row():
user_text_output = gr.Textbox(label="Сіздің Сөзіңіз", 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("## Кескін Генерациясы")
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("## Кескінді Талдау")
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 & MAP AI
with gr.TabItem("🗺️ Ауа Райы & Карта"):
gr.Markdown("## Өлгий Ауа Райы & Гео-Талдау")
initial_weather, initial_prediction = get_weather_and_prediction()
initial_map_ai = get_map_ai_analysis()
with gr.Row():
with gr.Column(scale=1):
weather_output = gr.Markdown(value=initial_weather)
time_output = gr.Markdown(get_local_time_and_holiday(0))
refresh_btn = gr.Button("🔄 Жаңарту")
time_refresh_btn = gr.Button("⏱️ Уақытты Жаңарту")
with gr.Column(scale=2):
gr.Markdown("### 5 Күндік Болжам")
prediction_output = gr.Textbox(value=initial_prediction, label="Gemini Шолуы", lines=10, interactive=False)
refresh_btn.click(fn=get_weather_and_prediction, outputs=[weather_output, prediction_output])
time_refresh_btn.click(fn=get_local_time_and_holiday, inputs=last_active, outputs=time_output)
gr.Markdown("---")
gr.Markdown("### 🌐 Карта & ЖИ Гео-Талдау")
gr.HTML(value='', label="Карта")
map_ai_output = gr.Textbox(value=initial_map_ai, label="Gemini Талдауы", lines=6, interactive=False)
map_ai_btn = gr.Button("🧠 Гео-Талдауды Жаңарту")
map_ai_btn.click(fn=get_map_ai_analysis, outputs=map_ai_output)
# 6. NEWS
with gr.TabItem("📰 Жаңалықтар"):
gr.Markdown("## Жаңалықтар Шолуы")
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("📢 Хабарламалар"):
gr.Markdown("## Коммуникация Хабы")
moderation_status = gr.Markdown("🛡️ Модерация Күйі", 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]
)
# 8. TRANSLATION TAB
with gr.TabItem("🌍 Аударма"):
gr.Markdown("## ЖИ Аудармашы")
with gr.Row():
source_text = gr.Textbox(label="Түпнұсқа Мәтін", lines=5)
source_lang_dropdown = gr.Dropdown(
["Орыс", "Түрік", "Моңғол", "Ағылшын"],
label="Түпнұсқа Тіл",
value="Орыс"
)
translate_btn = gr.Button("➡️ Аударма")
translated_text = gr.Textbox(label="Аударма", lines=5, interactive=False)
translate_btn.click(
fn=translate_text_gemini,
inputs=[source_text, source_lang_dropdown],
outputs=translated_text
)
# -----------------------------------------------------------------
# 4. LAUNCH INTERFACE
# -----------------------------------------------------------------
if __name__ == "__main__":
interface.launch()