feat: 创建 FastAPI 项目骨架(config + main + 依赖管理)
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
# 应用
|
||||||
|
DEBUG=false
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
|
||||||
|
# 数据库
|
||||||
|
DATABASE_URL=postgresql+asyncpg://gx-gp-notify:password@10.10.10.14:5432/gx-gp-notify
|
||||||
|
|
||||||
|
# 爬虫
|
||||||
|
CRAWLER_BASE_URL=https://zfcg.gxzf.gov.cn
|
||||||
|
CRAWLER_KEYWORDS=["大化"]
|
||||||
|
CRAWLER_MAX_PAGES=10
|
||||||
|
CRAWLER_TIMEOUT=30
|
||||||
|
|
||||||
|
# 企业微信
|
||||||
|
WECHAT_ENABLED=true
|
||||||
|
WECHAT_CORP_ID=ww69e8e44636f47780
|
||||||
|
WECHAT_AGENT_ID=1000007
|
||||||
|
WECHAT_SECRET=
|
||||||
|
WECHAT_TOKEN=
|
||||||
|
WECHAT_ENCODING_AES_KEY=
|
||||||
|
WECHAT_PORT=18001
|
||||||
|
WECHAT_HOST=0.0.0.0
|
||||||
|
|
||||||
|
# 定时任务
|
||||||
|
SCHEDULER_ENABLED=true
|
||||||
|
SCHEDULER_CRON=0 8,14,18 * * *
|
||||||
|
|
||||||
|
# Markdown
|
||||||
|
MARKDOWN_ENABLED=true
|
||||||
|
MARKDOWN_OUTPUT_FILE=onu.md
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
.env
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.venv/
|
||||||
|
.ruff_cache/
|
||||||
|
.pytest_cache/
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
|
||||||
|
|
||||||
|
# 应用
|
||||||
|
debug: bool = False
|
||||||
|
log_level: str = "INFO"
|
||||||
|
|
||||||
|
# 数据库
|
||||||
|
database_url: str = "postgresql+asyncpg://gx-gp-notify:password@localhost:5432/gx-gp-notify"
|
||||||
|
|
||||||
|
# 爬虫
|
||||||
|
crawler_base_url: str = "https://zfcg.gxzf.gov.cn"
|
||||||
|
crawler_keywords: List[str] = ["大化"]
|
||||||
|
crawler_max_pages: int = 10
|
||||||
|
crawler_timeout: int = 30
|
||||||
|
crawler_page_size: int = 100
|
||||||
|
|
||||||
|
# 企业微信
|
||||||
|
wechat_enabled: bool = True
|
||||||
|
wechat_corp_id: str = ""
|
||||||
|
wechat_agent_id: str = ""
|
||||||
|
wechat_secret: str = ""
|
||||||
|
wechat_token: str = ""
|
||||||
|
wechat_encoding_aes_key: str = ""
|
||||||
|
wechat_port: int = 18001
|
||||||
|
wechat_host: str = "0.0.0.0"
|
||||||
|
|
||||||
|
# 定时任务
|
||||||
|
scheduler_enabled: bool = True
|
||||||
|
scheduler_cron: str = "0 8,14,18 * * *"
|
||||||
|
|
||||||
|
# Markdown
|
||||||
|
markdown_enabled: bool = True
|
||||||
|
markdown_output_file: str = "onu.md"
|
||||||
|
|
||||||
|
# 公告来源(JSON 字符串,从环境变量读取)
|
||||||
|
announcement_sources: str = '{"ZcyAnnouncement1":{"category_id":66485,"name":"采购公告","type":"purchase"},"ZcyAnnouncement2":{"category_id":66485,"name":"结果公告","type":"result"},"ZcyAnnouncement3":{"category_id":66485,"name":"合同公告","type":"contract"},"ZcyAnnouncement4":{"category_id":66485,"name":"更正公告","type":"correction"},"ZcyAnnouncement5":{"category_id":66485,"name":"招标文件预公示","type":"pre_announcement"},"ZcyAnnouncement6":{"category_id":66485,"name":"单一来源公示","type":"single_source"},"ZcyAnnouncement7":{"category_id":66485,"name":"电子卖场公示","type":"electronic_market"},"ZcyAnnouncement10":{"category_id":66485,"name":"履约验收公示","type":"acceptance"},"ZcyAnnouncement11":{"category_id":66485,"name":"工程类公告","type":"engineering"},"ZcyAnnouncement20":{"category_id":66485,"name":"框架协议征集公告","type":"framework_agreement"},"ZcyAnnouncement21":{"category_id":66485,"name":"框架协议入围结果公告","type":"framework_result"},"ZcyAnnouncement23":{"category_id":66485,"name":"框架协议成交结果汇总公告","type":"framework_summary"},"61-266648":{"category_id":66485,"name":"采购意向公开","type":"intention"}}'
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
import logging
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from app.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
logging.basicConfig(
|
||||||
|
level=getattr(logging, settings.log_level),
|
||||||
|
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||||
|
)
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="广西政府采购网公告监控系统",
|
||||||
|
version="2.0.0",
|
||||||
|
lifespan=lifespan,
|
||||||
|
docs_url="/docs" if settings.debug else None,
|
||||||
|
redoc_url=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
async def health():
|
||||||
|
return {"status": "ok"}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
[project]
|
||||||
|
name = "gx-gp-notify"
|
||||||
|
version = "2.0.0"
|
||||||
|
description = "广西政府采购网公告监控系统"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi>=0.115.0",
|
||||||
|
"uvicorn[standard]>=0.30.0",
|
||||||
|
"sqlalchemy[asyncio]>=2.0.30",
|
||||||
|
"asyncpg>=0.29.0",
|
||||||
|
"alembic>=1.13.0",
|
||||||
|
"httpx>=0.27.0",
|
||||||
|
"apscheduler>=3.10.0",
|
||||||
|
"pydantic-settings>=2.3.0",
|
||||||
|
"beautifulsoup4>=4.12.0",
|
||||||
|
"lxml>=5.2.0",
|
||||||
|
"pycryptodome>=3.20.0",
|
||||||
|
"python-dateutil>=2.9.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"pytest>=8.2.0",
|
||||||
|
"pytest-asyncio>=0.23.0",
|
||||||
|
"pytest-cov>=5.0.0",
|
||||||
|
"ruff>=0.4.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["app*"]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
target-version = "py312"
|
||||||
|
line-length = 100
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "I", "N", "W", "UP"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
asyncio_mode = "auto"
|
||||||
|
testpaths = ["tests"]
|
||||||
Reference in New Issue
Block a user