支持自定义端口
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
DEEPSEEK_API_KEY=your-api-key
|
DEEPSEEK_API_KEY=your-api-key
|
||||||
|
SERVICE_PORT=8000
|
||||||
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||||
DEEPSEEK_MODEL=deepseek-v4-flash
|
DEEPSEEK_MODEL=deepseek-v4-flash
|
||||||
DEFAULT_SYSTEM_PROMPT=You are a helpful assistant.
|
DEFAULT_SYSTEM_PROMPT=You are a helpful assistant.
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv sync
|
uv sync
|
||||||
export DEEPSEEK_API_KEY="your-api-key"
|
cp .env.example .env
|
||||||
|
# 编辑 .env 并填写 DEEPSEEK_API_KEY
|
||||||
uv run uvicorn main:app --reload
|
uv run uvicorn main:app --reload
|
||||||
```
|
```
|
||||||
|
|
||||||
服务默认运行在 `http://127.0.0.1:8000`,交互式 API 文档位于 `/docs`。
|
服务默认运行在 `http://127.0.0.1:8000`,交互式 API 文档位于 `/docs`。
|
||||||
|
|
||||||
可通过环境变量配置 `DEEPSEEK_BASE_URL`、`DEEPSEEK_MODEL`、`DEFAULT_SYSTEM_PROMPT` 和 `CHAT_DATA_DIR`,完整示例见 `.env.example`。第一版应只使用一个 Uvicorn worker。
|
服务会自动加载项目根目录的 `.env`,已有系统环境变量优先级更高。可配置 `DEEPSEEK_BASE_URL`、`DEEPSEEK_MODEL`、`DEFAULT_SYSTEM_PROMPT` 和 `CHAT_DATA_DIR`,完整示例见 `.env.example`。第一版应只使用一个 Uvicorn worker。
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ from dataclasses import dataclass
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True, slots=True)
|
||||||
class Settings:
|
class Settings:
|
||||||
|
port: int
|
||||||
api_key: str | None
|
api_key: str | None
|
||||||
base_url: str
|
base_url: str
|
||||||
model: str
|
model: str
|
||||||
@@ -13,7 +16,9 @@ class Settings:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_env(cls) -> "Settings":
|
def from_env(cls) -> "Settings":
|
||||||
|
load_dotenv(dotenv_path=Path.cwd() / ".env", override=False)
|
||||||
return cls(
|
return cls(
|
||||||
|
port=int(os.getenv("SERVICE_PORT", "8000")),
|
||||||
api_key=os.getenv("DEEPSEEK_API_KEY"),
|
api_key=os.getenv("DEEPSEEK_API_KEY"),
|
||||||
base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"),
|
base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"),
|
||||||
model=os.getenv("DEEPSEEK_MODEL", "deepseek-v4-flash"),
|
model=os.getenv("DEEPSEEK_MODEL", "deepseek-v4-flash"),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from app import app
|
from app import app
|
||||||
|
from config import Settings
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
settings = Settings.from_env()
|
||||||
|
uvicorn.run("main:app", host="0.0.0.0", port=settings.port, reload=True)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ dependencies = [
|
|||||||
"fastapi>=0.115.0",
|
"fastapi>=0.115.0",
|
||||||
"httpx[socks]>=0.28.0",
|
"httpx[socks]>=0.28.0",
|
||||||
"openai>=1.55.0",
|
"openai>=1.55.0",
|
||||||
|
"python-dotenv>=1.0.0",
|
||||||
"uvicorn[standard]>=0.32.0",
|
"uvicorn[standard]>=0.32.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class FakeClient:
|
|||||||
def client_and_provider(tmp_path: Path) -> tuple[TestClient, FakeClient]:
|
def client_and_provider(tmp_path: Path) -> tuple[TestClient, FakeClient]:
|
||||||
provider = FakeClient()
|
provider = FakeClient()
|
||||||
settings = Settings(
|
settings = Settings(
|
||||||
|
port=8000,
|
||||||
api_key=None,
|
api_key=None,
|
||||||
base_url="https://api.deepseek.com",
|
base_url="https://api.deepseek.com",
|
||||||
model="deepseek-v4-flash",
|
model="deepseek-v4-flash",
|
||||||
@@ -66,6 +67,18 @@ def create_session(client: TestClient, **body: str) -> str:
|
|||||||
return response.json()["session_id"]
|
return response.json()["session_id"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_settings_load_api_key_from_dotenv(
|
||||||
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False)
|
||||||
|
(tmp_path / ".env").write_text("DEEPSEEK_API_KEY=test-key\n")
|
||||||
|
|
||||||
|
settings = Settings.from_env()
|
||||||
|
|
||||||
|
assert settings.api_key == "test-key"
|
||||||
|
|
||||||
|
|
||||||
def test_create_session_uses_default_prompt(
|
def test_create_session_uses_default_prompt(
|
||||||
client_and_provider: tuple[TestClient, FakeClient], tmp_path: Path
|
client_and_provider: tuple[TestClient, FakeClient], tmp_path: Path
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@@ -366,6 +366,7 @@ dependencies = [
|
|||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "httpx", extra = ["socks"] },
|
{ name = "httpx", extra = ["socks"] },
|
||||||
{ name = "openai" },
|
{ name = "openai" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
{ name = "uvicorn", extra = ["standard"] },
|
{ name = "uvicorn", extra = ["standard"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -379,6 +380,7 @@ requires-dist = [
|
|||||||
{ name = "fastapi", specifier = ">=0.115.0" },
|
{ name = "fastapi", specifier = ">=0.115.0" },
|
||||||
{ name = "httpx", extras = ["socks"], specifier = ">=0.28.0" },
|
{ name = "httpx", extras = ["socks"], specifier = ">=0.28.0" },
|
||||||
{ name = "openai", specifier = ">=1.55.0" },
|
{ name = "openai", specifier = ">=1.55.0" },
|
||||||
|
{ name = "python-dotenv", specifier = ">=1.0.0" },
|
||||||
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" },
|
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.32.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user