app:
  description: 食品の発注優先度判定サマリ。在庫・安全在庫・出荷実績を照合して、発注優先度とその理由、推奨発注量の一覧を作成します。
  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: code
      id: start-to-code1
      source: start
      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: 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    inputs[\"query\"] should\
          \ be a JSON array (as string) of items:\n    [\n      {\"product_id\": \"\
          A123\", \"stock\": 100, \"safety_stock\": 50, \"avg_daily_ship\": 10},\n\
          \      ...\n    ]\n    The function returns a JSON string in outputs[\"\
          output\"] with computed fields:\n    product_id, stock, safety_stock, avg_daily_ship,\
          \ days_cover, priority (高/中/低), reason\n    \"\"\"\n    import json\n  \
          \  raw = inputs.get(\"query\", \"\")\n    try:\n        parsed = json.loads(raw)\n\
          \    except Exception:\n        msg = \"ERROR: 入力はJSON配列の文字列で、各アイテムに product_id,\
          \ stock, safety_stock, avg_daily_ship を含めてください。\"\n        return dict(output=msg)\n\
          \    items = parsed if isinstance(parsed, list) else []\n    results = []\n\
          \    for it in items:\n        # 安全に値を取り出す（数値変換）\n        pid = it.get(\"\
          product_id\", \"\")\n        try:\n            stock = float(it.get(\"stock\"\
          , 0))\n        except Exception:\n            stock = 0.0\n        try:\n\
          \            safety = float(it.get(\"safety_stock\", 0))\n        except\
          \ Exception:\n            safety = 0.0\n        try:\n            avg_ship\
          \ = float(it.get(\"avg_daily_ship\", 0))\n        except Exception:\n  \
          \          avg_ship = 0.0\n        if avg_ship > 0:\n            days_cover\
          \ = stock / avg_ship\n        else:\n            days_cover = 9999.0\n \
          \       # 優先度判定ロジック\n        if stock < safety or days_cover < 7:\n    \
          \        priority = \"高\"\n            if stock < safety:\n            \
          \    reason = \"在庫が安全在庫を下回っている\"\n            else:\n                reason\
          \ = \"出荷実績から推定した在庫保有日数が短い\"\n        elif days_cover < 14:\n           \
          \ priority = \"中\"\n            reason = \"出荷実績から推定した在庫保有日数が中程度\"\n    \
          \    else:\n            priority = \"低\"\n            reason = \"十分な在庫がある\"\
          \n        # 推奨発注量（単純計算例: 目標在庫 = safety_stock + avg_daily_ship * リードタイム(7日)）\n\
          \        lead_days = 7.0\n        recommended_qty = max(0.0, (safety + avg_ship\
          \ * lead_days) - stock)\n        # 出力用に辞書を作成\n        rec = dict(\n    \
          \        product_id=pid,\n            stock=stock,\n            safety_stock=safety,\n\
          \            avg_daily_ship=avg_ship,\n            days_cover=round(days_cover,\
          \ 2),\n            priority=priority,\n            reason=reason,\n    \
          \        recommended_order_quantity=round(recommended_qty, 2)\n        )\n\
          \        results.append(rec)\n    return dict(output=json.dumps(results,\
          \ ensure_ascii=False))\n"
        variables:
        - value_selector:
          - start
          - query
          variable: query
        outputs:
          output:
            type: string
            children: null
      height: 90
      id: code1
      position:
        x: 380
        y: 282
      type: custom
      width: 244
    - data:
        title: 発注優先度判定・サマリ作成
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.5
        prompt_template:
        - role: system
          text: 'あなたは食品の調達担当者向けの発注優先度アナリストです。与えられた在庫照合結果をもとに、各製品について「発注優先度（高/中/低）」「理由」「推奨発注量（数量）」「信頼度（0-100）」を分かりやすく一覧化してください。

            出力要件（必ず守ること）:

            - 最終出力は日本語のMarkdownで返すこと。

            - 製品ごとに表形式（| ヘッダ | ... |）で、列は少なくとも: 製品ID, 優先度, 理由, 推奨発注量, 信頼度 を含めること。

            - 優先度の根拠を短く1-2文で付記すること。

            - 追加の生データやJSONは付け加えないでください。Markdownのみを返してください。

            '
        - role: user
          text: '以下は在庫照合ノードの出力（JSON配列）です。これを参照して集計・説明してください。

            在庫照合結果:

            {{#code1.output#}}


            （参考: 元の入力クエリ）

            {{#start.query#}}


            出力例（参考）:

            - Markdown の表で各行に製品を表示

            - 各製品の下に「根拠: 」で短い説明を付す

            - 信頼度は0-100で妥当性を推定してください

            以上の形式で、優先度が高い順に上から並べてください。

            '
        vision:
          enabled: false
        memory: null
        context:
          enabled: false
      height: 90
      id: llm1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: 終了
        type: end
        outputs:
        - value_selector:
          - llm1
          - text
          variable: result
      height: 90
      id: end
      position:
        x: 980
        y: 282
      type: custom
      width: 244
  hash: null
