diff --git a/.env.prod b/.env.prod index 7c05f6c..64b55db 100644 --- a/.env.prod +++ b/.env.prod @@ -20,3 +20,11 @@ VOLCENGINE_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 # Claude(Anthropic 风格) ANTHROPIC_API_KEY=sk-43ccdb29caa7e9ebe0db8ac0958c63f6d3a2d62e59064d3d26d94332055a9bc9 ANTHROPIC_BASE_URL=https://code.warpdevloper.cloud + + +# 阿里云 OSS +OSS_ACCESS_KEY_ID=LTAI5tEdLKKQUKhTyUpfH5Mk +OSS_ACCESS_KEY_SECRET=RjUdTrq0V5qA4b3BUElNhXqs3ZLp5k +OSS_ENDPOINT=oss-cn-guangzhou.aliyuncs.com +OSS_BUCKET=offerpie +OSS_DOMAIN=https://offerpie.oss-cn-guangzhou.aliyuncs.com \ No newline at end of file diff --git a/.env.test b/.env.test index ffd6e44..38d0231 100644 --- a/.env.test +++ b/.env.test @@ -20,3 +20,11 @@ VOLCENGINE_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 # Claude(Anthropic 风格) ANTHROPIC_API_KEY=sk-43ccdb29caa7e9ebe0db8ac0958c63f6d3a2d62e59064d3d26d94332055a9bc9 ANTHROPIC_BASE_URL=https://code.warpdevloper.cloud + + +# 阿里云 OSS +OSS_ACCESS_KEY_ID=LTAI5tEdLKKQUKhTyUpfH5Mk +OSS_ACCESS_KEY_SECRET=RjUdTrq0V5qA4b3BUElNhXqs3ZLp5k +OSS_ENDPOINT=oss-cn-guangzhou.aliyuncs.com +OSS_BUCKET=offerpie +OSS_DOMAIN=https://offerpie.oss-cn-guangzhou.aliyuncs.com \ No newline at end of file diff --git a/app/config/settings.py b/app/config/settings.py index 3fd374e..23a8282 100644 --- a/app/config/settings.py +++ b/app/config/settings.py @@ -26,6 +26,14 @@ class Settings(BaseSettings): anthropic_api_key: str = "" anthropic_base_url: str = "" + # ──────────── 阿里云 OSS ──────────── + oss_access_key_id: str = "" + oss_access_key_secret: str = "" + oss_endpoint: str = "oss-cn-guangzhou.aliyuncs.com" + oss_bucket: str = "offerpie" + oss_upload_dir: str = "company/logo" + oss_domain: str = "https://offerpie.oss-cn-guangzhou.aliyuncs.com" + # ──────────── 日志 ──────────── logging_level: str = "INFO" log_file_name: str = "spider.log" diff --git a/app/core/oss.py b/app/core/oss.py new file mode 100644 index 0000000..b296be6 --- /dev/null +++ b/app/core/oss.py @@ -0,0 +1,51 @@ +"""阿里云 OSS 图片上传工具。""" + +from __future__ import annotations + +import os +from urllib.parse import unquote, urlparse +from uuid import uuid4 + +import oss2 + +from app.config import settings +from app.core.logger import log +from app.tool.image_download import download_image + +_auth = oss2.Auth(settings.oss_access_key_id, settings.oss_access_key_secret) +_bucket = oss2.Bucket(_auth, f"https://{settings.oss_endpoint}", settings.oss_bucket) + + +def _get_file_name(image_url: str) -> str: + """从图片 URL 提取文件名,无扩展名时默认使用 PNG。""" + path = unquote(urlparse(image_url).path) + file_name = os.path.basename(path) + if not file_name or not os.path.splitext(file_name)[1]: + return "image.png" + return file_name + + +def upload(data: bytes, file_name: str) -> str: + """上传图片字节到固定目录,返回 OSS URL。""" + key = f"{settings.oss_upload_dir}/{uuid4().hex[:18]}{os.path.splitext(file_name)[1]}" + _bucket.put_object(key, data) + url = f"{settings.oss_domain}/{key}" + log.info("OSS 上传成功 [{}] -> {}", file_name, url) + return url + + +def upload_image_url(image_url: str) -> str | None: + """下载图片 URL 并上传到 OSS,成功时返回 OSS URL。""" + if not image_url or not image_url.strip(): + return None + + image_url = image_url.strip() + image = download_image(image_url) + if image is None: + return None + + try: + return upload(image, _get_file_name(image_url)) + except Exception as exc: + log.warning("图片上传 OSS 失败 [{}]: {}", image_url, exc) + return None diff --git a/app/service/__init__.py b/app/service/__init__.py new file mode 100644 index 0000000..829d0ed --- /dev/null +++ b/app/service/__init__.py @@ -0,0 +1 @@ +"""业务服务层。""" diff --git a/app/service/recruit_announcement_service.py b/app/service/recruit_announcement_service.py new file mode 100644 index 0000000..76658fa --- /dev/null +++ b/app/service/recruit_announcement_service.py @@ -0,0 +1,7 @@ +"""招聘公告业务服务。""" + + +class RecruitAnnouncementService: + """编排公告爬取、AI 信息提取与数据库保存。""" + + pass diff --git a/requirements.txt b/requirements.txt index aa7f0f8..8ad7f54 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,4 +17,5 @@ langchain-core>=0.3 # 工具 loguru>=0.7 +oss2==2.19.1 snowflake-id>=1.0