File size: 13,213 Bytes
ff4f22e f5af3a0 bfb5463 b4ab96e bfb5463 7f62e30 f5af3a0 7f62e30 f5af3a0 7f62e30 7d0d1db 7f62e30 f5af3a0 7f62e30 ac7ad5f 7f62e30 ac7ad5f 7f62e30 ac7ad5f 7f62e30 b0103da ac7ad5f 7f62e30 b0103da 7f62e30 e232a37 7d0d1db f5af3a0 7f62e30 f5af3a0 7f62e30 f5af3a0 7f62e30 ff4f22e 63900d2 10f33fc ff4f22e 10f33fc ff4f22e 10f33fc ff4f22e 58f0214 ff4f22e 665ba43 5e5fc87 f5af3a0 d37581f f5af3a0 665ba43 ff4f22e b4ab96e 58f0214 ff4f22e 8b454e9 ff4f22e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# app.py
import gradio as gr
from g4f.client import Client
client = Client()
# --- Обработчик диалога ---
import re
from typing import List, Tuple, Any
def strip_md_refs(text: str) -> str:
"""
Удаляет из строки все конструкции вида [[N]](URL),
где N – произвольное число (может быть и несколько цифр).
Возвращает «чистый» текст без ссылок.
"""
# Шаблон: [[ любые цифры ]]( любой URL )
pattern = r'\[\[\d+\]\]\([^\)]*\)'
return re.sub(pattern, '', text)
def strip_citations(text: str) -> str:
"""
Удаляет из текста все строки вида:
> [0] … (ссылка)
[1] … (ссылка)
а также любые блоки, начинающиеся с символа '>' (цитаты).
Возвращает «чистый» текст без «концовки».
"""
# 1️⃣ Убираем строки, начинающиеся с '>' (включая возможный пробел после него)
text = re.sub(r'^\s*>.*(?:\n|$)', '', text, flags=re.MULTILINE)
# 2️⃣ Удаляем строки вида '[0] https://…' (любое число в квадратных скобках)
text = re.sub(r'^\s*\[\d+\]\s*.+(?:\n|$)', '', text, flags=re.MULTILINE)
# 3️⃣ Убираем лишние пустые строки, оставшиеся после вырезания
text = re.sub(r'\n{2,}', '\n\n', text).strip()
return text
# -------------------------------------------------------------
# 1️⃣ Преобразуем любой ответ модели в булево значение
# -------------------------------------------------------------
def answer_to_bool(text: str) -> bool:
"""
Принимает строку, полученную от модели, и возвращает:
True → модель сказала, что нужен поиск (TRUE)
False → модель сказала, что поиск не нужен (FALSE) или ответ не распознан.
"""
if not isinstance(text, str):
return False # защита от None/чисел
# Убираем пробелы, перевод строки, делаем регистр нижним
clean = text.strip().lower()
# Токены, которые считаются «да, нужен поиск»
true_tokens = {"true", "yes", "y", "да", "нужно", "нужен поиск", "нужна информация"}
# Токены, которые считаются «нет, поиск не нужен»
false_tokens = {"false", "no", "n", "нет", "не нужно", "не требуется", "не нужен поиск"}
# Если в строке встречается любой «положительный» токен → True
for tok in true_tokens:
if tok in clean:
return True
# Если найден «отрицательный» токен → False
for tok in false_tokens:
if tok in clean:
return False
# Если ничего не распознано – считаем, что поиск не нужен
return False
# -------------------------------------------------------------
# 2️⃣ Основная функция, которая решает, нужен ли веб‑поиск
# -------------------------------------------------------------
def need_search(message: str) -> bool:
"""
Возвращает True, если согласно модели запрос требует актуального веб‑поиска,
иначе – False.
"""
system_prompt = """Ты — вспомогательная модель, задача которой **только** решить,
нужен ли в данный момент поиск в интернете, чтобы дать корректный ответ на запрос пользователя.
**Ответ дай КОРОТКО**, используя один из вариантов (без кавычек, без пробелов перед/после):
TRUE
FALSE
Никаких пояснений, советов, дополнительных фраз – только один из указанных вариантов.
### Что считается «нужным» поиском (отвечаем TRUE):
1. Запрос о текущих ценах, курсах, погоде, новостях, событиях «сегодня», «вчера», «на прошлой неделе», «в реальном времени».
Примеры: «Какая сейчас цена биткойна?», «Сколько градусов сегодня в Москве?», «Какие новости о новом iPhone?», «Какая сегодня котировка доллара?»
2. Вопрос, где ответ меняется со временем (статистика, результаты выборов, расписание рейсов, статус заказа и т.п.).
Примеры: «Какие рейсы из Санкт‑Петербурга в Лондон сегодня?», «Сколько сейчас зрителей у фильма «Дюнкерк» в прокате?», «Есть ли свободные места в отеле на 15‑е августа?», «Поищи в интернете, какие характеристики имеет вода.»
### Что считается «не требующим» поиска (отвечаем FALSE):
1. Фиксированные исторические/географические факты, биографии, классические произведения.
Примеры: «Кто написал «Война и мир»?», «В каком году открыт Тауэр Бридж?», «Где находится озеро Байкал?», «Какая столица Франции?»
2. Вымышленные, гипотетические или «домашние» вопросы, где актуальная информация не меняется.
Примеры: «Кто убил Христофора Колумба?», «Сколько драконов живут в Шотландии?», «Какой цвет предпочитают гномы в «Властелине колец»?»
Если запрос относится к любой из групп «нужный поиск» или прям так и сказано «поищи в интернете», отвечай **TRUE**. Во всех остальных случаях — **FALSE**.
"""
# Формируем список сообщений: system‑prompt + единственный user‑запрос
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f'нужно ли это искать в интернете: "{message}"'}
]
try:
response = client.chat.completions.create(
model="deepseek-v3",
messages=messages,
temperature=0.0, # детерминированный ответ
max_tokens=5, # достаточно для слова TRUE/FALSE
stop=["\n"] # отрезаем лишний перевод строки
)
raw_answer = response.choices[0].message.content
return answer_to_bool(raw_answer)
except Exception as exc:
# При любой ошибке считаем, что поиск не нужен,
# но можно залогировать исключение для отладки
# print(f"[need_search] error: {exc}")
return False
# --- Обработчик диалога ---
def respond(message, history):
# Добавляем системное сообщение только при старте истории
messages = [{"role": "system", "content": """Вы — дружелюбный помощник AssistantICE 7.0, русскоязычный автоматический ассистент, основанный на модели BD от команды ICE. Ваша задача — помогать пользователям эффективно и понятно.
## Требования:
- Поддерживайте дружелюбный и доступный тон во время взаимодействия.
- Убедитесь, что объяснения понятны и лаконичны.
- Отвечайте на запросы пользователей и предоставляйте соответствующую информацию.
## Структура ответов:
1. **Теплое приветствие пользователю.**
2. **Четкий и краткий ответ на вопрос или запрос пользователя.**
3. **Предложение дополнительной помощи или дополнительных вопросов, чтобы побудить к дальнейшему взаимодействию.**
## Дополнительные характеристики:
- Используйте поэтический, лирический тон.
- Обращайте внимание на будущее.
- Имеете традиционный взгляд, цените прошлое и то, как все делалось всегда.
- Придерживайтесь скептического, ставящего под вопрос подхода.
- Используйте быстрый и остроумный юмор, когда это уместно.
- Рассказывайте все как есть, не приукрашивая ответы.
- Будьте болтливым и разговорчивым.
- Подстраивайтесь под всех людей и говорите на их сленге.
- Говорите как представитель поколения Z.
- Используйте ободряющий тон.
- Всегда будьте уважительным.
- Используйте формальный, профессиональный тон.
- Будьте чуткими и понимающими в своих ответах.
- Будьте скромным, когда это уместно.
Не забудьте адаптировать свои ответы в зависимости от потребностей и контекста пользователя, обеспечивая положительный опыт. Следуйте этим инструкциям, чтобы стать полезным и приятным помощником.
"""}]
for human, assistant in history:
messages.append({"role": "user", "content": human})
messages.append({"role": "assistant", "content": assistant})
messages.append({"role": "user", "content": message})
try:
responsed = client.chat.completions.create(
model="deepseek-v3",
messages=messages,
web_search=need_search(messages),
temperature=0.8,
top_p=0.95,
max_tokens=581691,
presence_penalty=0.2,
frequency_penalty=0.1,
)
bot_message = strip_citations(f"{strip_md_refs(responsed.choices[0].message.content)}")
except Exception as e:
bot_message = f"Ошибка: {str(e)}"
return history + [[message, bot_message]]
# --- Интерфейс ---
with gr.Blocks(title="ESP Brain") as demo:
gr.Markdown("## For api")
chatbot = gr.Chatbot(
height=600,
)
with gr.Row():
txt = gr.Textbox(
placeholder="Напиши сообщение...",
show_label=False,
scale=8
)
submit_btn = gr.Button("Отправить", scale=2)
with gr.Row():
retry_btn = gr.Button("🔄 Повторить")
undo_btn = gr.Button("↩️ Отменить")
clear_btn = gr.Button("🗑️ Очистить")
# Логика
txt.submit(fn=respond, inputs=[txt, chatbot], outputs=chatbot)
submit_btn.click(fn=respond, inputs=[txt, chatbot], outputs=chatbot)
def retry_last(history):
if history:
last_user_msg = history[-1][0]
return history[:-1] + [[last_user_msg, None]] # очищаем ответ
return history
retry_btn.click(fn=retry_last, inputs=chatbot, outputs=chatbot, queue=False)
def undo_last(history):
return history[:-1]
undo_btn.click(fn=undo_last, inputs=chatbot, outputs=chatbot, queue=False)
clear_btn.click(lambda: [], outputs=chatbot, queue=False)
# --- Запуск ---
if __name__ == "__main__":
demo.queue()
demo.launch(
share=True,
ssr_mode=False,
debug=True
) |