Corin1998 commited on
Commit
c652bcc
·
verified ·
1 Parent(s): edde523

Create market_infer.py

Browse files
Files changed (1) hide show
  1. core/market_infer.py +117 -0
core/market_infer.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # core/market_infer.py
2
+ from __future__ import annotations
3
+ import os, json, hashlib, time
4
+ from typing import Dict, Any, List
5
+ from openai import OpenAI
6
+
7
+ OPENAI_MODEL_TEXT = os.environ.get("OPENAI_TEXT_MODEL", "gpt-4o-mini")
8
+
9
+ # ---- simple memo cache (in-memory) ----
10
+ _CACHE: Dict[str, Dict[str, Any]] = {}
11
+
12
+ def _client() -> OpenAI:
13
+ key = os.environ.get("OPENAI_API_KEY")
14
+ if not key:
15
+ raise RuntimeError("OPENAI_API_KEY が未設定です")
16
+ return OpenAI(api_key=key, timeout=45)
17
+
18
+ def _cache_key(industry: str, products: List[str], country: str, horizon_years: int) -> str:
19
+ raw = json.dumps({
20
+ "industry": industry.strip(),
21
+ "products": [p.strip() for p in products if p.strip()],
22
+ "country": country.strip(),
23
+ "horizon": horizon_years
24
+ }, ensure_ascii=False, sort_keys=True)
25
+ return hashlib.sha256(raw.encode("utf-8")).hexdigest()
26
+
27
+ def _to_float(x):
28
+ if x is None: return None
29
+ try: return float(str(x).replace(",",""))
30
+ except Exception: return None
31
+
32
+ def infer_market_metrics(industry: str, products: List[str], country: str = "JP", horizon_years: int = 3) -> Dict[str, Any]:
33
+ """
34
+ 事業領域・商品から市場メトリクスを推定して返す。
35
+ 返り値は数値を極力float化した dict。
36
+ """
37
+ key = _cache_key(industry, products, country, horizon_years)
38
+ if key in _CACHE:
39
+ return _CACHE[key]
40
+
41
+ prompt = f"""
42
+ あなたは投資銀行のセクターアナリストです。以下の事業領域・商品と地域を前提に、
43
+ “定量”重視で市場メトリクスを推定してください。専門常識に基づく概算で構いません。
44
+ 出力は **厳密なJSON** のみ、単位とキーは以下スキーマに合わせてください。
45
+
46
+ 【入力】
47
+ - 事業領域: {industry.strip() or "(未入力)"}
48
+ - 商品: {", ".join([p.strip() for p in products if p.strip()]) or "(未入力)"}
49
+ - 主対象国/地域: {country}
50
+ - 予測期間: 直近→{horizon_years}年
51
+
52
+ 【出力スキーマ(数値は可能な限り実数値、%は実数)】
53
+ {{
54
+ "市場の年成長率(%)": 0.0,
55
+ "市場成熟度(0-1)": 0.0, // 0=黎明, 1=成熟
56
+ "競争強度(0-10)": 0.0, // 大きいほど競争が激しい
57
+ "参入障壁(0-10)": 0.0,
58
+ "価格決定力(0-10)": 0.0,
59
+ "サイクル感応度(0-10)": 0.0,
60
+ "規制リスク(0-10)": 0.0,
61
+ "技術破壊リスク(0-10)": 0.0,
62
+ "TAM_億円": 0.0, "SAM_億円": 0.0, "SOM_億円": 0.0,
63
+ "製品別年成長率(%)": {{"<製品名>": 0.0}},
64
+ "注記": ["定量根拠の観点や前提(簡潔に)"]
65
+ }}
66
+
67
+ 注意:
68
+ - 未知は推定値で埋めて構いません(整合性重視)。
69
+ - 根拠の“観点”のみ列挙し、URLは不要。
70
+ - 回答はJSONのみ。
71
+ """.strip()
72
+
73
+ try:
74
+ cli = _client()
75
+ resp = cli.chat.completions.create(
76
+ model=OPENAI_MODEL_TEXT,
77
+ messages=[
78
+ {"role": "system", "content": "出力は厳密なJSONのみ。説明やマークダウンは不要。"},
79
+ {"role": "user", "content": prompt},
80
+ ],
81
+ response_format={"type": "json_object"},
82
+ temperature=0.3,
83
+ )
84
+ data = json.loads(resp.choices[0].message.content)
85
+
86
+ # 型の安全化
87
+ out: Dict[str, Any] = {}
88
+ for k in [
89
+ "市場の年成長率(%)","市場成熟度(0-1)","競争強度(0-10)","参入障壁(0-10)",
90
+ "価格決定力(0-10)","サイクル感応度(0-10)","規制リスク(0-10)","技術破壊リスク(0-10)",
91
+ "TAM_億円","SAM_億円","SOM_億円"
92
+ ]:
93
+ out[k] = _to_float(data.get(k))
94
+ # 製品別成長
95
+ prod = {}
96
+ for name, val in (data.get("製品別年成長率(%)") or {}).items():
97
+ fv = _to_float(val)
98
+ if name and fv is not None:
99
+ prod[str(name)] = fv
100
+ out["製品別年成長率(%)"] = prod
101
+ # 注記
102
+ notes = data.get("注記") or []
103
+ out["注記"] = [str(x) for x in notes][:5]
104
+
105
+ _CACHE[key] = out
106
+ return out
107
+ except Exception as e:
108
+ # フォールバック(無難値)
109
+ fallback = {
110
+ "市場の年成長率(%)": 4.0, "市場成熟度(0-1)": 0.6, "競争強度(0-10)": 6.0, "参入障壁(0-10)": 5.0,
111
+ "価格決定力(0-10)": 5.0, "サイクル感応度(0-10)": 5.0, "規制リスク(0-10)": 4.0, "技術破壊リスク(0-10)": 5.0,
112
+ "TAM_億円": 1000.0, "SAM_億円": 300.0, "SOM_億円": 60.0,
113
+ "製品別年成長率(%)": {p: 5.0 for p in products if p.strip()},
114
+ "注記": [f"推定失敗のため既定値を使用: {type(e).__name__}"]
115
+ }
116
+ _CACHE[key] = fallback
117
+ return fallback