增加swagger的离线模式
This commit is contained in:
parent
3eaf290b6d
commit
2b70de0e92
|
|
@ -127,3 +127,7 @@ models/
|
|||
|
||||
# docker export
|
||||
docker-images-export/
|
||||
|
||||
# Swagger UI static assets (keep these for offline use)
|
||||
# Uncomment the line below if you don't want to commit downloaded assets
|
||||
# static/swagger-ui/
|
||||
|
|
|
|||
|
|
@ -43,7 +43,11 @@ RUN pip install --upgrade pip && \
|
|||
COPY . /app/
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p /app/chroma_db /app/logs
|
||||
RUN mkdir -p /app/chroma_db /app/logs /app/static/swagger-ui
|
||||
|
||||
# 可选:如果在构建时有网络连接,可以下载 Swagger UI 资源
|
||||
# 取消下面的注释以在构建时自动下载资源(需要网络连接)
|
||||
# RUN python download_swagger_assets.py || echo "Warning: Failed to download Swagger UI assets. Run download_swagger_assets.py manually if needed."
|
||||
|
||||
# 暴露端口(注意:使用 host 网络模式时,EXPOSE 仅作文档说明)
|
||||
EXPOSE 8001
|
||||
|
|
|
|||
97
api/main.py
97
api/main.py
|
|
@ -10,7 +10,9 @@ warnings.filterwarnings("ignore", message=".*pkg_resources is deprecated.*", cat
|
|||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
from fastapi import FastAPI, HTTPException, UploadFile, File, Form
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.responses import StreamingResponse, Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, List
|
||||
from loguru import logger
|
||||
|
|
@ -170,14 +172,105 @@ async def lifespan(app: FastAPI):
|
|||
logger.info("RAG services shut down")
|
||||
|
||||
|
||||
# Check if static assets are available for offline use
|
||||
STATIC_DIR = Path(__file__).parent.parent / "static" / "swagger-ui"
|
||||
SWAGGER_UI_BUNDLE = STATIC_DIR / "swagger-ui-bundle.js"
|
||||
SWAGGER_UI_CSS = STATIC_DIR / "swagger-ui.css"
|
||||
REDOC_BUNDLE = STATIC_DIR / "redoc.standalone.js"
|
||||
|
||||
# Determine if we should use local assets or CDN
|
||||
USE_LOCAL_ASSETS = (
|
||||
SWAGGER_UI_BUNDLE.exists() and
|
||||
SWAGGER_UI_CSS.exists() and
|
||||
REDOC_BUNDLE.exists()
|
||||
)
|
||||
|
||||
if USE_LOCAL_ASSETS:
|
||||
logger.info("Using local Swagger UI assets for offline mode")
|
||||
else:
|
||||
logger.warning(
|
||||
"Local Swagger UI assets not found. Swagger UI will use CDN resources. "
|
||||
"For offline use, run: python download_swagger_assets.py"
|
||||
)
|
||||
|
||||
# Initialize FastAPI app
|
||||
app = FastAPI(
|
||||
title=settings.API_TITLE,
|
||||
version=settings.API_VERSION,
|
||||
description="RAG API for local knowledge base retrieval and generation",
|
||||
lifespan=lifespan
|
||||
lifespan=lifespan,
|
||||
swagger_ui_parameters={
|
||||
"persistAuthorization": True,
|
||||
},
|
||||
)
|
||||
|
||||
# Mount static files directory if it exists
|
||||
if STATIC_DIR.exists():
|
||||
app.mount("/static/swagger-ui", StaticFiles(directory=str(STATIC_DIR)), name="swagger-ui-static")
|
||||
|
||||
|
||||
# Add favicon route to prevent 404 errors
|
||||
@app.get("/favicon.ico", include_in_schema=False)
|
||||
async def favicon():
|
||||
"""Return empty favicon to prevent 404 errors"""
|
||||
# Return a minimal 1x1 transparent PNG
|
||||
# This prevents browser from requesting favicon and getting 404
|
||||
return Response(
|
||||
content=b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n-\xdb\x00\x00\x00\x00IEND\xaeB`\x82',
|
||||
media_type="image/png"
|
||||
)
|
||||
|
||||
|
||||
# Override Swagger UI to use local assets when available
|
||||
@app.get("/docs", include_in_schema=False)
|
||||
async def custom_swagger_ui_html():
|
||||
"""Custom Swagger UI that uses local assets in offline mode"""
|
||||
if USE_LOCAL_ASSETS:
|
||||
# Use local static files
|
||||
return get_swagger_ui_html(
|
||||
openapi_url=app.openapi_url,
|
||||
title=app.title + " - Swagger UI",
|
||||
swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",
|
||||
swagger_css_url="/static/swagger-ui/swagger-ui.css",
|
||||
swagger_favicon_url="/favicon.ico",
|
||||
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
|
||||
init_oauth=app.swagger_ui_init_oauth,
|
||||
swagger_ui_parameters=app.swagger_ui_parameters,
|
||||
)
|
||||
else:
|
||||
# Fallback to default (CDN)
|
||||
return get_swagger_ui_html(
|
||||
openapi_url=app.openapi_url,
|
||||
title=app.title + " - Swagger UI",
|
||||
swagger_favicon_url="/favicon.ico",
|
||||
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
|
||||
init_oauth=app.swagger_ui_init_oauth,
|
||||
swagger_ui_parameters=app.swagger_ui_parameters,
|
||||
)
|
||||
|
||||
|
||||
# Override ReDoc to use local assets when available
|
||||
@app.get("/redoc", include_in_schema=False)
|
||||
async def custom_redoc_html():
|
||||
"""Custom ReDoc that uses local assets in offline mode"""
|
||||
if USE_LOCAL_ASSETS:
|
||||
# Use local static files
|
||||
return get_redoc_html(
|
||||
openapi_url=app.openapi_url,
|
||||
title=app.title + " - ReDoc",
|
||||
redoc_js_url="/static/swagger-ui/redoc.standalone.js",
|
||||
redoc_favicon_url="/favicon.ico",
|
||||
with_google_fonts=False, # Disable Google Fonts for offline use
|
||||
)
|
||||
else:
|
||||
# Fallback to default (CDN)
|
||||
return get_redoc_html(
|
||||
openapi_url=app.openapi_url,
|
||||
title=app.title + " - ReDoc",
|
||||
redoc_favicon_url="/favicon.ico",
|
||||
with_google_fonts=True,
|
||||
)
|
||||
|
||||
|
||||
# Request/Response models
|
||||
class QueryRequest(BaseModel):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Download Swagger UI and ReDoc static assets for offline use
|
||||
Run this script once in an online environment to download necessary assets
|
||||
"""
|
||||
import os
|
||||
import urllib.request
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Swagger UI version and assets
|
||||
SWAGGER_UI_VERSION = "5.9.0"
|
||||
SWAGGER_UI_ASSETS = {
|
||||
"swagger-ui-bundle.js": f"https://cdn.jsdelivr.net/npm/swagger-ui-dist@{SWAGGER_UI_VERSION}/swagger-ui-bundle.js",
|
||||
"swagger-ui-standalone-preset.js": f"https://cdn.jsdelivr.net/npm/swagger-ui-dist@{SWAGGER_UI_VERSION}/swagger-ui-standalone-preset.js",
|
||||
"swagger-ui.css": f"https://cdn.jsdelivr.net/npm/swagger-ui-dist@{SWAGGER_UI_VERSION}/swagger-ui.css",
|
||||
}
|
||||
|
||||
# ReDoc version and assets
|
||||
REDOC_VERSION = "2.1.3"
|
||||
REDOC_ASSETS = {
|
||||
"redoc.standalone.js": f"https://cdn.jsdelivr.net/npm/redoc@{REDOC_VERSION}/bundles/redoc.standalone.js",
|
||||
}
|
||||
|
||||
# Output directory
|
||||
STATIC_DIR = Path(__file__).parent / "static" / "swagger-ui"
|
||||
STATIC_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def download_file(url: str, filepath: Path):
|
||||
"""Download a file from URL to filepath"""
|
||||
print(f"Downloading {filepath.name}...")
|
||||
try:
|
||||
urllib.request.urlretrieve(url, filepath)
|
||||
print(f"✓ Downloaded {filepath.name}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Failed to download {filepath.name}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""Download all Swagger UI and ReDoc assets"""
|
||||
print("=" * 60)
|
||||
print("Downloading Swagger UI and ReDoc assets for offline use")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
success_count = 0
|
||||
total_count = len(SWAGGER_UI_ASSETS) + len(REDOC_ASSETS)
|
||||
|
||||
# Download Swagger UI assets
|
||||
print("Downloading Swagger UI assets...")
|
||||
for filename, url in SWAGGER_UI_ASSETS.items():
|
||||
filepath = STATIC_DIR / filename
|
||||
if download_file(url, filepath):
|
||||
success_count += 1
|
||||
print()
|
||||
|
||||
# Download ReDoc assets
|
||||
print("Downloading ReDoc assets...")
|
||||
for filename, url in REDOC_ASSETS.items():
|
||||
filepath = STATIC_DIR / filename
|
||||
if download_file(url, filepath):
|
||||
success_count += 1
|
||||
print()
|
||||
|
||||
# Save version info
|
||||
version_info = {
|
||||
"swagger_ui_version": SWAGGER_UI_VERSION,
|
||||
"redoc_version": REDOC_VERSION,
|
||||
"assets": {
|
||||
**{f"swagger-ui/{k}": k for k in SWAGGER_UI_ASSETS.keys()},
|
||||
**{f"swagger-ui/{k}": k for k in REDOC_ASSETS.keys()},
|
||||
}
|
||||
}
|
||||
version_file = STATIC_DIR / "version.json"
|
||||
with open(version_file, "w") as f:
|
||||
json.dump(version_info, f, indent=2)
|
||||
print(f"✓ Saved version info to {version_file}")
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
if success_count == total_count:
|
||||
print(f"✓ Successfully downloaded all {total_count} assets")
|
||||
print(f"Assets saved to: {STATIC_DIR}")
|
||||
print()
|
||||
print("You can now use the API in offline mode!")
|
||||
else:
|
||||
print(f"⚠️ Downloaded {success_count}/{total_count} assets")
|
||||
print("Some assets failed to download. Please check your internet connection.")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Loading…
Reference in New Issue