Doc-chat / app.py
Rulga's picture
Refactor FastAPI server launch to use multiprocessing for improved performance
0005aa0
raw
history blame
8.15 kB
import os
import sys
import threading
import time
import requests
from requests.exceptions import ConnectionError
os.environ['MPLCONFIGDIR'] = os.path.join(os.getcwd(), 'cache', 'matplotlib')
os.makedirs(os.environ['MPLCONFIGDIR'], exist_ok=True)
import gradio as gr
import uvicorn
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
# Add project root to Python path
current_dir = os.path.abspath(os.path.dirname(__file__))
if current_dir not in sys.path:
sys.path.insert(0, current_dir)
# Import our main application
from api.fastapi_server import app as fastapi_app
def wait_for_fastapi(timeout=30, interval=0.5):
"""Wait for FastAPI server to start"""
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get("http://127.0.0.1:7860/health")
if response.status_code == 200:
print("FastAPI server is ready!")
return True
except ConnectionError:
time.sleep(interval)
return False
# Run FastAPI server in a separate thread
#def run_fastapi():
# uvicorn.run(fastapi_app, host="0.0.0.0", port=7860)
def run_fastapi():
import multiprocessing
multiprocessing.Process(target=uvicorn.run, args=(fastapi_app,), kwargs={"host": "0.0.0.0", "port": 7860}).start()
# Start FastAPI in a background thread
fastapi_thread = threading.Thread(target=run_fastapi, daemon=True)
fastapi_thread.start()
# Wait for FastAPI to start
if not wait_for_fastapi():
print("Failed to start FastAPI server")
sys.exit(1)
# Create a Gradio interface that will proxy requests to FastAPI
def respond(message, history, conversation_id=None):
"""Handle chat messages and update conversation history"""
if not message:
return history, conversation_id
try:
# Send request to FastAPI backend
response = requests.post(
"http://127.0.0.1:7860/chat",
json={"message": message, "conversation_id": conversation_id}
)
if response.status_code == 200:
data = response.json()
# Update conversation history
history = history + [(message, data["response"])]
return history, data["conversation_id"]
else:
error_message = f"Error: {response.status_code} - {response.text}"
history = history + [(message, error_message)]
return history, conversation_id
except Exception as e:
error_message = f"Error connecting to API: {str(e)}"
history = history + [(message, error_message)]
return history, conversation_id
def build_kb():
try:
response = requests.post("http://127.0.0.1:7860/build-kb")
if response.status_code == 200:
return f"Success: {response.json()['message']}"
else:
return f"Error: {response.status_code} - {response.text}"
except Exception as e:
return f"API connection error: {str(e)}"
def get_kb_size():
"""Calculate actual knowledge base size from files"""
vector_store_path = "vector_store"
try:
total_size = 0
for file in ["index.faiss", "index.pkl"]:
file_path = os.path.join(vector_store_path, file)
if os.path.exists(file_path):
total_size += os.path.getsize(file_path)
return total_size / (1024 * 1024) # Convert to MB
except Exception:
return None
# Добавим функцию проверки статуса базы знаний
def check_kb_status():
try:
response = requests.get("http://127.0.0.1:7860/")
if response.status_code == 200:
data = response.json()
if data["knowledge_base_exists"]:
kb_info = data["kb_info"]
version = kb_info.get('version', 'N/A')
# Получаем реальный размер файлов
actual_size = get_kb_size()
size_text = f"{actual_size:.2f} MB" if actual_size is not None else "N/A"
return f"✅ База знаний готова к работе\nВерсия: {version}\nРазмер: {size_text}"
else:
# Проверяем, есть ли файлы на диске
if os.path.exists(os.path.join("vector_store", "index.faiss")):
actual_size = get_kb_size()
size_text = f"{actual_size:.2f} MB" if actual_size is not None else "N/A"
return f"✅ База знаний найдена на диске\nРазмер: {size_text}\nТребуется перезагрузка сервера"
return "❌ База знаний не создана. Нажмите кнопку 'Create/Update Knowledge Base'"
except Exception as e:
# Проверяем наличие файлов даже при ошибке соединения
if os.path.exists(os.path.join("vector_store", "index.faiss")):
actual_size = get_kb_size()
size_text = f"{actual_size:.2f} MB" if actual_size is not None else "N/A"
return f"⚠️ Ошибка соединения, но база знаний существует\nРазмер: {size_text}"
return f"❌ Ошибка проверки статуса: {str(e)}"
def clear_history():
"""Reset chat history and conversation ID"""
return [], None # Returns empty history and resets conversation ID
# Create the Gradio interface
demo = gr.Blocks(title="Status Law Assistant", theme=gr.themes.Soft())
with demo:
# Add conversation_id state first
conversation_id = gr.State(None)
gr.Markdown("# 🤖 Status Law Assistant")
with gr.Row():
# Left column for chat (larger)
with gr.Column(scale=3):
chatbot = gr.Chatbot(
label="Conversation",
height=600,
show_label=False,
bubble_full_width=False
)
with gr.Row():
msg = gr.Textbox(
label="Enter your question here",
placeholder="Type your message and press Enter...",
scale=4
)
submit_btn = gr.Button("Send", variant="primary", scale=1)
# Right column for controls (smaller)
with gr.Column(scale=1):
gr.Markdown("### Knowledge Base Controls")
build_kb_btn = gr.Button("Create/Update Knowledge Base", variant="primary")
check_status_btn = gr.Button("Check Status")
kb_status = gr.Textbox(
label="Knowledge Base Status",
value="Checking status...",
interactive=False
)
gr.Markdown("### Chat Controls")
clear_btn = gr.Button("Clear Chat History")
# Help section
with gr.Accordion("ℹ️ How to use", open=False):
gr.Markdown("""
1. First, click **Create/Update Knowledge Base** button
2. Wait for confirmation message
3. Enter your question in the text field and press Enter or "Send" button
4. Use "Clear Chat History" to start a new conversation
""")
# Event handlers remain the same
msg.submit(respond, [msg, chatbot, conversation_id], [chatbot, conversation_id])
submit_btn.click(respond, [msg, chatbot, conversation_id], [chatbot, conversation_id])
clear_btn.click(clear_history, None, [chatbot, conversation_id])
build_kb_btn.click(build_kb, inputs=None, outputs=kb_status)
check_status_btn.click(check_kb_status, inputs=None, outputs=kb_status)
# Mount Gradio app to FastAPI at root path
app = gr.mount_gradio_app(fastapi_app, demo, path="/")
if __name__ == "__main__":
# Launch the combined app
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)
#demo.launch(server_name="0.0.0.0", server_port=7860, share=False)