Spaces:
Sleeping
Sleeping
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"\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"\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, # Добавим этот параметр | |
) | |