Spaces:
Sleeping
Sleeping
update
Browse files- Dockerfile +2 -5
- app.py +44 -27
- requirements.txt +1 -4
- server.py +0 -77
- start_services.sh +0 -62
Dockerfile
CHANGED
|
@@ -8,8 +8,5 @@ RUN pip install -r requirements.txt
|
|
| 8 |
COPY . .
|
| 9 |
|
| 10 |
# Hugging Face Space 必须监听 7860 端口
|
| 11 |
-
#
|
| 12 |
-
|
| 13 |
-
RUN chmod +x /app/start_services.sh
|
| 14 |
-
|
| 15 |
-
CMD ["/app/start_services.sh"]
|
|
|
|
| 8 |
COPY . .
|
| 9 |
|
| 10 |
# Hugging Face Space 必须监听 7860 端口
|
| 11 |
+
# 直接启动 Gradio 服务,内置所有功能
|
| 12 |
+
CMD ["python", "app.py"]
|
|
|
|
|
|
|
|
|
app.py
CHANGED
|
@@ -1,35 +1,52 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
-
import httpx
|
| 3 |
import asyncio
|
| 4 |
import json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
async def stream_words(query: str):
|
| 9 |
-
"""异步获取 FastAPI 的流式输出"""
|
| 10 |
-
async with httpx.AsyncClient(timeout=None) as client:
|
| 11 |
-
async with client.stream("GET", API_URL, params={"query": query}) as response:
|
| 12 |
-
async for line in response.aiter_lines():
|
| 13 |
-
if line.startswith("data: "):
|
| 14 |
-
try:
|
| 15 |
-
data = json.loads(line[6:])
|
| 16 |
-
if data.get('status') == 'word':
|
| 17 |
-
yield data.get('word', '')
|
| 18 |
-
elif data.get('status') == 'start':
|
| 19 |
-
yield f"🚀 {data.get('message', '开始生成单词...')}\n"
|
| 20 |
-
elif data.get('status') == 'complete':
|
| 21 |
-
yield f"\n✅ {data.get('message', '生成完成!')}"
|
| 22 |
-
except json.JSONDecodeError:
|
| 23 |
-
continue
|
| 24 |
-
|
| 25 |
-
def stream_words_mcp(query: str = "give me some english words"):
|
| 26 |
"""MCP工具包装函数:流式获取英文单词,返回结果给MCP客户端"""
|
| 27 |
try:
|
| 28 |
# 调用原始函数并收集结果
|
| 29 |
result = []
|
| 30 |
# 注意:这里需要处理异步函数
|
| 31 |
async def collect_tokens():
|
| 32 |
-
async for token in
|
| 33 |
if token.strip():
|
| 34 |
result.append(token)
|
| 35 |
return result
|
|
@@ -45,10 +62,10 @@ def stream_words_mcp(query: str = "give me some english words"):
|
|
| 45 |
except Exception as e:
|
| 46 |
return f"生成单词时出错: {str(e)}"
|
| 47 |
|
| 48 |
-
async def
|
| 49 |
"""MCP工具:流式返回英文单词"""
|
| 50 |
try:
|
| 51 |
-
async for token in
|
| 52 |
if token.strip():
|
| 53 |
yield token
|
| 54 |
except Exception as e:
|
|
@@ -104,7 +121,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 104 |
|
| 105 |
# 流式拼接回复
|
| 106 |
full_response = ""
|
| 107 |
-
async for token in
|
| 108 |
if token.strip():
|
| 109 |
full_response += " " + token
|
| 110 |
messages[-1] = {"role": "assistant", "content": full_response.strip()}
|
|
@@ -120,9 +137,9 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 120 |
clear_btn.click(clear_chat, outputs=chatbot)
|
| 121 |
|
| 122 |
# 注册MCP工具 - 使用包装函数并正确配置输出
|
| 123 |
-
demo.load(
|
| 124 |
# 注册流式MCP工具
|
| 125 |
-
demo.load(
|
| 126 |
|
| 127 |
# 开启 MCP server
|
| 128 |
demo.launch(mcp_server=True, server_port=7860)
|
|
|
|
| 1 |
import gradio as gr
|
|
|
|
| 2 |
import asyncio
|
| 3 |
import json
|
| 4 |
+
import subprocess
|
| 5 |
+
import sys
|
| 6 |
+
from typing import AsyncGenerator
|
| 7 |
+
|
| 8 |
+
# 预定义的200个常用英文单词
|
| 9 |
+
ENGLISH_WORDS = [
|
| 10 |
+
"the", "be", "to", "of", "and", "a", "in", "that", "have", "I",
|
| 11 |
+
"it", "for", "not", "on", "with", "he", "as", "you", "do", "at",
|
| 12 |
+
"this", "but", "his", "by", "from", "they", "we", "say", "her", "she",
|
| 13 |
+
"or", "an", "will", "my", "one", "all", "would", "there", "their", "what",
|
| 14 |
+
"so", "up", "out", "if", "about", "who", "get", "which", "go", "me",
|
| 15 |
+
"when", "make", "can", "like", "time", "no", "just", "him", "know", "take",
|
| 16 |
+
"people", "into", "year", "your", "good", "some", "could", "them", "see", "other",
|
| 17 |
+
"than", "then", "now", "look", "only", "come", "its", "over", "think", "also",
|
| 18 |
+
"back", "after", "use", "two", "how", "our", "work", "first", "well", "way",
|
| 19 |
+
"even", "new", "want", "because", "any", "these", "give", "day", "most", "us",
|
| 20 |
+
"very", "life", "after", "call", "world", "over", "still", "take", "every", "through",
|
| 21 |
+
"before", "long", "where", "much", "should", "well", "people", "down", "own", "work",
|
| 22 |
+
"first", "good", "new", "write", "our", "used", "me", "man", "too", "any",
|
| 23 |
+
"day", "same", "right", "look", "think", "also", "around", "another", "came"
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
async def generate_words_stream(query: str) -> AsyncGenerator[str, None]:
|
| 27 |
+
"""生成200个英文单词的流式输出(Gradio版本)"""
|
| 28 |
+
# 发送开始标记
|
| 29 |
+
yield f"🚀 开始生成200个英文单词...\n"
|
| 30 |
+
|
| 31 |
+
# 流式输出200个单词
|
| 32 |
+
for i, word in enumerate(ENGLISH_WORDS, 1):
|
| 33 |
+
# 模拟一些处理时间,让流式效果更明显
|
| 34 |
+
await asyncio.sleep(0.05)
|
| 35 |
+
|
| 36 |
+
# 发送单词
|
| 37 |
+
yield word
|
| 38 |
+
|
| 39 |
+
# 发送完成标记
|
| 40 |
+
yield f"\n✅ 200个英文单词生成完成!"
|
| 41 |
|
| 42 |
+
def generate_words_mcp(query: str = "give me some english words") -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
"""MCP工具包装函数:流式获取英文单词,返回结果给MCP客户端"""
|
| 44 |
try:
|
| 45 |
# 调用原始函数并收集结果
|
| 46 |
result = []
|
| 47 |
# 注意:这里需要处理异步函数
|
| 48 |
async def collect_tokens():
|
| 49 |
+
async for token in generate_words_stream(query):
|
| 50 |
if token.strip():
|
| 51 |
result.append(token)
|
| 52 |
return result
|
|
|
|
| 62 |
except Exception as e:
|
| 63 |
return f"生成单词时出错: {str(e)}"
|
| 64 |
|
| 65 |
+
async def generate_words_mcp_stream(query: str = "give me some english words") -> AsyncGenerator[str, None]:
|
| 66 |
"""MCP工具:流式返回英文单词"""
|
| 67 |
try:
|
| 68 |
+
async for token in generate_words_stream(query):
|
| 69 |
if token.strip():
|
| 70 |
yield token
|
| 71 |
except Exception as e:
|
|
|
|
| 121 |
|
| 122 |
# 流式拼接回复
|
| 123 |
full_response = ""
|
| 124 |
+
async for token in generate_words_stream(last_user_msg):
|
| 125 |
if token.strip():
|
| 126 |
full_response += " " + token
|
| 127 |
messages[-1] = {"role": "assistant", "content": full_response.strip()}
|
|
|
|
| 137 |
clear_btn.click(clear_chat, outputs=chatbot)
|
| 138 |
|
| 139 |
# 注册MCP工具 - 使用包装函数并正确配置输出
|
| 140 |
+
demo.load(generate_words_mcp, inputs=None, outputs=gr.Textbox(label="MCP结果", visible=False))
|
| 141 |
# 注册流式MCP工具
|
| 142 |
+
demo.load(generate_words_mcp_stream, inputs=None, outputs=gr.Textbox(label="流式MCP结果", visible=False))
|
| 143 |
|
| 144 |
# 开启 MCP server
|
| 145 |
demo.launch(mcp_server=True, server_port=7860)
|
requirements.txt
CHANGED
|
@@ -1,4 +1 @@
|
|
| 1 |
-
gradio[mcp]>=4.36.0
|
| 2 |
-
httpx
|
| 3 |
-
fastapi
|
| 4 |
-
uvicorn
|
|
|
|
| 1 |
+
gradio[mcp]>=4.36.0
|
|
|
|
|
|
|
|
|
server.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
| 1 |
-
from fastapi import FastAPI, Request
|
| 2 |
-
from fastapi.responses import StreamingResponse
|
| 3 |
-
import asyncio
|
| 4 |
-
import json
|
| 5 |
-
from typing import AsyncGenerator
|
| 6 |
-
|
| 7 |
-
app = FastAPI(title="Streaming English Words API", version="1.0.0")
|
| 8 |
-
|
| 9 |
-
# 预定义的200个常用英文单词
|
| 10 |
-
ENGLISH_WORDS = [
|
| 11 |
-
"the", "be", "to", "of", "and", "a", "in", "that", "have", "I",
|
| 12 |
-
"it", "for", "not", "on", "with", "he", "as", "you", "do", "at",
|
| 13 |
-
"this", "but", "his", "by", "from", "they", "we", "say", "her", "she",
|
| 14 |
-
"or", "an", "will", "my", "one", "all", "would", "there", "their", "what",
|
| 15 |
-
"so", "up", "out", "if", "about", "who", "get", "which", "go", "me",
|
| 16 |
-
"when", "make", "can", "like", "time", "no", "just", "him", "know", "take",
|
| 17 |
-
"people", "into", "year", "your", "good", "some", "could", "them", "see", "other",
|
| 18 |
-
"than", "then", "now", "look", "only", "come", "its", "over", "think", "also",
|
| 19 |
-
"back", "after", "use", "two", "how", "our", "work", "first", "well", "way",
|
| 20 |
-
"even", "new", "want", "because", "any", "these", "give", "day", "most", "us",
|
| 21 |
-
"very", "life", "after", "call", "world", "over", "still", "take", "every", "through",
|
| 22 |
-
"before", "long", "where", "much", "should", "well", "people", "down", "own", "work",
|
| 23 |
-
"first", "good", "new", "write", "our", "used", "me", "man", "too", "any",
|
| 24 |
-
"day", "same", "right", "look", "think", "also", "around", "another", "came"
|
| 25 |
-
]
|
| 26 |
-
|
| 27 |
-
async def generate_words_stream(query: str) -> AsyncGenerator[str, None]:
|
| 28 |
-
"""生成200个英文单词的流式输出"""
|
| 29 |
-
# 发送开始标记
|
| 30 |
-
yield f"data: {json.dumps({'status': 'start', 'query': query, 'message': '开始生成200个英文单词...'})}\n\n"
|
| 31 |
-
|
| 32 |
-
# 流式输出200个单词
|
| 33 |
-
for i, word in enumerate(ENGLISH_WORDS, 1):
|
| 34 |
-
# 模拟一些处理时间,让流式效果更明显
|
| 35 |
-
await asyncio.sleep(0.05)
|
| 36 |
-
|
| 37 |
-
# 发送单词数据
|
| 38 |
-
data = {
|
| 39 |
-
'status': 'word',
|
| 40 |
-
'index': i,
|
| 41 |
-
'word': word,
|
| 42 |
-
'total': len(ENGLISH_WORDS)
|
| 43 |
-
}
|
| 44 |
-
yield f"data: {json.dumps(data)}\n\n"
|
| 45 |
-
|
| 46 |
-
# 发送完成标记
|
| 47 |
-
yield f"data: {json.dumps({'status': 'complete', 'message': '200个英文单词生成完成!'})}\n\n"
|
| 48 |
-
|
| 49 |
-
@app.get("/")
|
| 50 |
-
async def root():
|
| 51 |
-
return {"message": "Streaming English Words API", "endpoint": "/stream-words"}
|
| 52 |
-
|
| 53 |
-
@app.get("/stream-words")
|
| 54 |
-
async def stream_words(query: str = "default"):
|
| 55 |
-
"""流式输出200个英文单词"""
|
| 56 |
-
return StreamingResponse(
|
| 57 |
-
generate_words_stream(query),
|
| 58 |
-
media_type="text/plain",
|
| 59 |
-
headers={
|
| 60 |
-
"Cache-Control": "no-cache",
|
| 61 |
-
"Connection": "keep-alive",
|
| 62 |
-
"Content-Type": "text/event-stream",
|
| 63 |
-
}
|
| 64 |
-
)
|
| 65 |
-
|
| 66 |
-
@app.get("/words")
|
| 67 |
-
async def get_words(query: str = "default"):
|
| 68 |
-
"""一次性返回所有200个英文单词"""
|
| 69 |
-
return {
|
| 70 |
-
"query": query,
|
| 71 |
-
"total_words": len(ENGLISH_WORDS),
|
| 72 |
-
"words": ENGLISH_WORDS
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
if __name__ == "__main__":
|
| 76 |
-
import uvicorn
|
| 77 |
-
uvicorn.run(app, host="0.0.0.0", port=8008)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
start_services.sh
DELETED
|
@@ -1,62 +0,0 @@
|
|
| 1 |
-
#!/bin/bash
|
| 2 |
-
# 启动脚本,替代supervisord
|
| 3 |
-
|
| 4 |
-
# 设置错误时退出
|
| 5 |
-
set -e
|
| 6 |
-
|
| 7 |
-
# 函数:启动服务
|
| 8 |
-
start_service() {
|
| 9 |
-
local name=$1
|
| 10 |
-
local command=$2
|
| 11 |
-
|
| 12 |
-
echo "Starting $name..."
|
| 13 |
-
$command &
|
| 14 |
-
local pid=$!
|
| 15 |
-
echo "$name started with PID $pid"
|
| 16 |
-
echo $pid > "/tmp/${name}.pid"
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
# 函数:停止服务
|
| 20 |
-
stop_service() {
|
| 21 |
-
local name=$1
|
| 22 |
-
local pid_file="/tmp/${name}.pid"
|
| 23 |
-
|
| 24 |
-
if [ -f "$pid_file" ]; then
|
| 25 |
-
local pid=$(cat "$pid_file")
|
| 26 |
-
echo "Stopping $name (PID: $pid)..."
|
| 27 |
-
kill -TERM $pid 2>/dev/null || true
|
| 28 |
-
rm -f "$pid_file"
|
| 29 |
-
fi
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
# 函数:清理退出
|
| 33 |
-
cleanup() {
|
| 34 |
-
echo "Received signal, cleaning up..."
|
| 35 |
-
stop_service "fastapi"
|
| 36 |
-
stop_service "gradio"
|
| 37 |
-
exit 0
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
# 设置信号处理
|
| 41 |
-
trap cleanup SIGTERM SIGINT
|
| 42 |
-
|
| 43 |
-
# 启动服务
|
| 44 |
-
start_service "fastapi" "uvicorn server:app --host 0.0.0.0 --port 8008"
|
| 45 |
-
start_service "gradio" "python app.py"
|
| 46 |
-
|
| 47 |
-
# 等待信号
|
| 48 |
-
echo "All services started, waiting for signal..."
|
| 49 |
-
while true; do
|
| 50 |
-
# 检查进程是否还在运行
|
| 51 |
-
if ! kill -0 $(cat /tmp/fastapi.pid 2>/dev/null) 2>/dev/null; then
|
| 52 |
-
echo "FastAPI process died, restarting..."
|
| 53 |
-
start_service "fastapi" "uvicorn server:app --host 0.0.0.0 --port 8008"
|
| 54 |
-
fi
|
| 55 |
-
|
| 56 |
-
if ! kill -0 $(cat /tmp/gradio.pid 2>/dev/null) 2>/dev/null; then
|
| 57 |
-
echo "Gradio process died, restarting..."
|
| 58 |
-
start_service "gradio" "python app.py"
|
| 59 |
-
fi
|
| 60 |
-
|
| 61 |
-
sleep 5
|
| 62 |
-
done
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|