This commit is contained in:
2026-06-22 10:21:13 +08:00
parent 918405a7e8
commit 37d43bd177
4 changed files with 57 additions and 10 deletions
+2
View File
@@ -1,3 +1,5 @@
# Reverse-proxy subpath, e.g. /openocr when served at https://example.com/openocr/
OPENOCR_ROOT_PATH=
OPENOCR_OUTPUT_DIR=data/output
OPENOCR_UPLOAD_DIR=data/uploads
OPENOCR_USE_GPU=false
+30
View File
@@ -163,6 +163,7 @@ docker compose up -d --build # 重新构建并启动
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `OPENOCR_ROOT_PATH` | *(空)* | 反向代理子路径,如 `/openocr` |
| `OPENOCR_OUTPUT_DIR` | `data/output` | 解析结果输出目录 |
| `OPENOCR_UPLOAD_DIR` | `data/uploads` | 上传文件临时目录 |
| `OPENOCR_USE_GPU` | `false` | 是否使用 GPU |
@@ -191,6 +192,35 @@ docker compose up -d --build # 重新构建并启动
└── .env.example
```
## 反向代理(Nginx 子路径)
若通过 `https://jsuse.com/openocr/` 这类**子路径**访问(而非直接 `:8000`),必须在 `.env` 中设置:
```env
OPENOCR_ROOT_PATH=/openocr
```
否则 `/health` 可能正常,但 `/docs` 会报 **Failed to load API definition**——因为 Swagger 会去根路径请求 `/openapi.json`,而不是 `/openocr/openapi.json`
Nginx 参考配置:
```nginx
location /openocr/ {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
修改后重启容器:
```bash
docker compose up -d --build
```
---
## 注意事项
- `.env``data/`、模型缓存目录已在 `.gitignore` 中排除,不会进入 Git
+17 -10
View File
@@ -36,7 +36,7 @@ def create_app() -> FastAPI:
settings.output_dir.mkdir(parents=True, exist_ok=True)
settings.upload_dir.mkdir(parents=True, exist_ok=True)
app = FastAPI(title=settings.app_name)
app = FastAPI(title=settings.app_name, root_path=settings.root_path or "")
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origin_list,
@@ -51,7 +51,7 @@ def create_app() -> FastAPI:
@app.get("/", include_in_schema=False)
async def root() -> RedirectResponse:
return RedirectResponse(url="/docs")
return RedirectResponse(url=settings.url_path("/docs"))
@app.get("/health")
async def health() -> dict[str, str]:
@@ -71,9 +71,15 @@ def create_app() -> FastAPI:
items.append(
HistoryItem(
id=item_dir.name,
markdown_url=f"/output/{item_dir.name}/{markdown_file.name}",
json_url=f"/output/{item_dir.name}/{json_file.name}" if json_file else None,
source_url=f"/output/{item_dir.name}/{source_file.name}" if source_file else None,
markdown_url=settings.url_path(
f"/output/{item_dir.name}/{markdown_file.name}"
),
json_url=settings.url_path(f"/output/{item_dir.name}/{json_file.name}")
if json_file
else None,
source_url=settings.url_path(f"/output/{item_dir.name}/{source_file.name}")
if source_file
else None,
updated_at=markdown_file.stat().st_mtime,
)
)
@@ -104,8 +110,8 @@ def create_app() -> FastAPI:
id=doc_id,
status="success",
message="Existing result reused. Set force=true to re-run.",
markdown_url=f"/output/{doc_id}/{markdown_file.name}",
json_url=f"/output/{doc_id}/{doc_id}.json",
markdown_url=settings.url_path(f"/output/{doc_id}/{markdown_file.name}"),
json_url=settings.url_path(f"/output/{doc_id}/{doc_id}.json"),
)
output_dir.mkdir(parents=True, exist_ok=True)
@@ -130,9 +136,9 @@ def create_app() -> FastAPI:
id=doc_id,
status="success",
message=f"Parsed successfully in {elapsed}s.",
markdown_url=f"/output/{doc_id}/{doc_id}.md",
json_url=f"/output/{doc_id}/{doc_id}.json",
source_url=f"/output/{doc_id}/{source_path.name}",
markdown_url=settings.url_path(f"/output/{doc_id}/{doc_id}.md"),
json_url=settings.url_path(f"/output/{doc_id}/{doc_id}.json"),
source_url=settings.url_path(f"/output/{doc_id}/{source_path.name}"),
)
app.mount("/output", StaticFiles(directory=settings.output_dir), name="output")
@@ -149,6 +155,7 @@ def main() -> None:
port=8000,
reload=False,
log_level=settings.log_level,
root_path=settings.root_path or "",
)
+8
View File
@@ -11,6 +11,7 @@ class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
app_name: str = "OpenOCR Markdown Service"
root_path: str = Field(default="", alias="OPENOCR_ROOT_PATH")
output_dir: Path = Field(default=Path("data/output"), alias="OPENOCR_OUTPUT_DIR")
upload_dir: Path = Field(default=Path("data/uploads"), alias="OPENOCR_UPLOAD_DIR")
use_gpu: bool = Field(default=False, alias="OPENOCR_USE_GPU")
@@ -29,5 +30,12 @@ class Settings(BaseSettings):
return ["*"]
return [origin.strip() for origin in self.cors_origins.split(",") if origin.strip()]
def url_path(self, path: str) -> str:
"""Build a public URL path, honoring reverse-proxy root prefix."""
prefix = self.root_path.rstrip("/")
if not prefix:
return path
return f"{prefix}{path}"
settings = Settings()