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    import csv\n    import io\n    text\
          \ = inputs.get(\"csv\", \"\")\n    reader = csv.reader(io.StringIO(text))\n\
          \    # 期待される列順: 顧客ID, 前月使用量, 当月使用量, 前年同月使用量, 使用形態\n    lines = []\n    header\
          \ = next(reader, None)\n    for row in reader:\n        if not row:\n  \
          \          continue\n        # 安全に列を取得（足りない場合は空文字）\n        cust = row[0].strip()\
          \ if len(row) > 0 else \"\"\n        try:\n            prev = float(row[1])\
          \ if len(row) > 1 and row[1].strip() != \"\" else 0.0\n        except:\n\
          \            prev = 0.0\n        try:\n            cur = float(row[2]) if\
          \ len(row) > 2 and row[2].strip() != \"\" else 0.0\n        except:\n  \
          \          cur = 0.0\n        try:\n            last = float(row[3]) if\
          \ len(row) > 3 and row[3].strip() != \"\" else 0.0\n        except:\n  \
          \          last = 0.0\n        usage = row[4].strip() if len(row) > 4 else\
          \ \"\"\n        prev_ratio = None\n        year_ratio = None\n        flag\
          \ = \"正常\"\n        if prev > 0:\n            prev_ratio = cur / prev *\
          \ 100.0\n            if prev_ratio > 150.0 or prev_ratio < 50.0:\n     \
          \           flag = \"異常\"\n        else:\n            # 前月が0の場合は要確認扱い（メーター交換等の可能性）\n\
          \            if cur > 0:\n                flag = \"要確認\"\n        if last\
          \ > 0:\n            year_ratio = cur / last * 100.0\n        # 年較比に基づくラベル\n\
          \        label = \"\"\n        if year_ratio is not None:\n            if\
          \ year_ratio > 200.0:\n                label = \"要漏水調査\"\n            elif\
          \ year_ratio < 50.0:\n                label = \"不在・節水・メータ故障の可能性\"\n    \
          \    prev_str = \"-\" if prev_ratio is None else str(round(prev_ratio, 1))\
          \ + \"%\"\n        year_str = \"-\" if year_ratio is None else str(round(year_ratio,\
          \ 1)) + \"%\"\n        line = \"顧客ID: \" + cust + \", 前月比: \" + prev_str\
          \ + \", 年較比: \" + year_str + \", フラグ: \" + flag + \", ラベル: \" + label +\
          \ \", 使用形態: \" + usage\n        lines.append(line)\n    output = \"\\n\"\
          .join(lines)\n    return dict(output=output)\n"
        variables:
        - value_selector:
          - start
          - query
          variable: csv
        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.6
        prompt_template:
        - role: system
          text: 'あなたは水道メーター検針データの分析アシスタントです。提供された異常顧客リストをもとに、各顧客について推定原因（漏水／長期不在／メータ故障／使用形態変化）と推奨対応（訪問調査／電話確認／メータ点検）をまとめた業務報告書を作成してください。出力は日本語で行い、各顧客ごとの要点（顧客ID、前月比、年較比、フラグ、推定原因、推奨対応、使用形態）を表形式で示し、最後に全体の要約と優先順位の高い対応案を記載してください。


            ---


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

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

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

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

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

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

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


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

            に変換してください。)'
        - role: user
          text: '異常顧客リスト:

            {{#code1.output#}}'
        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
