dragg2 commited on
Commit
07ca894
·
verified ·
1 Parent(s): 956b7fd

Upload 4 files

Browse files
Files changed (2) hide show
  1. app.py +68 -51
  2. start.sh +1 -6
app.py CHANGED
@@ -1,61 +1,78 @@
1
  import os
2
 
3
  from fastapi import FastAPI, Request
4
- from fastapi.responses import StreamingResponse
5
  import httpx
6
 
7
  # 内部真实 Bot API Server(telegram-bot-api)监听端口
8
  # 注意:外网端口必须是 7860(HF 会检查),但 Bot API 可以只跑在容器内部端口(默认 8081)
9
  UPSTREAM = f"http://127.0.0.1:{os.environ.get('TELEGRAM_UPSTREAM_PORT', '8081')}"
10
  app = FastAPI()
11
-
12
  @app.get("/")
13
- async def root():
14
- return {"ok": True, "hint": "use /tg/ prefix, e.g. /tg/bot<TOKEN>/getMe"}
15
-
16
- @app.api_route("/tg/{path:path}", methods=["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"])
17
- async def proxy(path: str, request: Request):
18
- url = f"{UPSTREAM}/{path}"
19
-
20
- params = list(request.query_params.multi_items())
21
-
22
- headers = dict(request.headers)
23
- headers.pop("host", None)
24
-
25
- async def iter_request_body():
26
- async for chunk in request.stream():
27
- yield chunk
28
-
29
- async with httpx.AsyncClient(timeout=None, follow_redirects=True) as client:
30
- async with client.stream(
31
- request.method,
32
- url,
33
- params=params,
34
- headers=headers,
35
- content=iter_request_body(),
36
- ) as r:
37
-
38
- passthrough_headers = {}
39
- for k, v in r.headers.items():
40
- lk = k.lower()
41
- if lk in [
42
- "content-type",
43
- "content-length",
44
- "content-disposition",
45
- "accept-ranges",
46
- "content-range",
47
- "etag",
48
- "cache-control",
49
- "last-modified",
50
- ]:
51
- passthrough_headers[k] = v
52
-
53
- async def iter_response():
54
- async for chunk in r.aiter_bytes():
55
- yield chunk
56
-
57
- return StreamingResponse(
58
- iter_response(),
59
- status_code=r.status_code,
60
- headers=passthrough_headers,
61
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
 
3
  from fastapi import FastAPI, Request
4
+ from fastapi.responses import Response, StreamingResponse
5
  import httpx
6
 
7
  # 内部真实 Bot API Server(telegram-bot-api)监听端口
8
  # 注意:外网端口必须是 7860(HF 会检查),但 Bot API 可以只跑在容器内部端口(默认 8081)
9
  UPSTREAM = f"http://127.0.0.1:{os.environ.get('TELEGRAM_UPSTREAM_PORT', '8081')}"
10
  app = FastAPI()
11
+
12
  @app.get("/")
13
+ async def root():
14
+ return {"ok": True, "hint": "use /tg/ prefix, e.g. /tg/bot<TOKEN>/getMe"}
15
+
16
+ @app.api_route("/tg/{path:path}", methods=["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"])
17
+ async def proxy(path: str, request: Request):
18
+ url = f"{UPSTREAM}/{path}"
19
+
20
+ params = list(request.query_params.multi_items())
21
+
22
+ headers = dict(request.headers)
23
+ headers.pop("host", None)
24
+
25
+ async def iter_request_body():
26
+ async for chunk in request.stream():
27
+ yield chunk
28
+
29
+ # 关键修复:
30
+ # - Bot API 的 /bot... 响应是小 JSON(sendDocument/getFile/getMe),直接“读全量再返回”,避免流式上下文提前关闭导致空响应。
31
+ # - Bot API 的 /file/... 响应是大文件,才需要流式透传。
32
+ is_file_download = path.startswith("file/") or path.startswith("/file/")
33
+
34
+ passthrough_allow = {
35
+ "content-type",
36
+ "content-length",
37
+ "content-disposition",
38
+ "accept-ranges",
39
+ "content-range",
40
+ "etag",
41
+ "cache-control",
42
+ "last-modified",
43
+ }
44
+
45
+ async with httpx.AsyncClient(timeout=None, follow_redirects=True) as client:
46
+ if not is_file_download:
47
+ r = await client.request(
48
+ request.method,
49
+ url,
50
+ params=params,
51
+ headers=headers,
52
+ content=iter_request_body(),
53
+ )
54
+ resp_headers = {k: v for k, v in r.headers.items() if k.lower() in passthrough_allow}
55
+ return Response(content=r.content, status_code=r.status_code, headers=resp_headers)
56
+
57
+ # /file/...:流式回传,必须保证上游连接在迭代期间保持打开
58
+ req = client.build_request(
59
+ request.method,
60
+ url,
61
+ params=params,
62
+ headers=headers,
63
+ content=iter_request_body(),
64
+ )
65
+ r = await client.send(req, stream=True)
66
+ resp_headers = {k: v for k, v in r.headers.items() if k.lower() in passthrough_allow}
67
+
68
+ async def iter_response():
69
+ try:
70
+ async for chunk in r.aiter_bytes():
71
+ yield chunk
72
+ finally:
73
+ try:
74
+ await r.aclose()
75
+ except Exception:
76
+ pass
77
+
78
+ return StreamingResponse(iter_response(), status_code=r.status_code, headers=resp_headers)
start.sh CHANGED
@@ -6,19 +6,14 @@ if [ -z "${TELEGRAM_API_ID}" ] || [ -z "${TELEGRAM_API_HASH}" ]; then
6
  exit 1
7
  fi
8
 
9
- # Hugging Face 外网只会检查一个端口(README.md 里的 app_port,通常是 7860)。
10
- # 所以“对外服务”(FastAPI/Uvicorn)必须监听 7860(或 $PORT)。
11
- # telegram-bot-api 可以只在容器内部跑(例如 8081),不需要对外暴露。
12
  PUBLIC_PORT="${PORT:-7860}"
13
  UPSTREAM_PORT="${TELEGRAM_UPSTREAM_PORT:-8081}"
14
 
15
- # Hugging Face 容器里最稳妥的可写目录是 /tmp
16
- # 你说“不用持久化也行”,所以把 Bot API 的数据也放 /tmp,避免因为权限导致反复重启
17
  WORK_DIR="${TELEGRAM_WORK_DIR:-/tmp/telegram-bot-api-data}"
18
  TEMP_DIR="${TELEGRAM_TEMP_DIR:-/tmp/telegram-bot-api-tmp}"
19
  mkdir -p "$WORK_DIR" "$TEMP_DIR"
20
 
21
- VERBOSITY="${TELEGRAM_VERBOSITY:-4}"
22
 
23
  telegram-bot-api \
24
  --api-id="${TELEGRAM_API_ID}" \
 
6
  exit 1
7
  fi
8
 
 
 
 
9
  PUBLIC_PORT="${PORT:-7860}"
10
  UPSTREAM_PORT="${TELEGRAM_UPSTREAM_PORT:-8081}"
11
 
 
 
12
  WORK_DIR="${TELEGRAM_WORK_DIR:-/tmp/telegram-bot-api-data}"
13
  TEMP_DIR="${TELEGRAM_TEMP_DIR:-/tmp/telegram-bot-api-tmp}"
14
  mkdir -p "$WORK_DIR" "$TEMP_DIR"
15
 
16
+ VERBOSITY="${TELEGRAM_VERBOSITY:-2}"
17
 
18
  telegram-bot-api \
19
  --api-id="${TELEGRAM_API_ID}" \