feat(third_party_api): 添加Dify工作流支持并优化API管理

重构UniversalAPIManager以支持Dify工作流API
添加DifyWorkflowRequest模型和控制器方法
优化API密钥管理和请求处理逻辑
修改JWT验证方式从HTTPBearer到Header
更新API配置以支持新的Dify端点
This commit is contained in:
邹方成 2025-10-10 13:04:10 +08:00
parent 9779c79516
commit 107e90cbcb
8 changed files with 4804 additions and 196 deletions

View File

@ -9,8 +9,10 @@ from app.schemas.valuation import (
UserValuationOut, UserValuationOut,
UserValuationDetail UserValuationDetail
) )
from app.models.user import AppUser
from app.schemas.base import Success, SuccessExtra from app.schemas.base import Success, SuccessExtra
from app.utils.app_user_jwt import get_current_app_user_id from app.utils.app_user_jwt import get_current_app_user
app_valuations_router = APIRouter(tags=["用户端估值评估"]) app_valuations_router = APIRouter(tags=["用户端估值评估"])
@ -18,19 +20,70 @@ app_valuations_router = APIRouter(tags=["用户端估值评估"])
@app_valuations_router.post("/", summary="创建估值评估") @app_valuations_router.post("/", summary="创建估值评估")
async def create_valuation( async def create_valuation(
data: UserValuationCreate, data: UserValuationCreate,
user_id: int = Depends(get_current_app_user_id) current_user: AppUser = Depends(get_current_app_user)
): ):
""" """
用户创建估值评估申请 用户创建估值评估申请
""" """
try: try:
result = await user_valuation_controller.create_valuation( result = await user_valuation_controller.create_valuation(
user_id=user_id, user_id=current_user.id,
data=data data=data
) )
# 使用model_dump_json()来正确序列化datetime然后解析为dict # 使用model_dump_json()来正确序列化datetime然后解析为dict
import json import json
result_dict = json.loads(result.model_dump_json()) result_dict = json.loads(result.model_dump_json())
# 开始计算 估值 信息
# 1 # 经济价值B1模块: EconomicValueB1Calculator | BasicValueB11Calculator | TrafficFactorB12Calculator | PolicyMultiplierB13Calculator
# 1.1 EconomicValueB1Calculator
# input_data = {
# # 基础价值B11相关参数
# 'three_year_income': data.three_year_income,
# 'patent_score': data.pa, # 专利分
# 'popularity_score': data.popularity_score, # 普及地域分值
# 'infringement_score': data.infringement_score, # 侵权分
# 'innovation_ratio': data.innovation_ratio,
# 'esg_score':data.esg_score,
# 'industry_coefficient':data.industry_coefficient,
# # 流量因子B12相关参数
# 'search_index_s1': 4500.0,
# 'industry_average_s2': 5000.0,
# # 'social_media_spread_s3': social_media_spread_s3,
# 'likes': 4, # 点赞
# 'comments': 5, # 评论
# 'shares': 6, # 转发
# 'followers': 7, # 粉丝数
# 'click_count': 1000,# 点击量
# 'view_count': 100, # 内容浏览量
# # 政策乘数B13相关参数
# 'policy_match_score': 10.0, # 政策匹配度
# 'implementation_stage': 10.0, # 实施阶段评分
# 'funding_support': 10.0 # 资金支持度
# }
# 1.2 BasicValueB11Calculator
# 1.3 TrafficFactorB12Calculator
# 1.4 PolicyMultiplierB13Calculator
# 2 # 文化价值B2模块: CulturalValueB2Calculator | LivingHeritageB21Calculator | PatternGeneB22Calculator
# 2.1 CulturalValueB2Calculator
# 2.2 LivingHeritageB21Calculator
# 2.3 PatternGeneB22Calculator
# 3 # 风险调整系数B3模块: RiskAdjustmentB3Calculator
# 3.1 RiskAdjustmentB3Calculator
# 4 # 市场估值C模块: MarketValueCCalculator | MarketBiddingC1Calculator | HeatCoefficientC2Calculator | ScarcityMultiplierC3Calculator | TemporalDecayC4Calculator
# 4.1 MarketValueCCalculator
# 4.2 MarketBiddingC1Calculator
# 4.3 HeatCoefficientC2Calculator
# 4.4 ScarcityMultiplierC3Calculator
# 4.5 TemporalDecayC4Calculator
# 5 # 最终估值A模块: FinalValueACalculator
# 5.1 FinalValueACalculator
return Success(data=result_dict, msg="估值评估申请提交成功") return Success(data=result_dict, msg="估值评估申请提交成功")
except Exception as e: except Exception as e:
raise HTTPException( raise HTTPException(
@ -42,14 +95,15 @@ async def create_valuation(
@app_valuations_router.get("/", summary="获取我的估值评估列表") @app_valuations_router.get("/", summary="获取我的估值评估列表")
async def get_my_valuations( async def get_my_valuations(
query: UserValuationQuery = Depends(), query: UserValuationQuery = Depends(),
user_id: int = Depends(get_current_app_user_id) current_user: AppUser = Depends(get_current_app_user)
): ):
""" """
获取当前用户的估值评估列表 获取当前用户的估值评估列表
""" """
try: try:
result = await user_valuation_controller.get_user_valuations( result = await user_valuation_controller.get_user_valuations(
user_id=user_id, user_id=current_user.id,
query=query query=query
) )
# 使用model_dump_json()来正确序列化datetime然后解析为dict列表 # 使用model_dump_json()来正确序列化datetime然后解析为dict列表
@ -73,14 +127,14 @@ async def get_my_valuations(
@app_valuations_router.get("/{valuation_id}", summary="获取估值评估详情") @app_valuations_router.get("/{valuation_id}", summary="获取估值评估详情")
async def get_valuation_detail( async def get_valuation_detail(
valuation_id: int, valuation_id: int,
user_id: int = Depends(get_current_app_user_id) current_user: AppUser = Depends(get_current_app_user)
): ):
""" """
获取指定估值评估的详细信息 获取指定估值评估的详细信息
""" """
try: try:
result = await user_valuation_controller.get_user_valuation_detail( result = await user_valuation_controller.get_user_valuation_detail(
user_id=user_id, user_id=current_user.id,
valuation_id=valuation_id valuation_id=valuation_id
) )
@ -105,14 +159,14 @@ async def get_valuation_detail(
@app_valuations_router.get("/statistics/overview", summary="获取我的估值评估统计") @app_valuations_router.get("/statistics/overview", summary="获取我的估值评估统计")
async def get_my_valuation_statistics( async def get_my_valuation_statistics(
user_id: int = Depends(get_current_app_user_id) current_user: AppUser = Depends(get_current_app_user)
): ):
""" """
获取当前用户的估值评估统计信息 获取当前用户的估值评估统计信息
""" """
try: try:
result = await user_valuation_controller.get_user_valuation_statistics( result = await user_valuation_controller.get_user_valuation_statistics(
user_id=user_id user_id=current_user.id
) )
return Success(data=result, msg="获取统计信息成功") return Success(data=result, msg="获取统计信息成功")
except Exception as e: except Exception as e:

View File

@ -11,6 +11,7 @@ from app.schemas.third_party_api import (
OCRRequest, OCRRequest,
XiaohongshuNoteRequest, XiaohongshuNoteRequest,
JizhiliaoSearchRequest, JizhiliaoSearchRequest,
DifyWorkflowRequest,
APIResponse, APIResponse,
APIProviderInfo, APIProviderInfo,
APIEndpointInfo, APIEndpointInfo,
@ -110,4 +111,22 @@ async def search_jizhiliao_index(request: JizhiliaoSearchRequest):
return Fail(message=result.message) return Fail(message=result.message)
except Exception as e: except Exception as e:
logger.error(f"极致聊指数搜索失败: {e}") logger.error(f"极致聊指数搜索失败: {e}")
return Fail(message=f"极致聊指数搜索失败: {str(e)}") return Fail(message=f"极致聊指数搜索失败: {str(e)}")
@router.post("/dify/workflows/run", summary="运行Dify工作流")
async def run_dify_workflow(request: DifyWorkflowRequest):
"""运行Dify工作流"""
try:
result = await third_party_api_controller.run_dify_workflow(
zl_img=request.zl_img,
response_mode=request.response_mode,
user=request.user
)
if result.success:
return Success(data=result.data, message=result.message)
else:
return Fail(message=result.message)
except Exception as e:
logger.error(f"运行Dify工作流失败: {e}")
return Fail(message=f"运行Dify工作流失败: {str(e)}")

View File

@ -78,9 +78,9 @@ class ThirdPartyAPIController:
endpoint="patent", endpoint="patent",
params={ params={
"searchKey": company_name, "searchKey": company_name,
"pageNo": 1, "pageNo": "1",
"range": 100, "range": "100",
"searchType": 0, "searchType": '1',
"ChinazVer": chinaz_ver "ChinazVer": chinaz_ver
} }
) )
@ -125,6 +125,20 @@ class ThirdPartyAPIController:
timeout=timeout timeout=timeout
) )
async def run_dify_workflow(
self,
zl_img: str,
response_mode: str = "blocking",
user: str = "default_user"
) -> APIResponse:
"""运行Dify工作流"""
params = {
"inputs": {"zl_img": zl_img},
"response_mode": response_mode,
"user": user
}
return await self.make_api_request("dify", "workflows_run", params)
# 创建全局控制器实例 # 创建全局控制器实例
third_party_api_controller = ThirdPartyAPIController() third_party_api_controller = ThirdPartyAPIController()

View File

@ -28,6 +28,12 @@ class JizhiliaoSearchRequest(BaseAPIRequest):
page: int = Field(1, description="页码") page: int = Field(1, description="页码")
size: int = Field(10, description="每页数量") size: int = Field(10, description="每页数量")
class DifyWorkflowRequest(BaseAPIRequest):
"""Dify工作流请求模型"""
zl_img: str = Field(..., description="资料图片字段")
response_mode: str = Field("blocking", description="响应模式blocking或streaming")
user: str = Field(..., description="用户标识")
class APIResponse(BaseModel): class APIResponse(BaseModel):
"""API响应模型""" """API响应模型"""
success: bool success: bool

View File

@ -32,7 +32,7 @@ class APIConfig:
"base_url": "https://openapi.chinaz.net", "base_url": "https://openapi.chinaz.net",
"endpoints": { "endpoints": {
"copyright_software": { "copyright_software": {
"api_key": os.getenv("CHINAZ_COPYRIGHT_API_KEY", "YOUR_API_KEY"), "APIKey": os.getenv("CHINAZ_COPYRIGHT_API_KEY", "YOUR_API_KEY"),
"path": "/v1/1036/copyrightsoftware", "path": "/v1/1036/copyrightsoftware",
"method": "POST", "method": "POST",
"description": "企业软件著作权查询", "description": "企业软件著作权查询",
@ -40,7 +40,7 @@ class APIConfig:
"optional_params": ["sign"] "optional_params": ["sign"]
}, },
"patent": { "patent": {
"api_key": os.getenv("CHINAZ_PATENT_API_KEY", "YOUR_API_KEY"), "APIKey": os.getenv("CHINAZ_PATENT_API_KEY", "apiuser_quantity_045e9c832d253a1fdfd41edd1a85a254_4e9f3a38e384414e97fdbd33cca13124"),
"path": "/v1/1036/patent", "path": "/v1/1036/patent",
"method": "POST", "method": "POST",
"description": "企业专利信息查询", "description": "企业专利信息查询",
@ -48,7 +48,7 @@ class APIConfig:
"optional_params": ["sign", "searchType"] "optional_params": ["sign", "searchType"]
}, },
"judgement": { "judgement": {
"api_key": os.getenv("CHINAZ_JUDGEMENT_API_KEY", "YOUR_API_KEY"), "APIKey": os.getenv("CHINAZ_JUDGEMENT_API_KEY", "YOUR_API_KEY"),
"path": "/v1/1036/judgementdetailv4", "path": "/v1/1036/judgementdetailv4",
"method": "POST", "method": "POST",
"description": "司法综合数据查询", "description": "司法综合数据查询",
@ -56,7 +56,7 @@ class APIConfig:
"optional_params": ["sign", "q", "idCardNo", "datatype", "id", "pageNo"] "optional_params": ["sign", "q", "idCardNo", "datatype", "id", "pageNo"]
}, },
"recognition_ocr": { "recognition_ocr": {
"api_key": os.getenv("CHINAZ_OCR_API_KEY", "YOUR_API_KEY"), "APIKey": os.getenv("CHINAZ_OCR_API_KEY", "apiuser_quantity_d0848e65f7b7ae50ff6f1ae37e413586_31466987e2ef402ba3142b72680a92fc"),
"path": "/v1/1024/recognition_ocr", "path": "/v1/1024/recognition_ocr",
"method": "POST", "method": "POST",
"description": "图片OCR识别", "description": "图片OCR识别",
@ -72,184 +72,75 @@ class APIConfig:
"timeout": 30, "timeout": 30,
"retries": 3, "retries": 3,
"endpoints": { "endpoints": {
"xiaohongshu": { "xiaohongshu_note_detail": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/xiaohongshu/get-note-detail/v7",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "小红书笔记详情查询",
"retries": 3, "required_params": ["noteId"],
"endpoints": { "optional_params": ["token"]
"xiaohongshu_note_detail": {
"path": "/api/xiaohongshu/get-note-detail/v7",
"method": "GET",
"description": "小红书笔记详情查询",
"required_params": ["noteId"],
"optional_params": ["token"]
},
"xiaohongshu_user_info": {
"path": "/api/xiaohongshu/get-user-info/v7",
"method": "GET",
"description": "小红书用户信息查询",
"required_params": ["userId"],
"optional_params": ["token"]
},
"xiaohongshu_search_notes": {
"path": "/api/xiaohongshu/search-notes/v7",
"method": "GET",
"description": "小红书笔记搜索",
"required_params": ["keyword"],
"optional_params": ["page", "size", "token"]
},
"weibo_user_detail": {
"path": "/api/weibo/get-user-detail/v1", # 微博只有粉丝数接口
"method": "GET",
"description": "获取用户信息 包括昵称、头像、用户ID、粉丝数、关注数、简介、认证状态等公开信息",
"required_params": ["token", "uid"],
"optional_params": ["token", "uid"]
},
"weixin_user_detail": {
"path": "/api/weixin/get-user-post/v1",
"method": "GET",
"description": "公众号发布的文章内容,包括标题、作者、发布时间、内容摘要以及阅读数、点赞数与转发数等互动数据",
"required_params": ["token", "wxid"],
"optional_params": ["token", "wxid"]
},
"douyin_video_detail": {
"path": "/api/douyin/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "videoId"],
"optional_params": ["token", "videoId"]
},
"kuaishou_video_detail": {
"path": "/api/kuaishou/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "videoId"],
"optional_params": ["token", "videoId"]
},
"bilibili_video_detail": {
"path": "/api/bilibili/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "bvid"],
"optional_params": ["token", "bvid"]
}
}
}, },
"weibo": { "xiaohongshu_user_info": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/xiaohongshu/get-user-info/v7",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "小红书用户信息查询",
"retries": 3, "required_params": ["userId"],
"endpoints": { "optional_params": ["token"]
"weibo_user_detail": {
"path": "/api/weibo/get-user-detail/v1", # 微博只有粉丝数接口
"method": "GET",
"description": "获取用户信息 包括昵称、头像、用户ID、粉丝数、关注数、简介、认证状态等公开信息",
"required_params": ["token", "uid"],
"optional_params": ["token", "uid"]
},
}
}, },
"weixin": { "xiaohongshu_search_notes": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/xiaohongshu/search-notes/v7",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "小红书笔记搜索",
"retries": 3, "required_params": ["keyword"],
"endpoints": { "optional_params": ["page", "size", "token"]
"weixin_user_detail": {
"path": "/api/weixin/get-user-post/v1",
"method": "GET",
"description": "公众号发布的文章内容,包括标题、作者、发布时间、内容摘要以及阅读数、点赞数与转发数等互动数据",
"required_params": ["token", "wxid"],
"optional_params": ["token", "wxid"]
}
}
}, },
"douyin": { "weibo_user_detail": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/weibo/get-user-detail/v1",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "获取用户信息 包括昵称、头像、用户ID、粉丝数、关注数、简介、认证状态等公开信息",
"retries": 3, "required_params": ["token", "uid"],
"endpoints": { "optional_params": []
"douyin_video_detail": {
"path": "/api/douyin/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "videoId"],
"optional_params": ["token", "videoId"]
}
}
}, },
"bilibili": { "weixin_user_detail": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/weixin/get-user-post/v1",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "公众号发布的文章内容,包括标题、作者、发布时间、内容摘要以及阅读数、点赞数与转发数等互动数据",
"retries": 3, "required_params": ["token", "wxid"],
"endpoints": { "optional_params": []
"bilibili_video_detail": {
"path": "/api/bilibili/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "bvid"],
"optional_params": ["token", "bvid"]
}
}
}, },
"kuaishou": { "douyin_video_detail": {
"api_key": os.getenv("XIAOHONGSHU_TOKEN", "YNSbIjdU"), "path": "/api/douyin/get-video-detail/v2",
"base_url": "https://api.justoneapi.com", "method": "GET",
"timeout": 30, "description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"retries": 3, "required_params": ["token", "videoId"],
"endpoints": { "optional_params": []
"kuaishou_video_detail": {
"path": "/api/kuaishou/get-video-detail/v2",
"method": "GET",
"description": "该接口用于获取指定抖音视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "videoId"],
"optional_params": ["token", "videoId"]
}
}
}, },
"other_apis": { "kuaishou_video_detail": {
"jizhiliao": { "path": "/api/kuaishou/get-video-detail/v2",
"api_key": os.getenv("JIZHILIAO_API_KEY", "JZL089ef0b7d0315d96"), "method": "GET",
"base_url": "https://api.justoneapi.com", "description": "该接口用于获取指定快手视频的详细信息,包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"timeout": 30, "required_params": ["token", "videoId"],
"retries": 3, "optional_params": []
"verifycode": os.getenv("JIZHILIAO_VERIFYCODE", ""),
"endpoints": {
"index_search": {
"path": "/fbmain/monitor/v3/web_search",
"method": "POST",
"description": "极致聊指数搜索",
"required_params": ["keyword", "mode", "BusinessType", "sub_search_type"],
"optional_params": ["key", "verifycode"]
},
}
},
"other": {
# 可以添加其他第三方API配置
"example_api": {
"api_key": os.getenv("EXAMPLE_API_KEY", ""),
"base_url": "https://api.example.com",
"endpoints": {}
}
}, },
"common_settings": { "bilibili_video_detail": {
"timeout": 60, "path": "/api/bilibili/get-video-detail/v2",
"retries": 3, "method": "GET",
"sign_prefix": "634xz" "description": "该接口用于获取指定B站视频的详细信息包括视频地址、描述文案、作者信息、发布时间、播放量、点赞数、评论数与分享数等",
"required_params": ["token", "bvid"],
"optional_params": []
},
"jizhiliao_index_search": {
"path": "/fbmain/monitor/v3/web_search",
"method": "POST",
"description": "极致聊指数搜索",
"api_key": os.getenv("JIZHILIAO_API_KEY", "JZL089ef0b7d0315d96"),
"verifycode": os.getenv("JIZHILIAO_VERIFYCODE", ""),
"required_params": ["keyword", "mode", "BusinessType", "sub_search_type"],
"optional_params": ["key", "verifycode"]
} }
} }
}
}, },
# 微信指数 # 微信指数
"dajiala": { "dajiala": {
"api_key": "",
"base_url": "https://www.dajiala.com", "base_url": "https://www.dajiala.com",
"timeout": 30, "timeout": 30,
"retries": 3, "retries": 3,
@ -263,6 +154,26 @@ class APIConfig:
} }
} }
}, },
# dify
"dify": {
"base_url": "http://106.14.211.94",
"api_key": "app-FJXEWdKv63oq1F4rHb4I8kvE",
"timeout": 30,
"retries": 3,
"endpoints": {
"workflows_run": {
"path": "/v1/workflows/run",
"method": "POST",
"description": "运行工作流",
"required_params": ["inputs", "response_mode", "user"],
"optional_params": [],
"headers": {
"Authorization": "Bearer {api_key}",
"Content-Type": "application/json"
}
}
}
}
} }
# 尝试从文件加载配置 # 尝试从文件加载配置

View File

@ -1,8 +1,7 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional from typing import Optional
import jwt import jwt
from fastapi import HTTPException, status, Depends from fastapi import HTTPException, status, Depends, Header
from fastapi.security import HTTPBearer
from app.controllers.app_user import app_user_controller from app.controllers.app_user import app_user_controller
from app.schemas.app_user import AppUserJWTPayload from app.schemas.app_user import AppUserJWTPayload
from app.settings import settings from app.settings import settings
@ -12,8 +11,6 @@ SECRET_KEY = settings.SECRET_KEY
ALGORITHM = "HS256" ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7天 ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7天
security = HTTPBearer()
def create_app_user_access_token(user_id: int, phone: str) -> str: def create_app_user_access_token(user_id: int, phone: str) -> str:
""" """
@ -51,7 +48,7 @@ def verify_app_user_token(token: str) -> Optional[AppUserJWTPayload]:
return None return None
def get_current_app_user_id(token: str = Depends(security)) -> int: def get_current_app_user_id(token: str = Header(None)) -> int:
""" """
从令牌中获取当前AppUser ID 从令牌中获取当前AppUser ID
""" """
@ -61,7 +58,10 @@ def get_current_app_user_id(token: str = Depends(security)) -> int:
headers={"WWW-Authenticate": "Bearer"}, headers={"WWW-Authenticate": "Bearer"},
) )
payload = verify_app_user_token(token.credentials) if not token:
raise credentials_exception
payload = verify_app_user_token(token)
if payload is None: if payload is None:
raise credentials_exception raise credentials_exception

View File

@ -53,7 +53,14 @@ class UniversalAPIManager:
endpoint_config = self._get_endpoint_config(provider, endpoint) endpoint_config = self._get_endpoint_config(provider, endpoint)
if not endpoint_config: if not endpoint_config:
return None return None
return endpoint_config.get('api_key')
# 优先从端点配置中获取APIKey
if 'APIKey' in endpoint_config:
return endpoint_config['APIKey']
# 如果端点配置中没有则从提供商配置中获取api_key
provider_config = self._get_provider_config(provider)
return provider_config.get('api_key')
def make_request(self, provider: str, endpoint: str, params: Dict[str, Any], timeout: Optional[int] = None) -> Dict[str, Any]: def make_request(self, provider: str, endpoint: str, params: Dict[str, Any], timeout: Optional[int] = None) -> Dict[str, Any]:
""" """
@ -89,7 +96,7 @@ class UniversalAPIManager:
# 添加API密钥到参数中 # 添加API密钥到参数中
params['APIKey'] = api_key params['APIKey'] = api_key
print(params)
# 发送请求 # 发送请求
try: try:
response = self.session.request( response = self.session.request(
@ -156,6 +163,17 @@ class UniversalAPIManager:
# 对于GET请求将参数添加到URL中 # 对于GET请求将参数添加到URL中
query_string = urllib.parse.urlencode(params) query_string = urllib.parse.urlencode(params)
full_url = f"{full_url}?{query_string}" full_url = f"{full_url}?{query_string}"
elif provider == 'chinaz' and method.upper() == 'POST':
# 对于Chinaz POST请求只将APIKey和ChinazVer添加到URL中
url_params = {}
if 'APIKey' in params:
url_params['APIKey'] = params['APIKey']
if 'ChinazVer' in params:
url_params['ChinazVer'] = params['ChinazVer']
if url_params:
query_string = urllib.parse.urlencode(url_params)
full_url = f"{full_url}?{query_string}"
return full_url return full_url
@ -176,6 +194,9 @@ class UniversalAPIManager:
missing_params = [] missing_params = []
for param in required_params: for param in required_params:
# 如果参数在端点配置中已经定义如APIKey则跳过验证
if param in endpoint_config:
continue
if param not in params or params[param] is None: if param not in params or params[param] is None:
missing_params.append(param) missing_params.append(param)
@ -195,6 +216,7 @@ class UniversalAPIManager:
Dict[str, Any]: 处理后的参数 Dict[str, Any]: 处理后的参数
""" """
provider_config = self._get_provider_config(provider) provider_config = self._get_provider_config(provider)
endpoint_config = self._get_endpoint_config(provider, endpoint)
prepared_params = params.copy() prepared_params = params.copy()
# 根据不同的API提供商添加特定参数 # 根据不同的API提供商添加特定参数
@ -202,6 +224,10 @@ class UniversalAPIManager:
# 站长之家API需要签名 # 站长之家API需要签名
if 'sign' not in prepared_params: if 'sign' not in prepared_params:
prepared_params['sign'] = self._generate_chinaz_sign() prepared_params['sign'] = self._generate_chinaz_sign()
# 添加APIKey参数
if 'APIKey' not in prepared_params and endpoint_config and 'APIKey' in endpoint_config:
prepared_params['APIKey'] = endpoint_config['APIKey']
elif provider == 'xiaohongshu': elif provider == 'xiaohongshu':
# 小红书接口使用 JustOneAPI 平台,需要 token 参数 # 小红书接口使用 JustOneAPI 平台,需要 token 参数
@ -228,6 +254,11 @@ class UniversalAPIManager:
if default_verifycode is not None: if default_verifycode is not None:
prepared_params['verifycode'] = default_verifycode prepared_params['verifycode'] = default_verifycode
elif provider == 'dify':
# Dify API需要在请求头中设置Authorization
# 这里不需要修改paramsAuthorization会在make_request中处理
pass
return prepared_params return prepared_params
@ -264,16 +295,38 @@ class UniversalAPIManager:
# 构建URL # 构建URL
url = self._build_url(provider, endpoint, prepared_params) url = self._build_url(provider, endpoint, prepared_params)
logger.info(f"发送{method}请求到: {url}")
# 发送请求 # 发送请求
for attempt in range(retries + 1): for attempt in range(retries + 1):
try: try:
if method == 'GET': if method == 'GET':
response = self.session.get(url, timeout=timeout) response = self.session.get(url, timeout=timeout)
elif method == 'POST': elif method == 'POST':
response = self.session.post(url, json=prepared_params, timeout=timeout) if provider == 'chinaz':
# 对于Chinaz API从prepared_params中移除URL参数只发送body参数
body_params = prepared_params.copy()
body_params.pop('APIKey', None)
body_params.pop('ChinazVer', None)
# Chinaz API使用application/x-www-form-urlencoded格式
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = self.session.post(url, data=body_params, headers=headers, timeout=timeout)
print(response.json())
elif provider == 'dify':
# 对于Dify API需要设置Authorization头
provider_config = self._get_provider_config(provider)
endpoint_config = self._get_endpoint_config(provider, endpoint)
# 获取API密钥
api_key = provider_config.get('api_key', 'app-FJXEWdKv63oq1F4rHb4I8kvE')
# 设置请求头
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
response = self.session.post(url, json=prepared_params, headers=headers, timeout=timeout)
else:
response = self.session.post(url, json=prepared_params, timeout=timeout)
else: else:
raise ValueError(f"不支持的HTTP方法: {method}") raise ValueError(f"不支持的HTTP方法: {method}")
@ -349,7 +402,7 @@ class UniversalAPIManager:
'searchKey': company_name, 'searchKey': company_name,
'pageNo': '1', 'pageNo': '1',
'range': '100', 'range': '100',
'searchType': '0', 'searchType': '1',
'ChinazVer': chinaz_ver 'ChinazVer': chinaz_ver
} }
return self.make_request('chinaz', 'patent', params) return self.make_request('chinaz', 'patent', params)

4551
app/utils/专利.json Normal file

File diff suppressed because it is too large Load Diff