dev
This commit is contained in:
@@ -1,14 +1,13 @@
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
from pydantic import Field
|
from pydantic import Field, BaseModel
|
||||||
from pydantic.generics import GenericModel
|
|
||||||
import gzip # 导入 gzip 模块
|
import gzip # 导入 gzip 模块
|
||||||
from io import BytesIO # 从 io 模块导入 BytesIO 类
|
from io import BytesIO # 从 io 模块导入 BytesIO 类
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
class Return(GenericModel, Generic[T]):
|
class Return(BaseModel, Generic[T]):
|
||||||
code: int = Field(..., description='响应状态码')
|
code: int = Field(..., description='响应状态码')
|
||||||
"""响应状态码"""
|
"""响应状态码"""
|
||||||
message: str = Field(..., description='响应消息')
|
message: str = Field(..., description='响应消息')
|
||||||
@@ -16,6 +15,7 @@ class Return(GenericModel, Generic[T]):
|
|||||||
data: T = Field(..., description='响应数据')
|
data: T = Field(..., description='响应数据')
|
||||||
"""响应数据"""
|
"""响应数据"""
|
||||||
|
|
||||||
|
|
||||||
# 定义一个函数,将字符串压缩为 gzip 格式,并进行 base64 编码后返回结果
|
# 定义一个函数,将字符串压缩为 gzip 格式,并进行 base64 编码后返回结果
|
||||||
def gzip_str(to_gzip: str) -> str:
|
def gzip_str(to_gzip: str) -> str:
|
||||||
out = BytesIO() # 创建一个 BytesIO 对象
|
out = BytesIO() # 创建一个 BytesIO 对象
|
||||||
@@ -24,9 +24,10 @@ def gzip_str(to_gzip: str) -> str:
|
|||||||
return base64.b64encode(out.getvalue()).decode() # 对压缩后的数据使用 base64 编码并返回结果
|
return base64.b64encode(out.getvalue()).decode() # 对压缩后的数据使用 base64 编码并返回结果
|
||||||
|
|
||||||
|
|
||||||
def response(*, code=200, data: list | dict | str, message='Success', zip=False)-> Return:
|
def response(*, code=200, data: list | dict | str, message='Success', zip=False) -> Return:
|
||||||
if zip:
|
if zip:
|
||||||
import gzip
|
import gzip
|
||||||
|
|
||||||
data = base64.b64encode(gzip.compress(json.dumps(data).encode()))
|
data = base64.b64encode(gzip.compress(json.dumps(data).encode()))
|
||||||
return Return(code=code, message=message, data=data)
|
return Return(code=code, message=message, data=data)
|
||||||
|
|
||||||
|
|||||||
+34
-28
@@ -34,6 +34,12 @@ url = 'https://poservice.colg.cn/api/v1/trend/getCoinTrendDataKol'
|
|||||||
|
|
||||||
payload = {'token': config.COLG_TOKEN, 'area': 0, 'time_type': 'other', 'start_time': '2026-01-06', 'end_time': '2026-01-06'}
|
payload = {'token': config.COLG_TOKEN, 'area': 0, 'time_type': 'other', 'start_time': '2026-01-06', 'end_time': '2026-01-06'}
|
||||||
|
|
||||||
|
payload_helper = {
|
||||||
|
'r': 'godRank/godDealRank',
|
||||||
|
'userId': config.HELPER_ID,
|
||||||
|
'token': config.HELPER_TOKEN,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_date_str(timestamp: int) -> str:
|
def get_date_str(timestamp: int) -> str:
|
||||||
utc_time = datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
utc_time = datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
||||||
@@ -41,13 +47,14 @@ def get_date_str(timestamp: int) -> str:
|
|||||||
return beijing_time.strftime('%Y-%m-%d %H:%M:%S')
|
return beijing_time.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
|
||||||
@router.get('/gold/realtime/', operation_id='realTimeGold')
|
@router.get('/gold/realtime/', operation_id='realtime_gold',response_model=Response[list[RealTimeGold]])
|
||||||
async def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
|
async def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
|
||||||
"""
|
"""
|
||||||
返回所有跨区的实时金价信息
|
返回所有跨区的实时金价信息
|
||||||
"""
|
"""
|
||||||
key = 'openapi:colg:real_time_gold'
|
key = 'openapi:colg:real_time_gold'
|
||||||
try:
|
try:
|
||||||
|
|
||||||
def get_gold_data():
|
def get_gold_data():
|
||||||
res = []
|
res = []
|
||||||
for region_name, region_id in regionMap.items():
|
for region_name, region_id in regionMap.items():
|
||||||
@@ -67,7 +74,7 @@ async def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
|
|||||||
return response(data=data)
|
return response(data=data)
|
||||||
|
|
||||||
|
|
||||||
@router.get('/gold/history/', operation_id='historyGold')
|
@router.get('/gold/history/', operation_id='history_gold',response_model=Response[HistoryGold] | Response[None])
|
||||||
async def get_history_gold(region: Annotated[int, Query(..., description='跨区id')], timeRange: Annotated[int, Query(..., description='时间跨度天数')] = 7) -> Response[HistoryGold] | Response[None]:
|
async def get_history_gold(region: Annotated[int, Query(..., description='跨区id')], timeRange: Annotated[int, Query(..., description='时间跨度天数')] = 7) -> Response[HistoryGold] | Response[None]:
|
||||||
"""
|
"""
|
||||||
获取历史金价数据
|
获取历史金价数据
|
||||||
@@ -139,43 +146,42 @@ async def get_history_gold(region: Annotated[int, Query(..., description='跨区
|
|||||||
return response(data={'region': region_name, 'data': data, 'echartsData': echartsData})
|
return response(data={'region': region_name, 'data': data, 'echartsData': echartsData})
|
||||||
|
|
||||||
|
|
||||||
@router.get('/gold/official/', operation_id='officialGold')
|
@router.get('/gold/official/', operation_id='official_gold',response_model=Response[list[OfficialGold]])
|
||||||
async def get_official_gold(redis: RedisDep) -> Response[list[OfficialGold]]:
|
async def get_official_gold(redis: RedisDep) -> Response[list[OfficialGold]]:
|
||||||
"""
|
"""
|
||||||
获取官方金币寄售实时数据
|
获取DNF官方金币寄售实时数据
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response[list[OfficialGold]]: 包含官方金币寄售数据的响应对象
|
||||||
|
Note:
|
||||||
|
- 该接口会返回所有跨区的官方金币寄售数据,包括最低成交价排名前5的价格和最高成交价排名前5的价格
|
||||||
|
- 数据来源于DNF官方提供的接口,可能会有一定的延迟和不稳定性
|
||||||
"""
|
"""
|
||||||
official_url = 'https://dzhu.qq.com/zangyi/activity/app'
|
official_url = 'https://dzhu.qq.com/zangyi/activity/app'
|
||||||
headers = {
|
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}
|
|
||||||
params = {
|
|
||||||
'r': 'godRank/godDealRank',
|
|
||||||
'userId': config.HELPER_ID,
|
|
||||||
'token': config.HELPER_TOKEN,
|
|
||||||
}
|
|
||||||
key = 'openapi:colg:real_time_gold_officical'
|
key = 'openapi:colg:real_time_gold_officical'
|
||||||
list = ['1', '2', '3A', '3B', '4', '5', '6', '7']
|
list = ['1', '2', '3A', '3B', '4', '5', '6', '7']
|
||||||
try:
|
try:
|
||||||
async def get_data():
|
async def get_data():
|
||||||
datas = []
|
datas = []
|
||||||
async def fetch_data():
|
async with aiohttp.ClientSession() as session:
|
||||||
async with aiohttp.ClientSession() as session:
|
tasks = []
|
||||||
tasks = []
|
for i in list:
|
||||||
for i in list:
|
payload_helper['serverNo'] = i
|
||||||
params['serverNo'] = i
|
query = '&'.join(f'{k}={v}' for k, v in payload_helper.items())
|
||||||
query = '&'.join(f'{k}={v}' for k, v in params.items())
|
tasks.append(session.post(official_url, data=query, headers=headers, timeout=10))
|
||||||
tasks.append(session.post(official_url, data=query, headers=headers, timeout=10))
|
responses = await asyncio.gather(*tasks)
|
||||||
responses = await asyncio.gather(*tasks)
|
for index, resp in enumerate(responses):
|
||||||
for index, resp in enumerate(responses):
|
res = json.loads(await resp.read())
|
||||||
res = json.loads(await resp.read())
|
datas.append(
|
||||||
datas.append({
|
{
|
||||||
'updataTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
'updataTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
'region': f'跨{list[index]}',
|
'region': f'跨{list[index]}',
|
||||||
'godDealRank': [int(i.get('price')) for i in res['data']['godDealRank']],
|
'goldDealRank': [int(i.get('price')) for i in res['data']['godDealRank']],
|
||||||
'godTopDealRank': [int(i.get('price')) for i in res['data']['godTopDealRank']],
|
'goldTopDealRank': [int(i.get('price')) for i in res['data']['godTopDealRank']],
|
||||||
})
|
}
|
||||||
return datas
|
)
|
||||||
return await fetch_data()
|
return datas
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
return response(data=[])
|
return response(data=[])
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ def replace_placeholders(template):
|
|||||||
return pattern.sub(repl, template)
|
return pattern.sub(repl, template)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/skills/", operation_id="skillsList")
|
@router.get("/skills/", operation_id="skills_list", response_model=SearchSkillResponse)
|
||||||
async def get_skills_list(
|
async def get_skills_list(
|
||||||
redis: RedisDep,
|
redis: RedisDep,
|
||||||
skillName: Annotated[str, Param(..., description="技能名称,支持模糊查询")] = None,
|
skillName: Annotated[str, Param(..., description="技能名称,支持模糊查询")] = None,
|
||||||
@@ -69,7 +69,7 @@ async def get_skills_list(
|
|||||||
return response(data=data)
|
return response(data=data)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/jobInfo/", operation_id="jobsInfo")
|
@router.get("/jobInfo/", operation_id="jobs_info", response_model=JobInfoResponse)
|
||||||
async def get_jobs_info(
|
async def get_jobs_info(
|
||||||
redis: RedisDep,
|
redis: RedisDep,
|
||||||
jobName: Annotated[str, Query(..., description="职业名称,支持模糊查询")] = None,
|
jobName: Annotated[str, Query(..., description="职业名称,支持模糊查询")] = None,
|
||||||
@@ -101,7 +101,7 @@ async def get_jobs_info(
|
|||||||
return response(data=result)
|
return response(data=result)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{jobId}/{jobGrowId}/skills/", operation_id="skillsByJob")
|
@router.get("/{jobId}/{jobGrowId}/skills/", operation_id="skills_by_job",response_model=SkillsListResponse)
|
||||||
async def get_cn_skills_by_job(
|
async def get_cn_skills_by_job(
|
||||||
redis: RedisDep,
|
redis: RedisDep,
|
||||||
jobId: Annotated[str, Path(..., description="职业")],
|
jobId: Annotated[str, Path(..., description="职业")],
|
||||||
@@ -125,7 +125,7 @@ async def get_cn_skills_by_job(
|
|||||||
return response(data=skills_list)
|
return response(data=skills_list)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{jobId}/{jobGrowId}/{skillId}/", operation_id="skillDetail")
|
@router.get("/{jobId}/{jobGrowId}/{skillId}/", operation_id="skill_detail", response_model=SkillDetailResponse)
|
||||||
async def get_cn_skill_info(
|
async def get_cn_skill_info(
|
||||||
redis: RedisDep,
|
redis: RedisDep,
|
||||||
jobId: Annotated[str, Path(..., description="职业")],
|
jobId: Annotated[str, Path(..., description="职业")],
|
||||||
@@ -192,7 +192,7 @@ async def get_cn_skill_info(
|
|||||||
return response(data=skill_info)
|
return response(data=skill_info)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/skillData/summary/", operation_id="skillDataSummary")
|
@router.get("/skillData/summary/", operation_id="skill_data_summary",response_model=SkillDataSummaryResponse)
|
||||||
async def get_skill_data_summary(
|
async def get_skill_data_summary(
|
||||||
redis: RedisDep,
|
redis: RedisDep,
|
||||||
job: Annotated[str, Param(..., description="职业")],
|
job: Annotated[str, Param(..., description="职业")],
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
from pydantic.generics import GenericModel
|
|
||||||
from api.core.Response import Return as Response
|
from api.core.Response import Return as Response
|
||||||
|
|
||||||
|
|
||||||
@@ -10,7 +9,7 @@ class RealTimeGold(BaseModel):
|
|||||||
"""更新时间"""
|
"""更新时间"""
|
||||||
region: str = Field(..., description='跨区')
|
region: str = Field(..., description='跨区')
|
||||||
"""跨区"""
|
"""跨区"""
|
||||||
goldPrice: float = Field(..., description='金价')
|
goldPrice: float|str = Field(..., description='金价')
|
||||||
"""金价"""
|
"""金价"""
|
||||||
|
|
||||||
class DayGold(BaseModel):
|
class DayGold(BaseModel):
|
||||||
@@ -33,7 +32,7 @@ class OfficialGold(BaseModel):
|
|||||||
"""更新时间"""
|
"""更新时间"""
|
||||||
region: str = Field(..., description='跨区')
|
region: str = Field(..., description='跨区')
|
||||||
"""跨区"""
|
"""跨区"""
|
||||||
godDealRank: list[float] = Field(..., description='金币寄售最低成交价排名前5的价格')
|
goldDealRank: list[float|str] = Field(..., description='金币寄售最低成交价排名前5的价格')
|
||||||
"""金币寄售最低成交价排名前5的价格"""
|
"""金币寄售最低成交价排名前5的价格"""
|
||||||
godTopDealRank: list[float] = Field(..., description='金币寄售最高成交价排名前5的价格')
|
goldTopDealRank: list[float|str] = Field(..., description='金币寄售最高成交价排名前5的价格')
|
||||||
"""金币寄售最高成交价排名前5的价格"""
|
"""金币寄售最高成交价排名前5的价格"""
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing import Generic, TypeVar
|
|
||||||
from pydantic.generics import GenericModel
|
|
||||||
from api.core.Response import Return as Response
|
from api.core.Response import Return as Response
|
||||||
|
|
||||||
|
|
||||||
class SkillInfo(BaseModel):
|
class SkillInfo(BaseModel):
|
||||||
skillId: str = Field(..., description='技能ID')
|
skillId: str = Field(..., description='技能ID')
|
||||||
"""技能ID"""
|
"""技能ID"""
|
||||||
|
|||||||
+11
-3
@@ -1,5 +1,12 @@
|
|||||||
from pydantic_settings import BaseSettings
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.chdir(os.path.dirname(sys.argv[0]))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
class Config(BaseSettings):
|
class Config(BaseSettings):
|
||||||
DEBUG_MODE: bool = True
|
DEBUG_MODE: bool = True
|
||||||
@@ -11,8 +18,9 @@ class Config(BaseSettings):
|
|||||||
HELPER_TOKEN: str = ''
|
HELPER_TOKEN: str = ''
|
||||||
HELPER_ID: str = ''
|
HELPER_ID: str = ''
|
||||||
|
|
||||||
class Config:
|
model_config = SettingsConfigDict(
|
||||||
env_file = ('config/.env', 'config/.env.dev', 'config/.env.prod')
|
env_file=('config/.env', 'config/.env.dev', 'config/.env.prod')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
# import os
|
# import os
|
||||||
# import sys
|
# import sys
|
||||||
from sqlalchemy import Column, Integer, Text, Float
|
from sqlalchemy import Column, Integer, Text, Float
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session,declarative_base
|
||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
metadata = Base.metadata
|
metadata = Base.metadata
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
from fastmcp import FastMCP
|
from fastmcp import FastMCP
|
||||||
from main import application
|
from main import application
|
||||||
from fastmcp.server.openapi import MCPType, HTTPRoute
|
from fastmcp.server.providers.openapi import MCPType
|
||||||
from config.main import config
|
from config.main import config
|
||||||
|
|
||||||
def custom_route_mapper(route: HTTPRoute, mcp_type: MCPType) -> MCPType | None:
|
def custom_route_mapper(route, mcp_type: MCPType) -> MCPType | None:
|
||||||
"""Advanced route type mapping."""
|
"""Advanced route type mapping."""
|
||||||
# Convert all admin routes to tools regardless of HTTP method
|
# Convert all admin routes to tools regardless of HTTP method
|
||||||
if "/open/" in route.path and route.method in ["GET"]:
|
if "/open/" in route.path and route.method in ["GET"]:
|
||||||
@@ -16,10 +16,7 @@ mcp = FastMCP.from_fastapi(
|
|||||||
app=application,
|
app=application,
|
||||||
name="Dcalc_MCP",
|
name="Dcalc_MCP",
|
||||||
instructions="DNF相关的MCP服务",
|
instructions="DNF相关的MCP服务",
|
||||||
timeout=60,
|
|
||||||
host="0.0.0.0",
|
|
||||||
port=config.MCPPORT,
|
|
||||||
route_map_fn=custom_route_mapper,
|
route_map_fn=custom_route_mapper,
|
||||||
)
|
)
|
||||||
|
|
||||||
mcp.run(transport="streamable-http")
|
mcp.run(transport="streamable-http", host="0.0.0.0", port=config.MCPPORT)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ requires-python = ">=3.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aiohttp>=3.13.3",
|
"aiohttp>=3.13.3",
|
||||||
"fastapi[all]>=0.115.11",
|
"fastapi[all]>=0.115.11",
|
||||||
"fastmcp>=2.7.1",
|
"fastmcp>=3.1.0",
|
||||||
"redis>=5.2.1",
|
"redis>=5.2.1",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.3",
|
||||||
"sqlalchemy>=2.0.38",
|
"sqlalchemy>=2.0.38",
|
||||||
|
|||||||
Generated
+891
-184
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user