chatx / app.py
vlasdadsda's picture
Update app.py
ee02959 verified
raw
history blame
25.2 kB
import g4f
import gradio as gr
import tempfile
import os
from pathlib import Path
from g4f.client import Client
from PIL import Image
import io
import requests
import numpy as np
from ultralytics import YOLO
import subprocess
import sys
import time
from typing import Dict, Any, Optional
AVAILABLE_MODELS = {
"GPT-4": "gpt-4",
"GPT-4 Turbo": "gpt-4-turbo",
"GPT-4o": "gpt-4o",
}
SYSTEM_PROMPT = """
1. Всегда используйте кодировку UTF-8
2. Используйте обработку ошибок
3. Если пользователь просит нарисовать или сгенерировать изображение:
- Начните ответ с [GENERATE_IMAGE]
- Напишите детальный промпт на английском языке
- Завершите промпт строкой [/GENERATE_IMAGE]
- Продолжите обычный ответ на русском языке
"""
def test_code(code: str, file_type: str = ".py") -> Dict[str, Any]:
"""Тестирование кода в безопасной среде"""
start_time = time.time()
result = {
"success": False,
"output": "",
"error": "",
"execution_time": 0
}
try:
code = "# -*- coding: utf-8 -*-\n" + code
with tempfile.NamedTemporaryFile(suffix=file_type, mode='w', encoding='utf-8', delete=False) as tmp:
tmp.write(code)
tmp_path = tmp.name
process = subprocess.Popen(
[sys.executable, tmp_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8'
)
try:
stdout, stderr = process.communicate(timeout=10)
result["success"] = process.returncode == 0
result["output"] = stdout
result["error"] = stderr
except subprocess.TimeoutExpired:
process.kill()
result["error"] = "Превышено время выполнения (10 сек)"
finally:
os.unlink(tmp_path)
except Exception as e:
result["error"] = str(e)
result["execution_time"] = time.time() - start_time
return result
def process_file(file):
"""Обработка загруженного файла"""
if not file:
return None
try:
# Получаем расширение файла
file_extension = file.name.lower().split('.')[-1] if hasattr(file, 'name') else ''
# Список поддерживаемых форматов изображений
image_extensions = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'}
# Если это изображение
if file_extension in image_extensions:
try:
# Открываем изображение
if isinstance(file, str):
image = Image.open(file)
else:
image = Image.open(io.BytesIO(file.read()))
# Анализируем изображение
return process_image(image)
except Exception as e:
return f"[Ошибка обработки изображения: {str(e)}]"
# Если это текстовый файл
if isinstance(file, str):
with open(file, 'r', encoding='utf-8') as f:
return f.read()
else:
return file.read().decode('utf-8')
except UnicodeDecodeError:
return "[Бинарный файл]"
except Exception as e:
return f"[Ошибка чтения файла: {str(e)}]"
def process_audio(file_path: str, operation: str) -> Optional[str]:
"""Обработка аудио файлов"""
try:
from pydub import AudioSegment
audio = AudioSegment.from_file(file_path)
if "громкость" in operation.lower():
audio = audio + 10
output_path = os.path.join(tempfile.gettempdir(), f"processed_{int(time.time())}.mp3")
audio.export(output_path, format="mp3")
return output_path
except Exception as e:
return f"Ошибка обработки аудио: {str(e)}"
def generate_image(prompt: str) -> str:
"""Генерация изображения через g4f"""
try:
client = Client()
response = client.images.generate(
model="flux",
prompt=prompt,
response_format="url"
)
return response.data[0].url
except Exception as e:
return f"Ошибка при генерации изобраения: {str(e)}"
def process_image(image_input) -> str:
"""Обработка изображения и распознавание объектов через YOLOv8"""
try:
# Загружаем модель YOLOv8n
model = YOLO('yolov11x.pt')
# Если передан URL
if isinstance(image_input, str):
response = requests.get(image_input)
image = Image.open(io.BytesIO(response.content))
# Если передан объект изображения
elif isinstance(image_input, Image.Image):
image = image_input
else:
return "❌ Неподдерживаемый формат изображения"
# Конвертируем изображение в RGB если оно в RGBA
if image.mode == 'RGBA':
image = image.convert('RGB')
# Сохраняем изображение во временный файл для обработки
with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp:
image.save(tmp.name, format='JPEG')
# Запускаем распознавание
results = model(tmp.name)
# Собираем найденные объекты
detected_objects = []
for r in results:
for box in r.boxes:
class_id = int(box.cls)
class_name = model.names[class_id]
detected_objects.append(class_name)
if not detected_objects:
return "Я ничего не вижу на этом изображении."
# Переводим объекты на русский
objects_str = ", ".join(detected_objects)
messages = [
{
"role": "system",
"content": """Ты - система компьютерного зрения.
Тебе нужно:
1. Перевести названия объектов на русский язык
2. Описать что ты видишь простыми словами
3. Всегда отвечать на русском языке
4. Начинать ответ со слов "Я на этом изображении вижу..."
5. Никогда не говри "Похоже,что у вас есть описание изображения..."
"""
},
{
"role": "user",
"content": f"Переведи и опиши эти объекты: {objects_str}"
}
]
response = g4f.ChatCompletion.create(
model="gpt-4o",
messages=messages,
# provider=g4f.Provider.Airforce
)
# Сохраняем результат в истории чата
if isinstance(response, str):
return response
elif isinstance(response, dict) and "content" in response:
return response["content"]
else:
# Если что-то пошло не так, хотя бы покажем список объектов
return f"Я на этом изображении вижу: {objects_str}"
except Exception as e:
return f"❌ Ошибка при обработке изображения: {str(e)}"
finally:
if 'tmp' in locals():
Path(tmp.name).unlink(missing_ok=True)
def chat_response(message, history, model_name, direct_mode, uploaded_file=None):
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
history = history or []
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": ""})
print(f"Получено сообщение: {message}")
print(f"Модель: {model_name}")
print(f"Прямая генерация: {direct_mode}")
print(f"Загруженный файл: {uploaded_file}")
try:
if direct_mode:
# Прямая отправка в нейронку для генерации изображения
image_url = generate_image(message)
if not image_url.startswith("Ошибка"):
# Анализируем изображение на наличие текста
image_analysis = process_image(image_url)
history[-1]["content"] = f"![Generated Image]({image_url})\n\n{image_analysis}"
else:
history[-1]["content"] = f"��� {image_url}"
yield history, *[gr.update(visible=False) for _ in range(6)]
return
# Начальные значения
yield (
history,
gr.update(visible=False),
gr.update(visible=False),
gr.update(visible=False),
"",
gr.update(visible=False),
gr.update(visible=False)
)
if uploaded_file:
file_content = process_file(uploaded_file)
if file_content:
message = f"Файл содержит:\n```\n{file_content}\n```\n\n{message}"
# Формируем историю сообщений
for msg in history[:-2]:
messages.append({"role": msg["role"], "content": msg["content"]})
messages.append({"role": "user", "content": str(message)})
partial_message = ""
code_block = None
response = g4f.ChatCompletion.create(
model=AVAILABLE_MODELS.get(model_name, "gpt-4o"),
messages=messages,
stream=True,
provider=g4f.Provider.Airforce
)
for chunk in response:
if chunk:
if isinstance(chunk, str):
partial_message += chunk
# Проверяем на запрос генерации изображения
if "[GENERATE_IMAGE]" in partial_message and "[/GENERATE_IMAGE]" in partial_message:
start_idx = partial_message.find("[GENERATE_IMAGE]") + len("[GENERATE_IMAGE]")
end_idx = partial_message.find("[/GENERATE_IMAGE]")
image_prompt = partial_message[start_idx:end_idx].strip()
# Показываем статус генерации
history[-1]["content"] = """
<div class="generating-animation">
<div class="generating-text">Генерация изображения...</div>
</div>
"""
yield history, *[gr.update(visible=False) for _ in range(6)]
# Генерируем изображение
image_url = generate_image(image_prompt)
if not image_url.startswith("Ошибка"):
# Анализируем изображение на наличие текста
image_analysis = process_image(image_url)
explanation_text = partial_message[end_idx + len("[/GENERATE_IMAGE]"):].strip()
partial_message = f"![Generated Image]({image_url})\n\n{image_analysis}\n\n{explanation_text}"
else:
partial_message = f"❌ {image_url}"
history[-1]["content"] = partial_message + "▓"
yield history, *[gr.update(visible=False) for _ in range(6)]
# Проверяем наличие кода
if "```" in partial_message:
code_start = partial_message.rfind("```") + 3
code_end = partial_message.find("```", code_start)
if code_end != -1:
code_block = partial_message[code_start:code_end].strip()
# В конце убираем курсор
history[-1]["content"] = partial_message
yield history, *[gr.update(visible=True if code_block else False) for _ in range(6)]
except Exception as e:
print(f"Error: {e}")
history[-1]["content"] = f"❌ Произошла ошибка: {str(e)}"
yield (
history,
gr.update(visible=False),
gr.update(visible=True, value=str(e)),
gr.update(visible=True),
"",
gr.update(visible=False),
gr.update(visible=False)
)
def analyze_code(code):
"""Анализ кода и получение объяснения"""
if not code:
return [{"role": "assistant", "content": "❌ Нет кода для анализа"}]
prompt = f"""Проанализируй этот код и объясни:
1. Что он делает
2. Возможные проблемы или ошибки
3. Как можно улучшить
4. Примеры использования
Код:
```
{code}
```"""
try:
response = g4f.ChatCompletion.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
stream=False
)
return [{"role": "assistant", "content": response if isinstance(response, str) else "Не удалось получить анализ"}]
except Exception as e:
return [{"role": "assistant", "content": f"❌ Ошибка при анализе: {str(e)}"}]
def create_interface():
# Обновляем тему на темную
theme = gr.themes.Soft(
primary_hue="slate",
secondary_hue="gray",
).set(
body_background_fill="#1a1a1a",
body_text_color="#ffffff",
button_primary_background_fill="#2d2d2d",
button_primary_background_fill_hover="#3d3d3d",
button_primary_text_color="white",
block_label_background_fill="#2d2d2d",
block_title_text_color="#ffffff",
input_background_fill="#2d2d2d",
)
# Обновляем CSS стили для управления цветом кода
css = """
.gradio-container {
background-color: #1a1a1a !important;
}
.chatbot {
background-color: #2d2d2d !important;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
}
.message.user {
background-color: #3d3d3d !important;
color: white !important;
border-radius: 15px;
}
.message.bot {
background-color: #2d2d2d !important;
color: white !important;
border-radius: 15px;
position: relative;
transition: all 0.3s ease;
}
/* Добавляем стиль для блоков кода */
.message.bot pre {
background-color: #1a1a1a !important;
border-radius: 8px;
padding: 10px;
}
.message.bot.typing::after {
content: '|';
animation: cursor 1s infinite;
}
@keyframes cursor {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
.message.bot:last-child {
animation: fadeIn 0.3s ease-in-out;
}
/* Убираем дублирующиеся стили курсора */
.message.bot:last-child:not(:empty)::after {
content: '';
}
/* Анимация появления текста */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes cursor {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
.footer {
display: none !important;
}
.generating-animation {
position: relative;
width: 100%;
height: 120px;
background: linear-gradient(45deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.generating-text {
color: white;
font-size: 16px;
z-index: 2;
animation: pulse 1.5s infinite;
}
.generating-animation::before {
content: '';
position: absolute;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
background:
radial-gradient(2px 2px at 20% 30%, rgba(255,255,255,0.8), rgba(0,0,0,0)),
radial-gradient(2px 2px at 40% 70%, rgba(255,255,255,0.8), rgba(0,0,0,0)),
radial-gradient(2px 2px at 50% 40%, rgba(255,255,255,0.8), rgba(0,0,0,0)),
radial-gradient(2px 2px at 60% 60%, rgba(255,255,255,0.8), rgba(0,0,0,0));
background-repeat: repeat;
animation: rotate 8s linear infinite;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; }
100% { opacity: 0.6; }
}
.submit-btn {
min-width: 100px !important;
cursor: pointer !important;
background-color: #4a4a4a !important;
transition: all 0.2s ease;
}
.submit-btn:hover {
background-color: #5a5a5a !important;
}
.input-row {
gap: 8px;
padding: 8px;
background: #2d2d2d;
border-radius: 8px;
margin-top: 8px;
}
.footer {
display: none !important;
}
"""
with gr.Blocks(theme=theme, css=css) as demo:
# gr.Markdown("# 💬 AI Chat Assistant")
current_code = gr.State("")
with gr.Row():
with gr.Column(scale=4):
chatbot = gr.Chatbot(
height="600px",
show_label=False,
container=True,
show_copy_button=True,
elem_classes="chatbot",
type="messages",
render_markdown=True
)
# Добавляем компоненты для вывода
output_text = gr.Textbox(
label="Вывод",
interactive=False,
visible=False
)
error_text = gr.Textbox(
label="⚠️ Ошибки",
interactive=False,
visible=False
)
ask_help_btn = gr.Button(
"❓ Спросить почему возникла ошибка",
visible=False
)
with gr.Row(elem_classes="input-row"):
msg = gr.Textbox(
placeholder="Спросите что-нибудь...",
container=False,
scale=4,
show_label=False,
lines=1, # Явно указываем одну строку
elem_classes="input-textbox"
)
submit = gr.Button(
"Отправить",
variant="primary",
scale=1,
elem_classes="submit-btn"
)
clear = gr.Button("Очистить", scale=1)
with gr.Column(scale=1, visible=True) as sidebar:
model = gr.Dropdown(
choices=list(AVAILABLE_MODELS.keys()),
value="GPT-4o",
label="Модель"
)
direct_mode = gr.Checkbox(
label="Прямая генерация (без обрботки прмпта)",
value=False
)
file_output = gr.File(label="Загрузить файл")
# Добавляем примеры ипользования в виде кнопок
# Добавляем кнопки анализа и запуска кода
analyze_btn = gr.Button(
"Анализировать",
visible=False,
elem_classes="analyze-btn"
)
run_btn = gr.Button(
"▶️ Запустить код",
visible=False,
elem_classes="run-btn"
)
def run_code(code):
if not code:
return {
output_text: gr.update(value=" Нет кода для выполнения", visible=True),
error_text: gr.update(visible=False),
ask_help_btn: gr.update(visible=False)
}
result = test_code(code)
return {
output_text: gr.update(value=result["output"] if result["success"] else "", visible=True),
error_text: gr.update(value=result["error"], visible=bool(result["error"])),
# ask_help_btn: gr.update(visible=bool(result["error"]))
}
def handle_error_question(error_message, code_block):
"""Обработчик кнопки помощи с ошибкой"""
error_prompt = f"""Объясните ошибку и как её исправить:
Код:
```
{code_block}
```
Ошибка:
{error_message}"""
try:
response = g4f.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": error_prompt}],
stream=False
)
return [{"role": "assistant", "content": response if isinstance(response, str) else "Не удалось получиь ответ"}]
except Exception as e:
return [{"role": "assistant", "content": f"Ошибка при получнии объяснения: {str(e)}"}]
# Обработчики событий
msg.submit(
fn=chat_response,
inputs=[msg, chatbot, model, direct_mode, file_output],
outputs=[chatbot, output_text, error_text, ask_help_btn, current_code, analyze_btn, run_btn],
api_name=None, # Изменим с False на None
show_progress=True
).then(
fn=lambda: gr.update(value=""),
outputs=[msg]
)
submit.click(
fn=chat_response,
inputs=[msg, chatbot, model, direct_mode, file_output],
outputs=[chatbot, output_text, error_text, ask_help_btn, current_code, analyze_btn, run_btn],
api_name=None, # Изменим с False на None
show_progress=True
).then(
fn=lambda: gr.update(value=""),
outputs=[msg]
)
ask_help_btn.click(
fn=handle_error_question,
inputs=[error_text, current_code],
outputs=chatbot
)
analyze_btn.click(
fn=analyze_code,
inputs=[current_code],
outputs=[chatbot]
)
run_btn.click(
fn=run_code,
inputs=[current_code],
outputs=[output_text, error_text, ask_help_btn]
)
clear.click(
fn=lambda: (None, "", "", False, ""),
outputs=[chatbot, output_text, error_text, ask_help_btn, current_code]
)
return demo
if __name__ == "__main__":
demo = create_interface()
# Запускаем мониторинг изменений в тдельном потоке
demo.launch(
show_api=False,
show_error=True,
favicon_path=None,
auth=None,
# quiet=True, # Добавим этот параметр
)