Update app/main.py
Browse files- app/main.py +46 -56
app/main.py
CHANGED
|
@@ -66,10 +66,10 @@ def append_feedback_row(category: str, rating: int, contact: str, feedback_text:
|
|
| 66 |
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 67 |
with FEEDBACK_CSV.open("a", newline="", encoding="utf-8") as f:
|
| 68 |
w = csv.writer(f)
|
| 69 |
-
w.writerow([ts, category, rating, contact.strip(), feedback_text.strip()])
|
| 70 |
|
| 71 |
|
| 72 |
-
# --- UI logic ---
|
| 73 |
def save_feedback(category: str, rating: int, contact: str, feedback_text: str):
|
| 74 |
if not feedback_text or not feedback_text.strip():
|
| 75 |
return "⚠️ Введите текст обратной связи.", gr.update(value=feedback_text), None
|
|
@@ -96,7 +96,7 @@ def save_feedback(category: str, rating: int, contact: str, feedback_text: str):
|
|
| 96 |
status += f"Файл: `{FEEDBACK_CSV.as_posix()}`\n\n"
|
| 97 |
status += ("✅ " if tg_ok else "⚠️ ") + tg_details
|
| 98 |
|
| 99 |
-
# очистим поле текста + выдадим файл (чтобы сразу можно было скачать
|
| 100 |
return status, gr.update(value=""), str(FEEDBACK_CSV)
|
| 101 |
|
| 102 |
|
|
@@ -106,24 +106,41 @@ def get_feedback_csv() -> Tuple[Optional[str], str]:
|
|
| 106 |
return None, "⚠️ Файл ещё не создан или пуст."
|
| 107 |
|
| 108 |
|
| 109 |
-
# --- Messenger logic
|
| 110 |
-
def messenger_reply(user_message: str, history
|
| 111 |
"""
|
| 112 |
-
|
| 113 |
-
|
| 114 |
"""
|
| 115 |
-
history = history or []
|
| 116 |
-
|
| 117 |
msg = (user_message or "").strip()
|
| 118 |
if not msg:
|
| 119 |
return "", history
|
| 120 |
|
| 121 |
-
history
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
return "", history
|
| 125 |
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
def build_interface():
|
| 128 |
ensure_feedback_csv_exists()
|
| 129 |
|
|
@@ -131,33 +148,29 @@ def build_interface():
|
|
| 131 |
gr.Markdown("# 2MOOD AI Workspace")
|
| 132 |
gr.Markdown("База знаний + Messenger + Обратная связь")
|
| 133 |
|
|
|
|
| 134 |
with gr.Tab("📚 База знаний"):
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
pdf_file = gr.File(label="Загрузить PDF")
|
| 138 |
-
add_btn = gr.Button("Добавить в базу", variant="primary")
|
| 139 |
-
status = gr.Markdown()
|
| 140 |
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
|
| 145 |
-
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
| 147 |
|
| 148 |
-
|
| 149 |
-
fn=index_pdf,
|
| 150 |
-
inputs=pdf_file,
|
| 151 |
-
outputs=status
|
| 152 |
-
)
|
| 153 |
with gr.Tab("💬 2MOOD Messenger"):
|
| 154 |
-
|
| 155 |
-
chat = gr.Chatbot(height=420)
|
| 156 |
msg = gr.Textbox(label="Сообщение", placeholder="Напишите сообщение…")
|
| 157 |
send = gr.Button("Отправить", variant="primary")
|
| 158 |
|
| 159 |
send.click(messenger_reply, inputs=[msg, chat], outputs=[msg, chat])
|
| 160 |
|
|
|
|
| 161 |
with gr.Tab("📝 Обратная связь"):
|
| 162 |
category = gr.Dropdown(
|
| 163 |
label="Категория",
|
|
@@ -179,20 +192,18 @@ def build_interface():
|
|
| 179 |
)
|
| 180 |
|
| 181 |
submit = gr.Button("Отправить", variant="primary")
|
| 182 |
-
|
| 183 |
|
| 184 |
-
# Кнопка скачивания
|
| 185 |
download_btn = gr.Button("📥 Скачать все отзывы")
|
| 186 |
download_file = gr.File(label="Файл с отзывами", interactive=False)
|
| 187 |
download_status = gr.Markdown()
|
| 188 |
|
| 189 |
-
# Покажем текущий путь
|
| 190 |
gr.Markdown(f"Файл логов: `{FEEDBACK_CSV.as_posix()}`")
|
| 191 |
|
| 192 |
submit.click(
|
| 193 |
save_feedback,
|
| 194 |
inputs=[category, rating, contact, feedback_text],
|
| 195 |
-
outputs=[
|
| 196 |
)
|
| 197 |
|
| 198 |
download_btn.click(
|
|
@@ -204,13 +215,8 @@ def build_interface():
|
|
| 204 |
return demo
|
| 205 |
|
| 206 |
|
|
|
|
| 207 |
def launch_with_port_fallback(demo: gr.Blocks):
|
| 208 |
-
"""
|
| 209 |
-
Устойчивый запуск:
|
| 210 |
-
- сначала локально (127.0.0.1, share=False)
|
| 211 |
-
- если Gradio считает, что localhost недоступен (proxy/настройки) -> fallback share=True
|
| 212 |
-
"""
|
| 213 |
-
# Частая причина "localhost is not accessible" — прокси/NO_PROXY
|
| 214 |
os.environ.setdefault("NO_PROXY", "localhost,127.0.0.1")
|
| 215 |
os.environ.setdefault("no_proxy", "localhost,127.0.0.1")
|
| 216 |
|
|
@@ -222,37 +228,21 @@ def launch_with_port_fallback(demo: gr.Blocks):
|
|
| 222 |
ports.extend([7860] + list(range(7861, 7871)))
|
| 223 |
|
| 224 |
last_error: Optional[Exception] = None
|
| 225 |
-
|
| 226 |
for port in ports:
|
| 227 |
-
# 1) Локальная попытка
|
| 228 |
try:
|
| 229 |
-
demo.launch(
|
| 230 |
-
server_name="127.0.0.1",
|
| 231 |
-
server_port=port,
|
| 232 |
-
share=False,
|
| 233 |
-
inbrowser=True,
|
| 234 |
-
)
|
| 235 |
return
|
| 236 |
except Exception as e:
|
| 237 |
last_error = e
|
| 238 |
msg = str(e)
|
| 239 |
-
|
| 240 |
-
# 2) Fallback: если localhost недоступен по мнению Gradio
|
| 241 |
if "localhost is not accessible" in msg or "shareable link must be created" in msg:
|
| 242 |
try:
|
| 243 |
-
demo.launch(
|
| 244 |
-
server_name="0.0.0.0",
|
| 245 |
-
server_port=port,
|
| 246 |
-
share=True,
|
| 247 |
-
inbrowser=False,
|
| 248 |
-
)
|
| 249 |
return
|
| 250 |
except Exception as e2:
|
| 251 |
last_error = e2
|
| 252 |
continue
|
| 253 |
|
| 254 |
-
continue
|
| 255 |
-
|
| 256 |
raise RuntimeError(f"Не удалось запустить Gradio ни на одном порту. Последняя ошибка: {last_error}")
|
| 257 |
|
| 258 |
|
|
|
|
| 66 |
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 67 |
with FEEDBACK_CSV.open("a", newline="", encoding="utf-8") as f:
|
| 68 |
w = csv.writer(f)
|
| 69 |
+
w.writerow([ts, category, rating, (contact or "").strip(), (feedback_text or "").strip()])
|
| 70 |
|
| 71 |
|
| 72 |
+
# --- UI logic: feedback ---
|
| 73 |
def save_feedback(category: str, rating: int, contact: str, feedback_text: str):
|
| 74 |
if not feedback_text or not feedback_text.strip():
|
| 75 |
return "⚠️ Введите текст обратной связи.", gr.update(value=feedback_text), None
|
|
|
|
| 96 |
status += f"Файл: `{FEEDBACK_CSV.as_posix()}`\n\n"
|
| 97 |
status += ("✅ " if tg_ok else "⚠️ ") + tg_details
|
| 98 |
|
| 99 |
+
# очистим поле текста + выдадим файл (чтобы сразу можно было скачать)
|
| 100 |
return status, gr.update(value=""), str(FEEDBACK_CSV)
|
| 101 |
|
| 102 |
|
|
|
|
| 106 |
return None, "⚠️ Файл ещё не создан или пуст."
|
| 107 |
|
| 108 |
|
| 109 |
+
# --- Messenger logic ---
|
| 110 |
+
def messenger_reply(user_message: str, history):
|
| 111 |
"""
|
| 112 |
+
Универсально: работаем как с history=None, так и с любым форматом.
|
| 113 |
+
Для простоты добавим пары (user, assistant).
|
| 114 |
"""
|
|
|
|
|
|
|
| 115 |
msg = (user_message or "").strip()
|
| 116 |
if not msg:
|
| 117 |
return "", history
|
| 118 |
|
| 119 |
+
if history is None:
|
| 120 |
+
history = []
|
| 121 |
+
|
| 122 |
+
# Gradio Chatbot обычно хранит list[tuple[str,str]] для старого формата
|
| 123 |
+
try:
|
| 124 |
+
history.append((msg, f"Echo: {msg}"))
|
| 125 |
+
except Exception:
|
| 126 |
+
# fallback на список словарей (если вдруг другой формат)
|
| 127 |
+
if isinstance(history, list):
|
| 128 |
+
history.append({"role": "user", "content": msg})
|
| 129 |
+
history.append({"role": "assistant", "content": f"Echo: {msg}"})
|
| 130 |
|
| 131 |
return "", history
|
| 132 |
|
| 133 |
|
| 134 |
+
# --- Knowledge Base (stub) ---
|
| 135 |
+
def index_pdf(file) -> str:
|
| 136 |
+
if file is None:
|
| 137 |
+
return "❌ Файл не выбран"
|
| 138 |
+
# Пока тестовый режим: делаем вид, что добавили
|
| 139 |
+
# Позже здесь будет реальная индексация (FAISS/Qdrant + embeddings)
|
| 140 |
+
name = getattr(file, "name", "uploaded.pdf")
|
| 141 |
+
return f"✅ Файл `{name}` успешно добавлен в базу (тестовый режим)."
|
| 142 |
+
|
| 143 |
+
|
| 144 |
def build_interface():
|
| 145 |
ensure_feedback_csv_exists()
|
| 146 |
|
|
|
|
| 148 |
gr.Markdown("# 2MOOD AI Workspace")
|
| 149 |
gr.Markdown("База знаний + Messenger + Обратная связь")
|
| 150 |
|
| 151 |
+
# -------- TAB: Knowledge Base --------
|
| 152 |
with gr.Tab("📚 База знаний"):
|
| 153 |
+
gr.Markdown("### Загрузка PDF и индексирование (пока заглушка)")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
+
pdf_file = gr.File(label="Загрузить PDF")
|
| 156 |
+
add_btn = gr.Button("Добавить в базу", variant="primary")
|
| 157 |
+
status_kb = gr.Markdown()
|
| 158 |
|
| 159 |
+
add_btn.click(
|
| 160 |
+
fn=index_pdf,
|
| 161 |
+
inputs=pdf_file,
|
| 162 |
+
outputs=status_kb
|
| 163 |
+
)
|
| 164 |
|
| 165 |
+
# -------- TAB: Messenger --------
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
with gr.Tab("💬 2MOOD Messenger"):
|
| 167 |
+
chat = gr.Chatbot(height=420) # без type="messages" для совместимости
|
|
|
|
| 168 |
msg = gr.Textbox(label="Сообщение", placeholder="Напишите сообщение…")
|
| 169 |
send = gr.Button("Отправить", variant="primary")
|
| 170 |
|
| 171 |
send.click(messenger_reply, inputs=[msg, chat], outputs=[msg, chat])
|
| 172 |
|
| 173 |
+
# -------- TAB: Feedback --------
|
| 174 |
with gr.Tab("📝 Обратная связь"):
|
| 175 |
category = gr.Dropdown(
|
| 176 |
label="Категория",
|
|
|
|
| 192 |
)
|
| 193 |
|
| 194 |
submit = gr.Button("Отправить", variant="primary")
|
| 195 |
+
status_fb = gr.Markdown()
|
| 196 |
|
|
|
|
| 197 |
download_btn = gr.Button("📥 Скачать все отзывы")
|
| 198 |
download_file = gr.File(label="Файл с отзывами", interactive=False)
|
| 199 |
download_status = gr.Markdown()
|
| 200 |
|
|
|
|
| 201 |
gr.Markdown(f"Файл логов: `{FEEDBACK_CSV.as_posix()}`")
|
| 202 |
|
| 203 |
submit.click(
|
| 204 |
save_feedback,
|
| 205 |
inputs=[category, rating, contact, feedback_text],
|
| 206 |
+
outputs=[status_fb, feedback_text, download_file],
|
| 207 |
)
|
| 208 |
|
| 209 |
download_btn.click(
|
|
|
|
| 215 |
return demo
|
| 216 |
|
| 217 |
|
| 218 |
+
# Локальный запуск (на HF не используется, но пусть будет)
|
| 219 |
def launch_with_port_fallback(demo: gr.Blocks):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
os.environ.setdefault("NO_PROXY", "localhost,127.0.0.1")
|
| 221 |
os.environ.setdefault("no_proxy", "localhost,127.0.0.1")
|
| 222 |
|
|
|
|
| 228 |
ports.extend([7860] + list(range(7861, 7871)))
|
| 229 |
|
| 230 |
last_error: Optional[Exception] = None
|
|
|
|
| 231 |
for port in ports:
|
|
|
|
| 232 |
try:
|
| 233 |
+
demo.launch(server_name="127.0.0.1", server_port=port, share=False, inbrowser=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
return
|
| 235 |
except Exception as e:
|
| 236 |
last_error = e
|
| 237 |
msg = str(e)
|
|
|
|
|
|
|
| 238 |
if "localhost is not accessible" in msg or "shareable link must be created" in msg:
|
| 239 |
try:
|
| 240 |
+
demo.launch(server_name="0.0.0.0", server_port=port, share=True, inbrowser=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
return
|
| 242 |
except Exception as e2:
|
| 243 |
last_error = e2
|
| 244 |
continue
|
| 245 |
|
|
|
|
|
|
|
| 246 |
raise RuntimeError(f"Не удалось запустить Gradio ни на одном порту. Последняя ошибка: {last_error}")
|
| 247 |
|
| 248 |
|