diff --git a/.gitignore b/.gitignore index b74e2d9..64a4483 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ db.sqlite3 db.sqlite3-journal db.sqlite3-shm db.sqlite3-wal - +test-api.py +test_api.py .DS_Store ._.DS_Store \ No newline at end of file diff --git a/app/api/v1/calculation/calcuation.py b/app/api/v1/calculation/calcuation.py index 5d03a7c..9e33f85 100644 --- a/app/api/v1/calculation/calcuation.py +++ b/app/api/v1/calculation/calcuation.py @@ -13,41 +13,67 @@ from app.schemas.valuation import ( from app.schemas.base import Success, SuccessExtra from app.utils.app_user_jwt import get_current_app_user_id 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.models.esg import ESG +from app.models.industry import Industry +from app.models.policy import Policy 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) + data: UserValuationCreate, + user_id: int = Depends(get_current_app_user_id) ): """ 计算估值评估 - + 根据用户提交的估值评估数据,调用计算引擎进行经济价值B1计算 """ try: # 创建计算器实例 calculator = EconomicValueB1Calculator() - - # 从用户数据中提取计算所需的参数 + + # 根据行业查询 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 + # 提取计算参数 input_data = _extract_calculation_params(data) - - # 调用计算引擎进行估值计算 + # ESG关联价值 ESG分 (0-10分) + input_data["esg_score"] = esg_score + # 行业修正系数I + input_data["industry_coefficient"] = fix_num_score + # 政策匹配度 + input_data["policy_match_score"] = policy_match_score + + # 调用计算引擎 calculation_result = calculator.calculate_complete_economic_value_b1(input_data) - + # 创建估值评估记录 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)}") @@ -66,15 +92,22 @@ def _extract_calculation_params(data: UserValuationCreate) -> Dict[str, Any]: # 财务价值所需数据 从近三年收益计算 three_year_income = data.three_year_income or [0, 0, 0] - - # 法律强度L相关参数 - 需要用户额外提供评分 - # 这里使用默认值,实际应用中需要用户填写 - patent_score = 5.0 # 专利分 (0-10分) - popularity_score = 5.0 # 普及地域分 (0-10分) - infringement_score = 5.0 # 侵权分 (0-10分) - + # 法律强度L相关参数 + # 普及地域分值 默认 7分 + popularity_score = calculate_popularity_score(data.application_coverage) + # TODO 专利剩余年限【专利证书】 需要使用第三方API + patent = data.patent_application_no + patent_score = 0 + # 侵权分 默认 6 TODO 需要使用第三方API 无侵权记录(10分),历史侵权已解决(6分),现存纠纷(2分) + # infringement_score = calculate_infringement_score() + infringement_score = 0 + + # 发展潜力D相关参数 - esg_score = 5.0 # ESG分 (0-10分) + # 专利使用量 TODO 需要使用第三方API + patent_score = calculate_patent_usage_score(0) + + # 创新投入比 = (研发费用/营收) * 100 try: rd_investment = float(data.rd_investment or 0) @@ -82,39 +115,44 @@ def _extract_calculation_params(data: UserValuationCreate) -> Dict[str, Any]: innovation_ratio = (rd_investment / annual_revenue) * 100 if annual_revenue > 0 else 0 except (ValueError, TypeError): innovation_ratio = 0.0 - - # 行业系数I - 系统配置值 - target_industry_roe = 0.15 # 目标行业平均ROE - benchmark_industry_roe = 0.12 # 基准行业ROE - + + # # 流量因子B12相关参数 - # 近30天搜索指数S1 - 从社交媒体数据计算 - search_index_s1 = 4500.0 # 默认值,实际应从API获取 - industry_average_s2 = 5000.0 # 行业均值,系统配置 - - # 社交媒体传播度S3 - 从线上账号信息计算 - social_media_spread_s3 = 1.07 # 默认值,实际应从API获取 - + # 近30天搜索指数S1 - 从社交媒体数据计算 TODO 需要使用第三方API + search_index_s1 = calculate_search_index_s1() # 默认值,实际应从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 - 根据行业和资助情况计算 - policy_compatibility_score = 9.1 # 默认值,实际应系统计算 - + # 实施阶段 + implementation_stage = data.implementation_stage + # 资金支持 + funding_support = data.funding_status + return { # 基础价值B11相关参数 - 'financial_value': financial_value, + 'three_year_income': three_year_income, 'patent_score': patent_score, 'popularity_score': popularity_score, 'infringement_score': infringement_score, - 'esg_score': esg_score, 'innovation_ratio': innovation_ratio, - 'target_industry_roe': target_industry_roe, - 'benchmark_industry_roe': benchmark_industry_roe, - + # 流量因子B12相关参数 'search_index_s1': search_index_s1, - 'industry_average_s2': industry_average_s2, - 'social_media_spread_s3': social_media_spread_s3, - + # 'industry_average_s2': industry_average_s2, + # 'social_media_spread_s3': social_media_spread_s3, + 'click_count': int(data.click_count) or 100, + 'view_count': int(data.link_views) or 100, + # 政策乘数B13相关参数 - 'policy_compatibility_score': policy_compatibility_score + 'implementation_stage': implementation_stage, + 'funding_support':funding_support } \ No newline at end of file diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/calculation_engine/economic_value_b1/economic_value_b1.py b/app/utils/calculation_engine/economic_value_b1/economic_value_b1.py index e263163..1d06fc2 100644 --- a/app/utils/calculation_engine/economic_value_b1/economic_value_b1.py +++ b/app/utils/calculation_engine/economic_value_b1/economic_value_b1.py @@ -8,7 +8,7 @@ from typing import Dict try: # 相对导入(当作为包使用时) - from .sub_formulas.basic_value_b11 import BasicValueB11Calculator + from .sub_formulas.basic_value_b11 import BasicValueB11Calculator, calculate_popularity_score from .sub_formulas.traffic_factor_b12 import TrafficFactorB12Calculator from .sub_formulas.policy_multiplier_b13 import PolicyMultiplierB13Calculator except ImportError: @@ -37,12 +37,12 @@ class EconomicValueB1Calculator: 经济价值B1 = 基础价值B11 × (1 + 流量因子B12) × 政策乘数B13 - Args: + args: basic_value_b11: 基础价值B11 (系统计算) traffic_factor_b12: 流量因子B12 (系统计算) policy_multiplier_b13: 政策乘数B13 (系统计算) - Returns: + returns: float: 经济价值B1 """ economic_value = basic_value_b11 * (1 + traffic_factor_b12) * policy_multiplier_b13 @@ -50,27 +50,27 @@ class EconomicValueB1Calculator: return economic_value def calculate_complete_economic_value_b1(self, input_data: Dict) -> Dict: + """ 计算完整的经济价值B1,包含所有子公式 - Args: + args: input_data: 输入数据字典,包含所有必要的参数 - Returns: + returns: Dict: 包含所有中间计算结果和最终结果的字典 """ # 财务价值F 近三年年均收益列表 [1,2,3] - financial_value = self.basic_value_calculator.calculate_financial_value_f() # 计算法律强度L patent_score: 专利分 (0-10分) (用户填写) # popularity_score: 普及地域分 (0-10分) (用户填写) # infringement_score: 侵权分 (0-10分) (用户填写) - + popularity_score = calculate_popularity_score() legal_strength = self.basic_value_calculator.calculate_legal_strength_l() + # 发展潜力 patent_score: 专利分 (0-10分) (用户填写) # esg_score: ESG分 (0-10分) (用户填写) # innovation_ratio: 创新投入比 (研发费用/营收) * 100 (用户填写) - development_potential = self.basic_value_calculator.calculate_development_potential_d() # 计算行业系数I target_industry_roe: 目标行业平均ROE (系统配置) # benchmark_industry_roe: 基准行业ROE (系统配置) diff --git a/app/utils/calculation_engine/economic_value_b1/sub_formulas/basic_value_b11.py b/app/utils/calculation_engine/economic_value_b1/sub_formulas/basic_value_b11.py index 72d427a..8c1e1ab 100644 --- a/app/utils/calculation_engine/economic_value_b1/sub_formulas/basic_value_b11.py +++ b/app/utils/calculation_engine/economic_value_b1/sub_formulas/basic_value_b11.py @@ -19,13 +19,13 @@ class BasicValueB11Calculator: 基础价值B11 = 财务价值F × (0.45 + 0.05 × 行业系数I) + 法律强度L × (0.35 + 0.05 × 行业系数I) + 发展潜力D × 0.2 - Args: + args: financial_value: 财务价值F (用户填写) legal_strength: 法律强度L (用户填写) development_potential: 发展潜力D (用户填写) industry_coefficient: 行业系数I (系统配置) - Returns: + returns: float: 基础价值B11 """ basic_value = (financial_value * (0.45 + 0.05 * industry_coefficient) + @@ -51,11 +51,11 @@ class BasicValueB11Calculator: 财务价值F = [3年内年均收益 × (1 + 增长率)^5] / 5 - Args: + args: annual_revenue_3_years: 近三年年均收益列表,单位:万元 (用户填写) growth_rate: 增长率,如果为None则自动计算 (用户填写) - Returns: + returns: float: 财务价值F """ if len(annual_revenue_3_years) != 3: @@ -76,10 +76,10 @@ class BasicValueB11Calculator: """ 根据三年收益数据计算增长率 - Args: + args: revenue_data: 三年收益数据 (用户填写) - Returns: + returns: float: 增长率 """ if len(revenue_data) != 3: @@ -104,12 +104,12 @@ class BasicValueB11Calculator: 法律强度L = 专利分 × 0.4 + 普及分 × 0.3 + 侵权分 × 0.3 - Args: + args: patent_score: 专利分 (0-10分) (用户填写) popularity_score: 普及地域分 (0-10分) (用户填写) infringement_score: 侵权分 (0-10分) (用户填写) - Returns: + returns: float: 法律强度L """ @@ -129,12 +129,12 @@ class BasicValueB11Calculator: 发展潜力D = 专利分 × 0.5 + ESG分 × 0.2 + 创新投入比 × 0.3 - Args: + args: patent_score: 专利分 (0-10分) (用户填写) esg_score: ESG分 (0-10分) (用户填写) innovation_ratio: 创新投入比 (研发费用/营收) * 100 (用户填写) - Returns: + returns: float: 发展潜力D """ @@ -152,11 +152,11 @@ class BasicValueB11Calculator: 行业系数I = (目标行业平均ROE - 基准行业ROE) / 基准行业ROE - Args: + args: target_industry_roe: 目标行业平均ROE (系统配置) benchmark_industry_roe: 基准行业ROE (系统配置) - Returns: + returns: float: 行业系数I """ if benchmark_industry_roe == 0: @@ -177,10 +177,10 @@ def calculate_patent_score(patent_remaining_years: int) -> float: - 5-10年: 7分 - <5年: 3分 - Args: + args: patent_remaining_years: 专利剩余保护期(年) (用户填写) - Returns: + returns: float: 专利分 """ if patent_remaining_years > 10: @@ -201,10 +201,10 @@ def calculate_patent_usage_score(patent_count: int) -> float: - 每引用一项: +2.5分 - 10分封顶 - Args: + args: patent_count: 专利数量 (用户填写) - Returns: + returns: float: 专利使用量分 """ score = min(patent_count * 2.5, 10.0) @@ -218,10 +218,10 @@ def calculate_popularity_score(region_coverage: str) -> float: 全球覆盖(10分),全国覆盖(7分),区域覆盖(4分) - Args: + args: region_coverage: 普及地域类型 (用户填写) - Returns: + returns: float: 普及地域分 """ coverage_scores = { @@ -230,7 +230,7 @@ def calculate_popularity_score(region_coverage: str) -> float: "区域覆盖": 4.0 } - return coverage_scores.get(region_coverage, 0.0) + return coverage_scores.get(region_coverage, 7.0) # 侵权记录评分 @@ -240,10 +240,10 @@ def calculate_infringement_score(infringement_status: str) -> float: 无侵权记录(10分),历史侵权已解决(6分),现存纠纷(2分) - Args: + args: infringement_status: 侵权记录状态 (用户填写) - Returns: + returns: float: 侵权记录分 """ infringement_scores = { @@ -252,7 +252,7 @@ def calculate_infringement_score(infringement_status: str) -> float: "现存纠纷": 2.0 } - return infringement_scores.get(infringement_status, 0.0) + return infringement_scores.get(infringement_status, 6.0) # 示例使用 diff --git a/app/utils/calculation_engine/economic_value_b1/sub_formulas/policy_multiplier_b13.py b/app/utils/calculation_engine/economic_value_b1/sub_formulas/policy_multiplier_b13.py index 78c4f5f..331af46 100644 --- a/app/utils/calculation_engine/economic_value_b1/sub_formulas/policy_multiplier_b13.py +++ b/app/utils/calculation_engine/economic_value_b1/sub_formulas/policy_multiplier_b13.py @@ -15,7 +15,7 @@ class PolicyMultiplierB13Calculator: Args: policy_compatibility_score: 政策契合度评分P (系统计算) - Returns: + returns: float: 政策乘数B13 """ # @@ -38,7 +38,7 @@ class PolicyMultiplierB13Calculator: implementation_stage_score: 实施阶段评分 (用户填写) funding_support_score: 资金支持度 (用户填写) - Returns: + returns: float: 政策契合度评分P """ # @@ -57,7 +57,7 @@ class PolicyMultiplierB13Calculator: Args: industry: 所属行业 (用户填写) - Returns: + returns: float: 政策匹配度 """ @@ -72,7 +72,7 @@ class PolicyMultiplierB13Calculator: Args: implementation_stage: 实施阶段 (用户填写) - Returns: + returns: float: 实施阶段评分 """ stage_scores = { @@ -81,7 +81,7 @@ class PolicyMultiplierB13Calculator: "试点阶段": 4.0 } - return stage_scores.get(implementation_stage, 0.0) + return stage_scores.get(implementation_stage, 10.0) def calculate_funding_support_score(self, funding_support: str) -> float: """ @@ -92,7 +92,7 @@ class PolicyMultiplierB13Calculator: Args: funding_support: 资金支持情况 (用户填写) - Returns: + returns: float: 资金支持度 """ funding_scores = { diff --git a/app/utils/calculation_engine/economic_value_b1/sub_formulas/traffic_factor_b12.py b/app/utils/calculation_engine/economic_value_b1/sub_formulas/traffic_factor_b12.py index 6e785ed..20a382e 100644 --- a/app/utils/calculation_engine/economic_value_b1/sub_formulas/traffic_factor_b12.py +++ b/app/utils/calculation_engine/economic_value_b1/sub_formulas/traffic_factor_b12.py @@ -19,12 +19,12 @@ class TrafficFactorB12Calculator: 流量因子B12 = ln(近30天搜索指数S1/行业均值S2) × 0.3 + 社交媒体传播度S3 × 0.7 - Args: + args: search_index_s1: 近30天搜索指数S1 (API获取) industry_average_s2: 行业均值S2 (系统配置) social_media_spread_s3: 社交媒体传播度S3 (API获取) - Returns: + returns: float: 流量因子B12 """ # 避免除零和对数计算错误 @@ -40,30 +40,8 @@ class TrafficFactorB12Calculator: social_media_spread_s3 * 0.7) return traffic_factor - - def calculate_search_index_s1(self, - baidu_index: float, - wechat_index: float, - weibo_index: float) -> float: - """ - 计算近30天搜索指数S1 - 近30天搜索指数S1 = 百度搜索指数 × 0.4 + 微信搜索指数 × 0.3 + 微博搜索指数 × 0.3 - - Args: - baidu_index: 百度搜索指数 (API获取) - wechat_index: 微信搜索指数 (API获取) - weibo_index: 微博搜索指数 (API获取) - - Returns: - float: 近30天搜索指数S1 - """ - # - search_index = (baidu_index * 0.4 + - wechat_index * 0.3 + - weibo_index * 0.3) - - return search_index + def calculate_social_media_spread_s3(self, interaction_index: float, @@ -73,20 +51,20 @@ class TrafficFactorB12Calculator: 计算社交媒体传播度S3 社交媒体传播度S3 = 互动量指数 × 0.4 + 覆盖人群指数 × 0.3 + 转化效率 × 0.3 - - Args: + + args: interaction_index: 互动量指数 (API获取) coverage_index: 覆盖人群指数 (API获取) conversion_efficiency: 转化效率 (用户填写) - - Returns: + + returns: float: 社交媒体传播度S3 """ - # - social_media_spread = (interaction_index * 0.4 + - coverage_index * 0.3 + + # + social_media_spread = (interaction_index * 0.4 + + coverage_index * 0.3 + conversion_efficiency * 0.3) - + return social_media_spread def calculate_interaction_index(self, @@ -98,12 +76,12 @@ class TrafficFactorB12Calculator: 互动量指数 = (点赞 + 评论 + 转发) / 1000 - Args: + args: likes: 点赞数 (API获取) comments: 评论数 (API获取) shares: 转发数 (API获取) - Returns: + returns: float: 互动量指数 """ # @@ -117,10 +95,10 @@ class TrafficFactorB12Calculator: 覆盖人群指数 = 粉丝数 / 10000 - Args: + args: followers: 粉丝数 (API获取) - Returns: + returns: float: 覆盖人群指数 """ # @@ -137,11 +115,11 @@ class TrafficFactorB12Calculator: : 转化效率 = 商品链接点击量 / 内容浏览量 - Args: + args: click_count: 商品链接点击量 (用户填写) view_count: 内容浏览量 (用户填写) - Returns: + returns: float: 转化效率 """ if view_count == 0: @@ -163,10 +141,10 @@ class PlatformDataProcessor: 输入格式:B站:12345678\n抖音:22334455 - Args: + args: platform_data: 平台账号数据字符串 (用户填写) - Returns: + returns: Dict[str, str]: 平台账号字典 """ accounts = {} @@ -188,10 +166,10 @@ class PlatformDataProcessor: """ 计算多平台互动数据 - Args: + args: platform_data: 平台数据字典,格式为 {平台名: {likes: int, comments: int, shares: int, followers: int}} (API获取) - Returns: + returns: Tuple[float, float]: (互动量指数, 覆盖人群指数) """ total_interactions = 0 @@ -227,11 +205,11 @@ def calculate_heat_score(daily_views: float, favorites: int) -> float: - 低热度:近7日日均浏览量 < 100,且收藏数 < 20 → 0.2 - 无数据:无任何浏览与互动数据 → 0.0 - Args: + args: daily_views: 近7日日均浏览量 (API获取) favorites: 收藏数 (API获取) - Returns: + returns: float: 热度分 """ if daily_views > 1000 or favorites > 100: @@ -243,7 +221,29 @@ def calculate_heat_score(daily_views: float, favorites: int) -> float: else: return 0.0 +# 30天搜索指数S1 +def calculate_search_index_s1(baidu_index: float, + wechat_index: float, + weibo_index: float) -> float: + """ + 计算近30天搜索指数S1 + 近30天搜索指数S1 = 百度搜索指数 × 0.4 + 微信搜索指数 × 0.3 + 微博搜索指数 × 0.3 + + args: + baidu_index: 百度搜索指数 (API获取) + wechat_index: 微信搜索指数 (API获取) + weibo_index: 微博搜索指数 (API获取) + + returns: + float: 近30天搜索指数S1 + """ + # + search_index = (baidu_index * 0.4 + + wechat_index * 0.3 + + weibo_index * 0.3) + + return search_index # 示例使用 if __name__ == "__main__": # 创建计算器实例