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