chatx / app.py
vlasdadsda's picture
Update app.py
428a486 verified
raw
history blame
35.7 kB
import asyncio
import sys
if sys.platform.startswith('win'):
# Используем более стабильную политику событий для Windows
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# Создаем новый цикл событий
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
import g4f
import gradio as gr
import tempfile
import os
from pathlib import Path
from g4f.client import Client, AsyncClient
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
import easyocr
import asyncio
AVAILABLE_MODELS = {
"GPT-4": "gpt-4",
"GPT-4 Turbo": "gpt-4-turbo",
"GPT-4o": "gpt-4o",
"GPT-4o THINK": "gpt-4o-think"
}
SYSTEM_PROMPT = """
1. Всегда используйте кодировку UTF-8
2. Используйте обработку ошибок
3. Если пользователь отправляет изображение или пишет чтото на подобие 'посмотри на изображение':
- Автоматически проанализируйте изображение
- Опишите что вы видите на русском языке
- Тебе дается текстовая информация, которая может быть полезна для анализа
4. Если пользователь просит нарисовать или сгенерировать изображение:
- Начните ответ с [GENERATE_IMAGE]
- Напишите детальный промпт на ангийском языке
- Завершите промпт строкой [/GENERATE_IMAGE]
- Продолжите обычный ответ на русском языке
5. В режиме размышления:
- Используйте [THINKING_STEP] для обозначения шага размышления
- Используйте [FINAL_ANSWER] для итогового ответа
- Старайтесь подробно описывать ход мыслей
"""
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 и текста через EasyOCR"""
try:
# Загружаем модель YOLOv8n
model = YOLO('yolov8n.pt')
# Инициализируем EasyOCR для русского и английского языков
reader = easyocr.Reader(['ru', 'en'])
# Обработка входного изображения
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 "[IMAGE]\n❌ Неподдерживаемый формат изображения\n[/IMAGE]"
# Конвертируем изображение в 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)
# Распознаем текст
text_results = reader.readtext(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)
# Собираем найденный текст
detected_text = []
for detection in text_results:
text = detection[1]
if text.strip(): # Проверяем, что текст не пустой
detected_text.append(text)
if not detected_objects and not detected_text:
return """
<div class="image-analysis-animation">
<div class="analysis-text">К сожалению, я не смог распознать объекты на этом изображении</div>
</div>
"""
# Формируем сообщение для GPT
prompt = "Я на этом изображении вижу "
if detected_objects:
objects_str = ", ".join(detected_objects)
prompt += f"следующие объекты: {objects_str}. "
if detected_text:
text_str = ", ".join(detected_text)
prompt += f"Также на изображении есть текст: {text_str}"
messages = [
{
"role": "system",
"content": """Ты - система компьютерного зрения.
Тебе нужно:
1. Перевести названия объектов на русский язык
2. Описать что ты видишь простыми словами
3. Всегда отвечать на русском языке
4. Если есть текст, упомянуть его в описании
5. Никогда не говори "Похоже,что у вас есть описание изображения..."
"""
},
{
"role": "user",
"content": prompt
}
]
response = g4f.ChatCompletion.create(
model="gpt-4o",
messages=messages
)
return response if isinstance(response, str) else prompt
except Exception as e:
return f"❌ Ошибка при обработке изображения: {str(e)}"
finally:
if 'tmp' in locals():
Path(tmp.name).unlink(missing_ok=True)
async def chat_response(message, history, model_name, direct_mode, thinking_depth=1.0, uploaded_file=None):
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
history = history or []
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": ""})
try:
if model_name == "GPT-4o THINK":
client = AsyncClient()
min_steps = 3
max_steps = 20
num_steps = int(min_steps + (max_steps - min_steps) * (thinking_depth / 10.0))
thinking_prompt = f"""Ты - система глубокого анализа.
СТРОГО СОБЛЮДАЙ ФОРМАТ:
1. Каждый шаг должен быть в отдельных тегах [THINKING_STEP]текст шага[/THINKING_STEP]
2. После ВСЕХ шагов размышления пиши [FINAL_ANSWER]итоговый ответ[/FINAL_ANSWER]
3. Не пиши ничего между тегами
4. Не используй теги внутри других тегов
5. Обязательно сделай {num_steps} шагов, не больше и не меньше
Глубина анализа: {thinking_depth:.1f}/10
Вопрос для анализа: {message}
"""
thinking_html = f"""
<div class="thinking-animation">
<div class="thinking-step">🤔 Начинаю анализ (глубина: {thinking_depth:.1f}, шагов: {num_steps})</div>
</div>
"""
history[-1]["content"] = thinking_html
yield history, *[gr.update(visible=False) for _ in range(6)]
try:
stream = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": thinking_prompt}],
stream=True
)
thinking_steps = []
current_text = ""
async for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
current_text += chunk.choices[0].delta.content
while "[THINKING_STEP]" in current_text and "[/THINKING_STEP]" in current_text:
start = current_text.find("[THINKING_STEP]")
end = current_text.find("[/THINKING_STEP]")
if start != -1 and end != -1:
step = current_text[start + len("[THINKING_STEP]"):end].strip()
if step and step not in thinking_steps:
thinking_steps.append(step)
thinking_html = f"""
<div class="thinking-animation">
<div class="thinking-step">🤔 Процесс размышления ({len(thinking_steps)}/{num_steps}):</div>
"""
for i, s in enumerate(thinking_steps, 1):
thinking_html += f'<div class="thinking-step">Шаг {i}: {s}</div>'
thinking_html += '</div>'
history[-1]["content"] = thinking_html
yield history, *[gr.update(visible=False) for _ in range(6)]
current_text = current_text[end + len("[/THINKING_STEP]"):]
if "[FINAL_ANSWER]" in current_text and "[/FINAL_ANSWER]" in current_text:
start = current_text.find("[FINAL_ANSWER]")
end = current_text.find("[/FINAL_ANSWER]")
final_answer = current_text[start + len("[FINAL_ANSWER]"):end].strip()
thinking_html = f"""
<div class="thinking-animation">
<div class="thinking-step">✨ Результат анализа (выполнено шагов: {len(thinking_steps)}/{num_steps}):</div>
"""
for i, step in enumerate(thinking_steps, 1):
thinking_html += f'<div class="thinking-step">Шаг {i}: {step}</div>'
thinking_html += f'<div class="thinking-conclusion">{final_answer}</div>'
thinking_html += '</div>'
history[-1]["content"] = thinking_html
yield history, *[gr.update(visible=False) for _ in range(6)]
break
except Exception as e:
history[-1]["content"] = f"❌ Ошибка при анализе: {str(e)}"
yield history, *[gr.update(visible=False) for _ in range(6)]
finally:
await client.close()
return
else:
# Обычный режим работы
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 and 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}")
if not history:
history = [{"role": "user", "content": message}, {"role": "assistant", "content": ""}]
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;
}
/* Добавляем анимацию для просмотра изображения */
.image-analysis-animation {
position: relative;
width: 100%;
min-height: 100px;
background: linear-gradient(45deg, #2d2d2d, #3d3d3d);
border-radius: 15px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
margin: 10px 0;
}
.analysis-text {
color: white;
font-size: 16px;
z-index: 2;
text-align: center;
animation: pulse 1.5s infinite;
}
.image-analysis-animation::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent 0%,
rgba(255,255,255,0.1) 50%,
transparent 100%);
animation: scanning 2s linear infinite;
}
@keyframes scanning {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.thinking-animation {
position: relative;
width: 100%;
min-height: 100px;
background: linear-gradient(45deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
overflow: hidden;
margin: 10px 0;
padding: 20px;
border-left: 4px solid #4a90e2;
transition: all 0.3s ease;
}
.thinking-animation:hover {
background: linear-gradient(45deg, #202020, #333333);
}
.thinking-step {
color: #b0b0b0;
font-style: italic;
margin-bottom: 10px;
padding-left: 20px;
border-left: 2px solid #4a90e2;
opacity: 0;
transform: translateY(10px);
animation: fadeInStep 0.5s ease-in-out forwards;
}
.thinking-conclusion {
color: white;
font-weight: bold;
margin-top: 15px;
padding: 10px;
background: rgba(74, 144, 226, 0.1);
border-radius: 8px;
border-left: 4px solid #4a90e2;
}
@keyframes fadeInStep {
to {
opacity: 1;
transform: translateY(0);
}
}
.typing-cursor {
display: inline-block;
width: 2px;
height: 15px;
background: #4a90e2;
margin-left: 5px;
animation: blink 1s infinite;
}
@keyframes blink {
50% { opacity: 0; }
}
/* Стили для слайдера глубины размышления */
.thinking-depth-slider {
margin-top: 10px;
padding: 8px;
background: rgba(74, 144, 226, 0.1);
border-radius: 8px;
border-left: 4px solid #4a90e2;
}
/* Индикатор глубины размышления в сообщении */
.thinking-depth-indicator {
font-size: 0.9em;
color: #4a90e2;
margin-bottom: 10px;
font-style: italic;
}
"""
# Добавте этот скрипт в create_interface()
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="Модель"
)
# Добавляем слайдер глубины размышления (изначально скрытый)
thinking_depth = gr.Slider(
minimum=0.1,
maximum=10.0,
value=1.0,
step=0.1,
label="Глубина размышления",
visible=False
)
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, thinking_depth, file_output],
outputs=[chatbot, output_text, error_text, ask_help_btn, current_code, analyze_btn, run_btn],
api_name=None
)
submit.click(
fn=chat_response,
inputs=[msg, chatbot, model, direct_mode, thinking_depth, file_output],
outputs=[chatbot, output_text, error_text, ask_help_btn, current_code, analyze_btn, run_btn],
api_name=None
)
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]
)
# Добавляем обработчик изменения модели
def update_thinking_depth_visibility(model_name):
return gr.update(visible=model_name == "GPT-4o THINK")
model.change(
fn=update_thinking_depth_visibility,
inputs=[model],
outputs=[thinking_depth]
)
return demo
if __name__ == "__main__":
demo = create_interface()
try:
demo.launch(
server_name="127.0.0.1", # Явно указываем хост
server_port=7860, # Явно указываем порт
show_api=False,
show_error=True,
debug=True
)
except Exception as e:
print(f"Ошибка запуска: {e}")
finally:
# Закрываем цикл событий
loop.close()