app:
  description: 投資案件評価メモを作成するワークフロー。ユーザーが投資額・期待CF・割引率・リスク等を1つのテキスト欄（query）に入力すると、構造化抽出、仮計算（ROI/NPV/IRR）、定性評価、推奨スタンスを含む評価メモを返します。
  icon: 📈
  icon_background: '#FFEAD5'
  mode: workflow
  name: 投資案件評価メモ作成
  use_icon_as_answer_icon: false
kind: app
version: 0.6.0
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      image:
        enabled: false
    opening_statement: ''
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
  graph:
    edges:
    - data:
        sourceType: start
        targetType: parameter-extractor
      id: start-to-pe1
      source: start
      target: pe1
    - data:
        sourceType: parameter-extractor
        targetType: code
      id: pe1-to-code1
      source: pe1
      target: code1
    - data:
        sourceType: code
        targetType: llm
      id: code1-to-llm1
      source: code1
      target: llm1
    - data:
        sourceType: llm
        targetType: end
      id: llm1-to-end
      source: llm1
      target: end
    nodes:
    - data:
        title: 開始
        type: start
        variables:
        - label: query
          max_length: 2048
          options: []
          required: true
          type: paragraph
          variable: query
      height: 90
      id: start
      position:
        x: 80
        y: 282
      type: custom
      width: 244
    - data:
        title: 情報抽出
        type: parameter-extractor
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.2
        query:
        - start
        - query
        parameters:
        - name: investment_amount
          type: number
          description: 投資額（通貨単位は入力テキスト内で指定）
          required: true
        - name: expected_cash_flows
          type: string
          description: 期待キャッシュフロー（年ごとにカンマ区切りで）
          required: true
        - name: discount_rate
          type: number
          description: 割引率（年率、%で記載されることが多い）
          required: true
        - name: project_life
          type: number
          description: 想定期間（年）
          required: false
        - name: risk_assessment
          type: string
          description: リスク要因の概要
          required: false
        - name: strategic_fit
          type: string
          description: 戦略適合性の説明
          required: false
        - name: currency
          type: string
          description: '通貨単位（例: JPY, USD）'
          required: false
        reasoning_mode: prompt
        instruction: 以下の文章から投資評価に必要な項目を抽出してください。投資額、期待キャッシュフロー（年ごと）、割引率（%）、想定期間（年）、主要リスク、戦略適合性、通貨を可能な限り抽出してください。キャッシュフローは年ごとにカンマ区切りの文字列で返してください。
      height: 90
      id: pe1
      position:
        x: 380
        y: 282
      type: custom
      width: 244
    - data:
        title: 数値計算（ROI/NPV/IRR）
        type: code
        code_language: python3
        code: "def _safe_str(v):\n    \"\"\"Convert any value to string safely.\"\"\
          \"\n    if v is None:\n        return \"\"\n    if isinstance(v, list):\n\
          \        return \"\\n\".join(str(i) for i in v)\n    return str(v)\n\ndef\
          \ _safe_list(v):\n    \"\"\"Ensure value is a list.\"\"\"\n    if v is None:\n\
          \        return []\n    if isinstance(v, str):\n        return [v]\n   \
          \ if isinstance(v, list):\n        return v\n    return [v]\n\ndef main(**kwargs)\
          \ -> dict:\n    inputs = kwargs\n    # 入力取り出しと安全なキャスト\n    inv = inputs.get(\"\
          investment\")\n    cf_str = inputs.get(\"cashflows\")\n    disc = inputs.get(\"\
          discount\")\n    life = inputs.get(\"life\")\n    cur = inputs.get(\"currency\"\
          )\n    # デフォルト\n    if inv is None:\n        inv = 0.0\n    try:\n     \
          \   investment = float(inv)\n    except Exception:\n        investment =\
          \ 0.0\n    if cf_str is None:\n        cf_list = []\n    else:\n       \
          \ text = str(cf_str)\n        text = text.replace(\";\", \",\")\n      \
          \  parts = [p.strip() for p in text.split(\",\")]\n        nums = []\n \
          \       for p in parts:\n            if p != \"\":\n                try:\n\
          \                    nums.append(float(p))\n                except Exception:\n\
          \                    # 無効な値は無視\n                    pass\n        cf_list\
          \ = nums\n    try:\n        discount = float(disc)\n    except Exception:\n\
          \        discount = 0.0\n    # 割引率がパーセント表記（例: 10）で渡された場合を想定して調整\n    if\
          \ discount > 1.0:\n        discount = discount / 100.0\n    # ROI\n    total_cf\
          \ = 0.0\n    for v in cf_list:\n        total_cf = total_cf + v\n    roi\
          \ = 0.0\n    if investment != 0.0:\n        roi = (total_cf - investment)\
          \ / investment\n    # NPV（初年度を1年目とする）\n    npv = -investment\n    for i,\
          \ v in enumerate(cf_list):\n        denom = (1.0 + discount) ** (i + 1)\n\
          \        npv = npv + v / denom\n    # IRR（単純ニュートン法＋バイセクションfallback）\n  \
          \  def irr_calc(cashflows):\n        # cashflows: list where cashflows[0]\
          \ is -investment, then yrs\n        if not cashflows:\n            return\
          \ None\n        cf = [ -investment ] + cashflows\n        # function for\
          \ NPV at rate r\n        def npv_at(r):\n            s = 0.0\n         \
          \   for t, val in enumerate(cf):\n                s = s + val / ((1.0 +\
          \ r) ** t)\n            return s\n        # derivative for Newton\n    \
          \    def npv_derivative(r):\n            s = 0.0\n            for t, val\
          \ in enumerate(cf):\n                if t == 0:\n                    continue\n\
          \                s = s - t * val / ((1.0 + r) ** (t + 1))\n            return\
          \ s\n        r = 0.1\n        for _ in range(100):\n            denom =\
          \ 1.0 + r\n            if denom == 0.0:\n                break\n       \
          \     val = npv_at(r)\n            der = npv_derivative(r)\n           \
          \ if der == 0.0:\n                break\n            newr = r - val / der\n\
          \            if abs(newr - r) < 1e-6:\n                r = newr\n      \
          \          break\n            r = newr\n        # if rate unrealistic, try\
          \ bisection\n        if r < -0.9999 or r != r:\n            low = -0.9999\n\
          \            high = 1.0\n            f_low = npv_at(low)\n            f_high\
          \ = npv_at(high)\n            if f_low * f_high > 0:\n                return\
          \ None\n            for _ in range(100):\n                mid = (low + high)\
          \ / 2.0\n                f_mid = npv_at(mid)\n                if abs(f_mid)\
          \ < 1e-6:\n                    return mid\n                if f_low * f_mid\
          \ <= 0:\n                    high = mid\n                    f_high = f_mid\n\
          \                else:\n                    low = mid\n                \
          \    f_low = f_mid\n            return (low + high) / 2.0\n        return\
          \ r\n    irr_value = None\n    if len(cf_list) > 0:\n        irr_value =\
          \ irr_calc(cf_list)\n    # 結果整形\n    parts = []\n    parts.append(\"投資額:\
          \ \" + str(investment))\n    parts.append(\"通貨: \" + str(cur))\n    parts.append(\"\
          期待キャッシュフロー(年ごと): \" + str(cf_list))\n    parts.append(\"割引率: \" + str(discount))\n\
          \    parts.append(\"合計期待CF: \" + str(total_cf))\n    parts.append(\"ROI:\
          \ \" + str(round(roi * 100.0, 2)) + \" %\")\n    parts.append(\"NPV: \"\
          \ + str(round(npv, 2)))\n    if irr_value is None:\n        parts.append(\"\
          IRR: 計算不可\")\n    else:\n        parts.append(\"IRR: \" + str(round(irr_value\
          \ * 100.0, 2)) + \" %\")\n    result_text = \"\\n\".join(parts)\n    return\
          \ dict(output=result_text)\n"
        variables:
        - value_selector:
          - pe1
          - investment_amount
          variable: investment
        - value_selector:
          - pe1
          - expected_cash_flows
          variable: cashflows
        - value_selector:
          - pe1
          - discount_rate
          variable: discount
        - value_selector:
          - pe1
          - project_life
          variable: life
        - value_selector:
          - pe1
          - risk_assessment
          variable: risk
        - value_selector:
          - pe1
          - strategic_fit
          variable: strategy
        - value_selector:
          - pe1
          - currency
          variable: currency
        outputs:
          output:
            type: string
            children: null
      height: 90
      id: code1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: 評価メモ生成
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.6
        prompt_template:
        - role: system
          text: 'あなたは経営企画部の投資評価アナリストです。以下の入力と計算結果を用いて、投資委員会・取締役会向けの評価メモを作成してください。メモには必ず、要約（1段落）、計算結果（ROI/NPV/IRRの数値を明示）、主要リスク、戦略適合性、定性評価（採択理由の根拠）、推奨スタンス（Go
            / Conditional / No-go）とその条件や留意点を含めてください。数値は可能な限り具体的に示し、前提・仮定も明記してください。簡潔で読みやすい箇条書きと短い段落を混ぜて出力してください。


            ---


            【最終出力フォーマット (この指示が最優先)】

            最終出力は **読みやすい日本語の Markdown** で返してください。JSON

            配列・オブジェクトをそのまま出力してはいけません。

            - 見出し (## / ###) でセクションを区切る

            - リスト (- / 1.) や表 (| ... |) で構造化

            - 各項目の意図や根拠が分かるよう短い説明文を添える

            - 営業デモで顧客に直接見せられる体裁にする


            (構造化されたデータ項目を内部で扱うのは構いませんが、出力時に Markdown

            に変換してください。)'
        - role: user
          text: '入力テキスト:

            {{#start.query#}}


            計算結果（解析用）:

            {{#code1.output#}}


            上記を参考に、投資委員会向けの正式な評価メモを日本語で作成してください。'
        vision:
          enabled: false
        memory: null
        context:
          enabled: false
      height: 90
      id: llm1
      position:
        x: 980
        y: 282
      type: custom
      width: 244
    - data:
        title: 終了
        type: end
        outputs:
        - value_selector:
          - llm1
          - text
          variable: result
      height: 90
      id: end
      position:
        x: 1280
        y: 282
      type: custom
      width: 244
  hash: null
