jackkuo commited on
Commit
de36d65
·
1 Parent(s): a9efc75
Files changed (5) hide show
  1. Dockerfile +2 -5
  2. app.py +44 -27
  3. requirements.txt +1 -4
  4. server.py +0 -77
  5. 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
- # shell 脚本同时跑 FastAPI(8008) + Gradio(7860)
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
- API_URL = "http://localhost:8008/stream-words"
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 stream_words(query):
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 stream_words_mcp_stream(query: str = "give me some english words"):
49
  """MCP工具:流式返回英文单词"""
50
  try:
51
- async for token in stream_words(query):
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 stream_words(last_user_msg):
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(stream_words_mcp, inputs=None, outputs=gr.Textbox(label="MCP结果", visible=False))
124
  # 注册流式MCP工具
125
- demo.load(stream_words_mcp_stream, inputs=None, outputs=gr.Textbox(label="流式MCP结果", visible=False))
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