feat(backend): 6-axis dynamic evaluation system with weight engine and template management
This commit is contained in:
@@ -13,8 +13,10 @@ from app.models.customer_plan import CustomerAcquisitionPlan
|
||||
from app.models.data_source import DataSource
|
||||
from app.models.decision_sentinel import DecisionSentinel
|
||||
from app.models.digital_twin import DigitalTwinModel
|
||||
from app.models.evaluation_template import EvaluationTemplate
|
||||
from app.models.exit_prediction import ExitPrediction
|
||||
from app.models.financial_data import FinancialData
|
||||
from app.models.fund import CompanyFundLink, Fund
|
||||
from app.models.health_score import HealthScore
|
||||
from app.models.hypothesis import Hypothesis
|
||||
from app.models.inquiry import InquiryList
|
||||
@@ -50,8 +52,11 @@ __all__ = [
|
||||
"DataSource",
|
||||
"DecisionSentinel",
|
||||
"DigitalTwinModel",
|
||||
"EvaluationTemplate",
|
||||
"ExitPrediction",
|
||||
"FinancialData",
|
||||
"Fund",
|
||||
"CompanyFundLink",
|
||||
"FirmProfile",
|
||||
"FundProfile",
|
||||
"HealthScore",
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""评价模板模型。
|
||||
|
||||
6 轴动态评价指标体系的模板配置,支持基金类型、存续期、企业阶段、产业赛道、投资策略、投资人类型的动态组合。
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.database import Base
|
||||
from app.core.types import JSONBType
|
||||
|
||||
|
||||
class EvaluationTemplate(Base):
|
||||
"""评价模板 — 6 轴配置单元,定义维度权重和专属指标。"""
|
||||
|
||||
__tablename__ = "evaluation_templates"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
tenant_id: Mapped[str] = mapped_column(String(36), ForeignKey("tenants.id"), nullable=False, index=True)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="模板名称")
|
||||
|
||||
# 6 轴参数
|
||||
fund_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="基金类型:angel/early_vc/growth_vc/pe/cvc/fof/distress/esg")
|
||||
fund_lifecycle: Mapped[str] = mapped_column(String(50), nullable=False, default="investment", comment="存续期阶段:investment/growth/exit_preparation/liquidation")
|
||||
company_stage: Mapped[str] = mapped_column(String(50), nullable=False, default="a", comment="企业阶段:seed/a/b/c/pre_ipo")
|
||||
industry: Mapped[str] = mapped_column(String(50), nullable=False, default="ai", comment="产业赛道:ai/saas/hardware/biotech/consumer/fintech/manufacturing")
|
||||
strategy: Mapped[str] = mapped_column(String(50), nullable=False, default="growth", comment="投资策略:growth/value/empowerment/turnaround")
|
||||
investor_type: Mapped[str] = mapped_column(String(50), nullable=False, default="investor", comment="投资人类型:gp/post_invest_lead/investor")
|
||||
|
||||
# 权重配置 — {dimension_key: weight},归一化后总和 = 1.0
|
||||
weights_json: Mapped[dict] = mapped_column(JSONBType, nullable=False, comment="14 维度权重(归一化后)")
|
||||
|
||||
# 维度裁剪
|
||||
enabled_dimensions: Mapped[list] = mapped_column(JSONBType, nullable=False, comment="启用的维度 key 列表")
|
||||
disabled_dimensions: Mapped[list] = mapped_column(JSONBType, nullable=False, default=list, comment="禁用的维度 key 列表")
|
||||
|
||||
# 专属指标 — [{key, label, description, data_source}]
|
||||
custom_metrics_json: Mapped[dict | None] = mapped_column(JSONBType, nullable=True, comment="赛道专属指标定义")
|
||||
|
||||
# 修饰因子
|
||||
lp_focus_metrics: Mapped[list | None] = mapped_column(JSONBType, nullable=True, comment="LP 附加指标列表")
|
||||
regional_benchmark: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="地域基准标识:china_mainland/us/sea/europe")
|
||||
|
||||
# 元数据
|
||||
is_default: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否为该组合的默认模板")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否启用")
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1, comment="版本号")
|
||||
|
||||
created_by: Mapped[str | None] = mapped_column(String(36), nullable=True, comment="创建人")
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
@@ -0,0 +1,95 @@
|
||||
"""基金模型。
|
||||
|
||||
管理基金类型、存续期、LP 构成等信息,支撑评价指标体系的动态权重计算。
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from datetime import date, datetime, timezone
|
||||
|
||||
from sqlalchemy import Boolean, Date, DateTime, Float, ForeignKey, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.database import Base
|
||||
from app.core.types import JSONBType
|
||||
|
||||
|
||||
class Fund(Base):
|
||||
"""基金信息 — 管理基金类型和存续期。"""
|
||||
|
||||
__tablename__ = "funds"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
tenant_id: Mapped[str] = mapped_column(String(36), ForeignKey("tenants.id"), nullable=False, index=True)
|
||||
name: Mapped[str] = mapped_column(String(200), nullable=False, comment="基金名称")
|
||||
|
||||
# 基金类型:angel/early_vc/growth_vc/pe/cvc/fof/distress/esg
|
||||
fund_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="基金类型")
|
||||
# 投资策略:growth/value/empowerment/turnaround
|
||||
strategy: Mapped[str] = mapped_column(String(50), nullable=False, default="growth", comment="投资策略")
|
||||
|
||||
# 存续期信息
|
||||
established_date: Mapped[date | None] = mapped_column(Date, nullable=True, comment="基金成立日")
|
||||
total_lifespan_months: Mapped[int] = mapped_column(Integer, nullable=False, default=84, comment="总存续期(月)")
|
||||
investment_period_months: Mapped[int] = mapped_column(Integer, nullable=False, default=48, comment="投资期(月)")
|
||||
|
||||
# LP 构成 — {government: 30, market: 50, corporate: 20}
|
||||
lp_composition_json: Mapped[dict | None] = mapped_column(JSONBType, nullable=True, comment="LP 构成百分比")
|
||||
|
||||
# 地域
|
||||
primary_market: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="主要市场:china_mainland/us/sea/europe")
|
||||
|
||||
# 状态
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否活跃")
|
||||
|
||||
# 元数据
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
@property
|
||||
def current_lifecycle(self) -> str:
|
||||
"""根据当前日期自动计算基金存续期阶段。
|
||||
|
||||
返回:investment / growth / exit_preparation / liquidation
|
||||
"""
|
||||
if not self.established_date:
|
||||
return "investment"
|
||||
|
||||
today = date.today()
|
||||
months_elapsed = (today.year - self.established_date.year) * 12 + (today.month - self.established_date.month)
|
||||
|
||||
if months_elapsed < self.investment_period_months:
|
||||
return "investment"
|
||||
elif months_elapsed < self.total_lifespan_months - 24:
|
||||
return "growth"
|
||||
elif months_elapsed < self.total_lifespan_months - 12:
|
||||
return "exit_preparation"
|
||||
else:
|
||||
return "liquidation"
|
||||
|
||||
|
||||
class CompanyFundLink(Base):
|
||||
"""企业-基金关联 — 一个企业可能被多支基金投资。"""
|
||||
|
||||
__tablename__ = "company_fund_links"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
company_id: Mapped[str] = mapped_column(String(36), ForeignKey("companies.id"), nullable=False, index=True)
|
||||
fund_id: Mapped[str] = mapped_column(String(36), ForeignKey("funds.id"), nullable=False, index=True)
|
||||
|
||||
investment_date: Mapped[date | None] = mapped_column(Date, nullable=True, comment="投资日期")
|
||||
investment_stage: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="投资时企业阶段")
|
||||
round: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="轮次")
|
||||
amount: Mapped[float | None] = mapped_column(Float, nullable=True, comment="投资金额(万元)")
|
||||
ownership_pct: Mapped[float | None] = mapped_column(Float, nullable=True, comment="持股比例(%)")
|
||||
|
||||
is_current: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="当前是否持有")
|
||||
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
@@ -13,6 +13,7 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.database import Base
|
||||
from app.core.types import JSONBType
|
||||
from app.core.types import JSONBType as _JSONB # 兼容别名
|
||||
|
||||
|
||||
class HealthScore(Base):
|
||||
@@ -47,3 +48,13 @@ class HealthScore(Base):
|
||||
calculated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
# 评价模板关联(向后兼容:旧数据为 NULL)
|
||||
template_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("evaluation_templates.id"), nullable=True, comment="使用的评价模板 ID")
|
||||
fund_type: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="冗余存储基金类型,便于查询")
|
||||
fund_lifecycle: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="冗余存储存续期阶段")
|
||||
company_stage: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="冗余存储企业阶段")
|
||||
industry: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="冗余存储产业赛道")
|
||||
strategy: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="冗余存储投资策略")
|
||||
custom_metrics_result: Mapped[dict | None] = mapped_column(JSONBType, nullable=True, comment="专属指标评分结果")
|
||||
lp_focus_result: Mapped[dict | None] = mapped_column(JSONBType, nullable=True, comment="LP 附加指标结果")
|
||||
|
||||
Reference in New Issue
Block a user