guzhi/app/api/v1/calculation/calcuation.py

257 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, Depends, HTTPException, status
from typing import Optional, List, Dict, Any
import json
from app.controllers.user_valuation import user_valuation_controller
from app.schemas.valuation import (
UserValuationCreate,
UserValuationQuery,
UserValuationList,
UserValuationOut,
UserValuationDetail
)
from app.schemas.base import Success, SuccessExtra
from app.utils.app_user_jwt import get_current_app_user_id
from app.utils.calculation_engine.cultural_value_b2 import CulturalValueB2Calculator
from app.utils.calculation_engine.economic_value_b1.economic_value_b1 import EconomicValueB1Calculator
from app.utils.calculation_engine.economic_value_b1.sub_formulas.basic_value_b11 import calculate_popularity_score, \
calculate_infringement_score, calculate_patent_usage_score
from app.utils.calculation_engine.economic_value_b1.sub_formulas.traffic_factor_b12 import calculate_search_index_s1
from app.utils.calculation_engine.risk_adjustment_b3 import RiskAdjustmentB3Calculator
from app.models.esg import ESG
from app.models.industry import Industry
from app.models.policy import Policy
from app.utils.universal_api_manager import universal_api
app_valuations_router = APIRouter(tags=["用户端估值评估"])
@app_valuations_router.post("/calculation", summary="计算估值")
async def calculate_valuation(
data: UserValuationCreate,
user_id: int = Depends(get_current_app_user_id)
):
"""
计算估值评估
根据用户提交的估值评估数据调用计算引擎进行经济价值B1计算
"""
try:
calculator_by_b1 = EconomicValueB1Calculator()
calculator_by_b2 = CulturalValueB2Calculator()
# 风险调整系数B3
calculator_by_b3 = RiskAdjustmentB3Calculator()
# 根据行业查询 ESG 基准分(优先用行业名称匹配,如用的是行业代码就把 name 改成 code
esg_obj = await ESG.filter(name=data.industry).first()
esg_score = float(esg_obj.number) if esg_obj else 0.0
# 根据行业查询 行业修正系数与ROE
industry_obj = await Industry.filter(name=data.industry).first()
# roe_score = industry_obj.roe
fix_num_score = industry_obj.fix_num
# 根据行业查询 政策匹配度
policy_obj = await Policy.filter(name=data.industry).first()
policy_match_score = policy_obj.score
# 提取 经济价值B1 计算参数
input_data_by_b1 = _extract_calculation_params_b1(data)
# ESG关联价值 ESG分 (0-10分)
input_data_by_b1["esg_score"] = esg_score
# 行业修正系数I
input_data_by_b1["industry_coefficient"] = fix_num_score
# 政策匹配度
input_data_by_b1["policy_match_score"] = policy_match_score
# 获取专利信息 TODO 参数
try:
patent_data = universal_api.query_patent_info("未找到 企业名称、企业统代、企业注册号")
# 解析专利数量
patentData = patent_data.get("data", {"dataList":[]})
patent_data_num = len(patentData["dataList"])
# 查询专利是否存在
patent_data_al = list(filter(lambda x: x.get("SQH") == data.patent_application_no, patentData))
if len(patent_data_al) > 0:
# 验证 专利剩余年限
# TODO 无法验证 专利剩余保护期>10年(10分)5-10年(7分)<5年(3分)
# 发展潜力D相关参数 专利数量
patent_count = calculate_patent_usage_score(len(patent_data_al))
input_data_by_b1["patent_count"] = patent_count
else:
input_data_by_b1["patent_count"] = 0
except Exception as e:
input_data_by_b1["patent_count"] = 0
# 提取 文化价值B2 计算参数
input_data_by_b2 = _extract_calculation_params_b2(data)
# 提取 风险调整系数B3 计算参数
input_data_by_b3 = _extract_calculation_params_b3(data)
# 提取 市场估值C 参数
input_data_by_c = _extract_calculation_params_c(data)
# 调用 经济价值B1 计算引擎
calculation_result_by_b1 = calculator_by_b1.calculate_complete_economic_value_b1(input_data_by_b1)
# 调用 文化价值B2 计算引擎
calculation_result_by_b2 = calculator_by_b2.calculate_complete_cultural_value_b2(input_data_by_b2)
# 调用 风险调整系数B3 计算引擎
calculation_result_by_b3 = calculator_by_b3.calculate_complete_risky_value_b3(input_data_by_b3)
# 创建估值评估记录
result = await user_valuation_controller.create_valuation(
user_id=user_id,
data=data
)
# 组装返回
result_dict = json.loads(result.model_dump_json())
result_dict['calculation_result'] = calculation_result
return Success(data=result_dict, msg="估值计算完成")
except Exception as e:
raise HTTPException(status_code=400, detail=f"计算失败: {str(e)}")
def _extract_calculation_params_b1(data: UserValuationCreate) -> Dict[str, Any]:
"""
从用户提交的数据中提取计算所需的参数
Args:
data: 用户提交的估值评估数据
Returns:
Dict: 计算所需的参数字典
"""
# 基础价值B11相关参数
# 财务价值所需数据 从近三年收益计算
three_year_income = data.three_year_income or [0, 0, 0]
# 法律强度L相关参数
# 普及地域分值 默认 7分
popularity_score = calculate_popularity_score(data.application_coverage)
# 侵权分 默认 6 TODO 需要使用第三方API 无侵权记录(10分),历史侵权已解决(6分),现存纠纷(2分)
infringement_score = calculate_infringement_score("无侵权信息")
infringement_score = 0
# 创新投入比 = (研发费用/营收) * 100
try:
rd_investment = float(data.rd_investment or 0)
annual_revenue = float(data.annual_revenue or 1) # 避免除零
innovation_ratio = (rd_investment / annual_revenue) * 100 if annual_revenue > 0 else 0
except (ValueError, TypeError):
innovation_ratio = 0.0
# 流量因子B12相关参数
# 近30天搜索指数S1 - 从社交媒体数据计算 TODO 需要使用第三方API
baidu_index = "暂无"
wechat_index = universal_api.wx_index(data.asset_name) # 通过资产信息获取微信指数 TODO 这里返回的没确认指数参数,有可能返回的图示是指数信息
weibo_index = "暂无"
search_index_s1 = calculate_search_index_s1(baidu_index,wechat_index,weibo_index) # 默认值实际应从API获取
# 行业均值S2 TODO 系统内置 未找到相关内容
industry_average_s2 = 0.0
# 社交媒体传播度S3 - TODO 需要使用第三方API,click_count view_count 未找到对应参数
# likes: 点赞数(API获取)
# comments: 评论数(API获取)
# shares: 转发数(API获取)
# followers: 粉丝数
# click_count: 商品链接点击量(用户填写) sales_volume 使用 sales_volume 销售量
# view_count: 内容浏览量(用户填写) link_views
# 政策乘数B13相关参数
# 政策契合度评分P - 根据行业和资助情况计算
# 实施阶段
implementation_stage = data.application_maturity
# 资金支持
funding_support = data.funding_status
return {
# 基础价值B11相关参数
'three_year_income': three_year_income,
'popularity_score': popularity_score,
'infringement_score': infringement_score,
'innovation_ratio': innovation_ratio,
# 流量因子B12相关参数
'search_index_s1': search_index_s1,
'industry_average_s2': industry_average_s2,
# 'social_media_spread_s3': social_media_spread_s3,
'likes':likes,
'comments':comments,
'shares':shares,
'followers':followers,
'click_count': int(data.click_count) or 100,
'view_count': int(data.link_views) or 100,
# 政策乘数B13相关参数
'implementation_stage': implementation_stage,
'funding_support':funding_support
}
# 获取 文化价值B2 相关参数
def _extract_calculation_params_b2(data: UserValuationCreate) -> Dict[str, Any]:
"""
argrg:
data: 用户提交的估值评估数据
retus:
Dict: 计算所需的参数字典
"""
# 活态传承系数B21 县官参数
inheritor_level_coefficient = data.inheritor_level # 传承人等级
offline_sessions = int(data.offline_activities) #线下传习次数
# 以下调用API douyin\bilibili\kuaishou
douyin_views = universal_api.video_views("douyin",video_id="视频id未知")
kuaishou_views= universal_api.video_views("kuaishou",video_id="视频id未知")
bilibili_views= universal_api.video_views("bilibili",video_id="视频id未知")
# 跨界合作深度 品牌联名0.3科技载体0.5国家外交礼品1.0
cross_border_depth = float(data.cooperation_depth)
# 纹样基因值B22相关参数
historical_inheritance = "历史传承度HI信息未找到"
# 用户上传资产相关的纹样图片,系数识别处理,得出结构复杂度值 TODO 一下两项未实现配置 识别图片功能
structure_complexity = "结构复杂度SC"
normalized_entropy = "归一化信息熵H"
return {
"inheritor_level_coefficient": inheritor_level_coefficient,
"offline_sessions": offline_sessions,
"douyin_views": douyin_views,
"kuaishou_views": kuaishou_views,
"bilibili_views": bilibili_views,
"cross_border_depth": cross_border_depth,
"historical_inheritance": historical_inheritance,
"structure_complexity": structure_complexity,
"normalized_entropy": normalized_entropy,
}
# 获取 文化价值B2 相关参数
def _extract_calculation_params_b3(data: UserValuationCreate) -> Dict[str, Any]:
# 过去30天最高价格 过去30天最低价格 TODO 需要根据字样进行切分获取最高价和最低价 转换成 float 类型
highest_price,lowest_price= data.price_fluctuation
lawsuit_status = "无诉讼" # 诉讼状态 TODO (API获取)
inheritor_ages = data.inheritor_age_count # [45, 60, 75] # 传承人年龄列表
return {
"highest_price": highest_price,
"lowest_price": lowest_price,
"lawsuit_status": lawsuit_status,
"inheritor_ages": inheritor_ages,
}
# 获取 市场估值C 相关参数
def _extract_calculation_params_c(data: UserValuationCreate) -> Dict[str, Any]:
# 稀缺性乘数C3 发行量
circulation = data.circulation\
# 时效性衰减C4 参数 用户选择距离最近一次市场活动(交易、报价、评估)的相距时间
last_market_activity = data.last_market_activity