# app.py import gradio as gr import asyncio from itertools import cycle from core.utils import generate_first_question from core.mbti_analyzer import analyze_mbti from core.interviewer import stream_question # ✅ теперь используем потоковую версию # -------------------------------------------------------------- # 🌀 Асинхронная анимация "Thinking..." # -------------------------------------------------------------- async def async_loader(update_fn, delay=0.15): frames = cycle(["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]) for frame in frames: update_fn(f"💭 Interviewer is thinking... {frame}") await asyncio.sleep(delay) # -------------------------------------------------------------- # ⚙️ Основная логика # -------------------------------------------------------------- def analyze_and_ask(user_text, prev_count): """Основная функция — анализирует ответ и генерирует следующий вопрос (потоково).""" if not user_text.strip(): yield "⚠️ Please enter your answer.", "", prev_count return try: n = int(prev_count.split("/")[0]) + 1 except Exception: n = 1 counter = f"{n}/8" # мгновенный отклик yield "⏳ Analyzing personality...", "💭 Interviewer is thinking... ⠋", counter # анализ MBTI (также потоковый) mbti_gen = analyze_mbti(user_text) mbti_text = "" for chunk in mbti_gen: mbti_text = chunk yield mbti_text, "💭 Interviewer is thinking... ⠙", counter # генерация вопроса новой моделью (потоково) try: partial_question = "" for piece in stream_question(): # 👈 здесь идёт токен-за-токен поток partial_question = piece yield mbti_text, partial_question, counter except Exception as e: yield mbti_text, f"⚠️ Question generator error: {e}", counter # -------------------------------------------------------------- # 🧱 Интерфейс Gradio # -------------------------------------------------------------- with gr.Blocks(theme=gr.themes.Soft(), title="MBTI Personality Interviewer") as demo: gr.Markdown( "## 🧠 MBTI Personality Interviewer\n" "Определи личностный тип и получи вопросы из разных категорий MBTI.\n\n" "_Теперь с потоковой генерацией вопросов._" ) with gr.Row(): with gr.Column(scale=1): inp = gr.Textbox( label="Ваш ответ", placeholder="Например: I enjoy working with people and organizing events.", lines=4, ) btn = gr.Button("Анализировать и задать новый вопрос", variant="primary") with gr.Column(scale=1): mbti_out = gr.Textbox(label="📊 Анализ MBTI", lines=4) interviewer_out = gr.Textbox(label="💬 Следующий вопрос (streaming)", lines=3) progress = gr.Textbox(label="⏳ Прогресс", value="0/8") btn.click( analyze_and_ask, inputs=[inp, progress], outputs=[mbti_out, interviewer_out, progress], show_progress=True, ) demo.load( lambda: ("", generate_first_question(), "0/8"), inputs=None, outputs=[mbti_out, interviewer_out, progress], ) demo.queue(max_size=32).launch(server_name="0.0.0.0", server_port=7860)