Spaces:
Runtime error
Runtime error
File size: 5,208 Bytes
f0574c7 57e423f f0574c7 | 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 | #!/usr/bin/env python3
"""
启动脚本:同时运行 vLLM 服务器和 Streamlit 应用
保留原有的 Streamlit 入口,添加 vLLM 后台服务
"""
import subprocess
import time
import os
import signal
import sys
import threading
import logging
from pathlib import Path
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# 添加项目根目录到路径
sys.path.append(str(Path(__file__).parent.parent))
class ServiceManager:
def __init__(self):
self.processes = []
self.running = True
def run_vllm(self):
"""启动 vLLM 服务器(后台服务)"""
logger.info("🚀 正在启动 vLLM 推理服务器...")
# vLLM 启动命令(优化显存使用)
cmd = [
"python", "-m", "vllm.entrypoints.openai.api_server",
"--model", "Qwen/Qwen3.5-27B-GPTQ-Int4",
"--port", "8000",
"--host", "0.0.0.0",
"--tensor-parallel-size", "1",
"--quantization", "gptq",
"--max-model-len", "32768",
"--gpu-memory-utilization", "0.85", # 保留 15% 显存给 Streamlit 等
"--enforce-eager",
"--max-num-batched-tokens", "8192",
"--max-num-seqs", "4",
"--disable-log-stats", # 减少日志输出
]
# 设置 CUDA 环境
env = os.environ.copy()
#env["CUDA_VISIBLE_DEVICES"] = "0"
#env["VLLM_USE_TRITON"] = "1" # 使用 Triton 加速
# 启动进程
process = subprocess.Popen(
cmd,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1
)
self.processes.append(("vllm", process))
# 在单独的线程中读取输出
def log_output():
for line in process.stdout:
if line.strip():
logger.info(f"[vLLM] {line.strip()}")
threading.Thread(target=log_output, daemon=True).start()
# 等待 vLLM 就绪
self.wait_for_vllm()
def wait_for_vllm(self, max_retries=60):
"""等待 vLLM 服务器就绪"""
import requests
logger.info("⏳ 等待 vLLM 服务器初始化...")
for i in range(max_retries):
try:
response = requests.get("http://localhost:8000/health")
if response.status_code == 200:
logger.info("✅ vLLM 服务器已就绪!")
return True
except:
pass
# 显示进度
if i % 10 == 0:
logger.info(f"⏳ 仍在等待 vLLM... ({i+1}/{max_retries})")
time.sleep(2)
logger.error("❌ vLLM 启动超时")
return False
def run_streamlit(self):
"""启动 Streamlit 应用(主服务)"""
logger.info("🖥️ 正在启动 Streamlit 应用...")
# 使用原有的入口点
cmd = [
"streamlit", "run",
"streamlit_app.py",
"--server.port=8501",
"--server.address=0.0.0.0",
"--server.enableCORS=false",
"--server.enableXsrfProtection=false",
"--server.maxUploadSize=10", # 限制上传大小
]
process = subprocess.Popen(cmd)
self.processes.append(("streamlit", process))
logger.info("✅ Streamlit 应用已启动")
def monitor_services(self):
"""监控服务状态"""
while self.running:
time.sleep(10)
for name, process in self.processes:
if process.poll() is not None:
logger.error(f"❌ {name} 服务意外停止,退出码: {process.returncode}")
self.stop_all()
sys.exit(1)
def stop_all(self, signum=None, frame=None):
"""停止所有服务"""
logger.info("🛑 正在停止所有服务...")
self.running = False
for name, process in self.processes:
logger.info(f"正在停止 {name}...")
process.terminate()
# 等待进程结束
for name, process in self.processes:
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
logger.warning(f"强制终止 {name}")
process.kill()
logger.info("✅ 所有服务已停止")
sys.exit(0)
def run(self):
"""运行所有服务"""
# 注册信号处理
signal.signal(signal.SIGINT, self.stop_all)
signal.signal(signal.SIGTERM, self.stop_all)
# 启动 vLLM(后台)
self.run_vllm()
# 启动 Streamlit(前台)
self.run_streamlit()
# 开始监控
self.monitor_services()
if __name__ == "__main__":
manager = ServiceManager()
manager.run() |