sub-path 배포 지원 (root_path) + HTML 상대경로화
Apache 리버스 프록시로 /plagiarism 같은 sub-path에 배포 가능하도록: - config.Settings.root_path 추가 (.env의 ROOT_PATH) - FastAPI app(root_path=...) + uvicorn run(root_path=..., proxy_headers=True, forwarded_allow_ips="*") - index.html의 모든 절대경로(/v1/..., /docs, /openapi.json)를 상대경로로 변경 - .env / .env.example 에 ROOT_PATH 추가 URL 직접 노출(localhost:8000)이든 sub-path(/plagiarism)든 모두 동작.main
parent
66dea0cc52
commit
b8370f5c1a
|
|
@ -3,6 +3,8 @@ HOST=0.0.0.0
|
|||
PORT=8000
|
||||
LOG_LEVEL=info
|
||||
RELOAD=false
|
||||
# 리버스 프록시 sub-path 배포 시. 예: /plagiarism (Apache가 /plagiarism → 컨테이너 매핑할 때)
|
||||
ROOT_PATH=
|
||||
|
||||
ENGINE_VERSION=o2o-plagiarism-2.1.0-kosimcse
|
||||
REFERENCE_CORPUS_DIR=./data/reference
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class Settings(BaseSettings):
|
|||
port: int = 8000
|
||||
log_level: str = "info" # debug / info / warning / error
|
||||
reload: bool = False # 개발용 자동 재시작
|
||||
root_path: str = "" # 리버스 프록시 sub-path (예: /plagiarism)
|
||||
|
||||
engine_version: str = "o2o-plagiarism-2.0.0-pdf-v1.2"
|
||||
reference_corpus_dir: str = "./data/reference"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ def rebuild_detector(app: FastAPI) -> int:
|
|||
return app.state.detector.corpus_size
|
||||
|
||||
|
||||
_settings = get_settings()
|
||||
|
||||
app = FastAPI(
|
||||
title="O2O 저작권 침해 여부 탐지 API",
|
||||
description=(
|
||||
|
|
@ -48,6 +50,7 @@ app = FastAPI(
|
|||
),
|
||||
version="1.0.0",
|
||||
lifespan=lifespan,
|
||||
root_path=_settings.root_path,
|
||||
)
|
||||
|
||||
app.include_router(api_router)
|
||||
|
|
@ -83,6 +86,9 @@ def main() -> None:
|
|||
port=settings.port,
|
||||
log_level=settings.log_level,
|
||||
reload=settings.reload,
|
||||
root_path=settings.root_path,
|
||||
forwarded_allow_ips="*", # 리버스 프록시(Apache) 헤더 신뢰
|
||||
proxy_headers=True,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -351,8 +351,8 @@
|
|||
</main>
|
||||
|
||||
<footer>
|
||||
<a href="/docs">API 문서 (Swagger)</a> ·
|
||||
<a href="/openapi.json">OpenAPI 스펙</a> ·
|
||||
<a href="docs">API 문서 (Swagger)</a> ·
|
||||
<a href="openapi.json">OpenAPI 스펙</a> ·
|
||||
엔진 버전: <span id="engine-version">…</span> ·
|
||||
레퍼런스 코퍼스: <span id="corpus-size">…</span>건
|
||||
</footer>
|
||||
|
|
@ -445,7 +445,7 @@ async function runDetect() {
|
|||
document.getElementById("result-body").style.display = "none";
|
||||
|
||||
try {
|
||||
const resp = await fetch("/v1/plagiarism/detect", {
|
||||
const resp = await fetch("v1/plagiarism/detect", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
|
|
@ -613,7 +613,7 @@ async function loadCorpus() {
|
|||
const tbody = document.getElementById("corpus-tbody");
|
||||
tbody.innerHTML = '<tr><td colspan="4" style="color: var(--muted); text-align: center; padding: 20px;">로딩 중…</td></tr>';
|
||||
try {
|
||||
const resp = await fetch("/v1/corpus");
|
||||
const resp = await fetch("v1/corpus");
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
document.getElementById("corpus-count").textContent = data.total;
|
||||
|
|
@ -664,9 +664,9 @@ async function uploadCorpus() {
|
|||
fd.append("title", title);
|
||||
if (docId) fd.append("doc_id", docId);
|
||||
fd.append("file", file);
|
||||
resp = await fetch("/v1/corpus/file", { method: "POST", body: fd });
|
||||
resp = await fetch("v1/corpus/file", { method: "POST", body: fd });
|
||||
} else {
|
||||
resp = await fetch("/v1/corpus", {
|
||||
resp = await fetch("v1/corpus", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ doc_id: docId || null, title, text }),
|
||||
|
|
@ -695,7 +695,7 @@ async function uploadCorpus() {
|
|||
async function deleteDoc(docId) {
|
||||
if (!confirm(`'${docId}' 문서를 삭제하시겠습니까? 인덱스가 재빌드됩니다.`)) return;
|
||||
try {
|
||||
const resp = await fetch(`/v1/corpus/${encodeURIComponent(docId)}`, {
|
||||
const resp = await fetch(`v1/corpus/${encodeURIComponent(docId)}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!resp.ok && resp.status !== 204) {
|
||||
|
|
@ -728,7 +728,7 @@ function escapeJs(s) {
|
|||
// 헬스 체크 + 코퍼스 정보 표시
|
||||
async function checkHealth() {
|
||||
try {
|
||||
const resp = await fetch("/v1/health");
|
||||
const resp = await fetch("v1/health");
|
||||
if (!resp.ok) throw new Error("not ok");
|
||||
const data = await resp.json();
|
||||
const autobio = data.autobiography_mode ? ' · 자서전모드' : '';
|
||||
|
|
|
|||
Loading…
Reference in New Issue