diff --git a/App/AstRouter.py b/App/AstRouter.py new file mode 100644 index 0000000..9fd7029 --- /dev/null +++ b/App/AstRouter.py @@ -0,0 +1,51 @@ +import ast +import json +import os +from typing import Dict, Union +from fastapi import APIRouter, HTTPException +from pydantic import BaseModel +from starlette import status + +ast_router = APIRouter() + + +class CalculationInput(BaseModel): + params: Dict[str, Union[int, float]] + formula_name: str + + +def calculate_expression(expression: ast.Expression, params: Dict) -> float: + """ + 使用AST模块计算安全的表达式 + """ + try: + code = compile(expression, "", "eval") + result = eval(code, {}, params) + return result + except SyntaxError as e: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="公式语法错误:" + str(e)) + except NameError as e: + raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="公式中存在未定义的变量:" + str(e)) + except TypeError as e: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail="公式中的某些操作不支持所提供的参数类型:" + str(e)) + except Exception as e: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="执行公式时出现错误:" + str(e)) + + +@ast_router.post("/calculate_ast", summary="传入指标名称与参数进行计算", tags=['指标计算']) +def calculate(request: CalculationInput): + name = request.formula_name + data = request.params + + # 查询公式 + with open(os.getcwd() + '\\App\\FormulaData.json', encoding='utf-8') as f: + calculation = json.load(f) + try: + item = calculation.get(name) + formula = item.get('formula') + expression_ast = ast.parse(formula, mode="eval") + result = calculate_expression(expression_ast, data) + return {"result": round(result, request.precision) if hasattr(request, 'precision') else round(result, 2)} + except AttributeError: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="公式名称错误") diff --git a/App/FormulaData.json b/App/FormulaData.json new file mode 100644 index 0000000..c83fe87 --- /dev/null +++ b/App/FormulaData.json @@ -0,0 +1,60 @@ +{ + "债务率": { + "type": "定量", + "formula": "地方政府债务余额 / 地方政府综合财力 * 100", + "params": [ + "地方政府债务余额", + "地方政府综合财力" + ] + }, + "不良贷款率": { + "type": "定量", + "formula": "(次级类贷款 + 可疑类贷款 + 损失类贷款) / 各项贷款 * 100", + "params": [ + "次级类贷款", + "可疑类贷款", + "损失类贷款", + "各项贷款" + ] + }, + "拨备覆盖率": { + "type": "定量", + "formula": "应收融资租赁款减值准备 / 不良应收融资租赁款 * 100", + "params": [ + "应收融资租赁款减值准备", + "不良应收融资租赁款" + ] + }, + "拨备覆盖率_商业银行": { + "type": "定量", + "formula": "贷款损失准备 / 不良贷款余额 * 100", + "params": [ + "贷款损失准备", + "不良贷款余额" + ] + }, + "核心一级资本充足率": { + "type": "定量", + "formula": "(核心一级资本 + 对应资本扣除项) / 风险加权资产 * 100", + "params": [ + "核心一级资本", + "对应资本扣除项", + "风险加权资产" + ] + }, + "综合偿付能力充足率": { + "type": "定量", + "formula": "实际资本 / 200000000 * 100", + "params": [ + "实际资本" + ] + }, + "资本资产比率": { + "type": "定量", + "formula": "所有者权益 / 总资产 * 100", + "params": [ + "所有者权益", + "总资产" + ] + } +} \ No newline at end of file diff --git a/App/__init__.py b/App/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py index 3fd448a..952b3bb 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware import 基本信用评级指标 +from App.AstRouter import ast_router app = FastAPI( title="指标函数计算接口", @@ -19,11 +20,10 @@ app.add_middleware( allow_headers=["*"], ) - # 路由 PREFIX = "/api/index_function" -app.include_router(基本信用评级指标.router, prefix=PREFIX) - +# app.include_router(基本信用评级指标.router, prefix=PREFIX) +app.include_router(ast_router, prefix=PREFIX) if __name__ == "__main__": - uvicorn.run(app, host="127.0.0.1", port=8002) \ No newline at end of file + uvicorn.run(app, host="127.0.0.1", port=8002)