chat-bots-test / app.py
MrAlexGov's picture
Update app.py
14d1f54 verified
raw
history blame
8.7 kB
import gradio as gr
from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
from typing import List, Dict, Any, Tuple
import torch
import warnings
# Подавляем ненужные предупреждения
warnings.filterwarnings("ignore", message=".*low_cpu_mem_usage.*")
# CPU-модели (только одна маленькая модель для экономии памяти)
MODELS = {
"Qwen2.5-0.5B": "Qwen/Qwen2.5-0.5B-Instruct",
"Qwen2.5-1.5B": "Qwen/Qwen2.5-1.5B-Instruct",
}
def load_model(model_key: str):
model_id = MODELS[model_key]
print(f"🚀 Загрузка {model_id}...")
tokenizer = AutoTokenizer.from_pretrained(model_id)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
# Сначала загружаем модель отдельно с оптимизацией памяти
try:
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float32,
device_map=None, # Используем CPU
low_cpu_mem_usage=True,
trust_remote_code=True
)
except Exception as e:
print(f"⚠️ Не удалось загрузить с low_cpu_mem_usage: {e}")
print("🔄 Пробуем без low_cpu_mem_usage...")
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.float32,
trust_remote_code=True
)
# Затем создаем pipeline
pipe = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
device=-1, # Явно указываем CPU (-1 означает CPU)
max_new_tokens=128, # Ещё меньше токенов для экономии памяти
do_sample=True,
temperature=0.7,
pad_token_id=tokenizer.eos_token_id
)
print(f"✅ {model_id} загружена!")
return pipe
model_cache = {}
def respond(message: str,
history: List[Dict[str, str]],
model_key: str,
system_prompt: str) -> Tuple[List[Dict[str, str]], str, Dict[str, Any]]:
try:
if model_key not in model_cache:
model_cache[model_key] = load_model(model_key)
pipe = model_cache[model_key]
print(f"🚀 Генерация: {model_key}, Msg='{message[:30]}...'")
messages = []
if system_prompt.strip():
messages.append({"role": "system", "content": system_prompt})
for msg in history:
messages.append({"role": msg["role"], "content": msg["content"]})
messages.append({"role": "user", "content": message})
tokenizer = pipe.tokenizer
# Используем чат-шаблон для Qwen моделей
try:
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
except Exception as e:
print(f"⚠️ Ошибка применения чат-шаблона: {e}")
# Альтернативный способ форматирования
prompt = ""
for msg in messages:
if msg["role"] == "system":
prompt += f"System: {msg['content']}\n\n"
elif msg["role"] == "user":
prompt += f"User: {msg['content']}\n\n"
elif msg["role"] == "assistant":
prompt += f"Assistant: {msg['content']}\n\n"
prompt += "Assistant:"
outputs = pipe(
prompt,
max_new_tokens=256, # Уменьшил для экономии памяти
do_sample=True,
temperature=0.7,
repetition_penalty=1.1
)
# Извлекаем ответ
generated_text = outputs[0]["generated_text"]
if generated_text.startswith(prompt):
bot_reply = generated_text[len(prompt):].strip()
else:
bot_reply = generated_text.strip()
print(f"✅ Ответ: {bot_reply[:50]}...")
new_history = history + [
{"role": "user", "content": message},
{"role": "assistant", "content": bot_reply}
]
return new_history, "", gr.update(value="")
except Exception as e:
error_msg = f"❌ {model_key}: {str(e)}"
print(f"💥 {error_msg}")
new_history = history + [
{"role": "user", "content": message},
{"role": "assistant", "content": error_msg}
]
return new_history, error_msg, gr.update(value="")
# Исправлено: убран параметр theme для совместимости со старой версией Gradio
with gr.Blocks(title="🚀 Локальный HF Чат (на слабом CPU!)") as demo:
gr.Markdown("""
# 🚀 Локальный Inference (без API!)
⚠️ **Внимание**: Модели загружаются при первом выборе и могут занять несколько минут! Работают на слабом CPU - запаситесь терпением.
""")
with gr.Row():
model_dropdown = gr.Dropdown(
choices=list(MODELS.keys()),
value="Qwen2.5-0.5B",
label="🧠 Модель",
info="Выберите модель (загрузка при первшем использовании)"
)
system_prompt = gr.Textbox(
label="📝 System Prompt",
placeholder="Ты весёлый и полезный ИИ-ассистент.",
lines=2,
value="Ты весёлый и полезный ИИ-ассистент."
)
chatbot = gr.Chatbot(
height=400,
label="Чат"
)
with gr.Row():
msg_input = gr.Textbox(
placeholder="Напишите сообщение... (Enter для отправки)",
show_label=False,
lines=2,
scale=4
)
send_btn = gr.Button("📤 Отправить", variant="primary", scale=1)
with gr.Row():
clear_btn = gr.Button("🗑️ Очистить историю", variant="secondary")
retry_btn = gr.Button("🔄 Повторить последнее", variant="secondary")
status = gr.Textbox(
label="Статус",
interactive=False,
lines=3,
placeholder="Здесь будут отображаться логи работы..."
)
# Обработчики событий
def clear_chat():
return [], "", gr.update(value="")
def retry_last(history: List[Dict[str, str]]):
if history:
last_user_msg = None
for msg in reversed(history):
if msg["role"] == "user":
last_user_msg = msg["content"]
break
return last_user_msg if last_user_msg else ""
return ""
# Привязка событий
send_btn.click(
fn=respond,
inputs=[msg_input, chatbot, model_dropdown, system_prompt],
outputs=[chatbot, status, msg_input]
)
msg_input.submit(
fn=respond,
inputs=[msg_input, chatbot, model_dropdown, system_prompt],
outputs=[chatbot, status, msg_input]
)
clear_btn.click(
fn=clear_chat,
outputs=[chatbot, status, msg_input]
)
retry_btn.click(
fn=retry_last,
inputs=[chatbot],
outputs=[msg_input]
)
# Информация о состоянии
gr.Markdown("""
### 💡 Советы:
1. Первая загрузка модели может занять 1-5 минут
2. Ответы генерируются на CPU, будьте терпеливы
3. Для более быстрых ответов используйте Qwen2.5-0.5B
4. Очищайте историю, если чат становится медленным
""")
if __name__ == "__main__":
print("=" * 50)
print("🚀 Запуск локального чат-бота на CPU")
print("=" * 50)
demo.queue(max_size=5).launch(
debug=False,
show_error=True,
server_name="0.0.0.0",
server_port=7860,
share=False # Отключаем share для локального использования
)