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: parameter-extractor
      id: code1-to-extractor1
      source: code1
      target: extractor1
    - data:
        sourceType: parameter-extractor
        targetType: llm
      id: extractor1-to-llm2
      source: extractor1
      target: llm2
    - data:
        sourceType: llm
        targetType: end
      id: llm2-to-end
      source: llm2
      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 re\n    raw = inputs.get(\"\
          logs\", \"\")\n    # 抽出ルール: ロット識別子を「Lot:」や「LOT」等の表記から検出\n    lots = re.findall(r'Lot[:\\\
          s]*([A-Za-z0-9\\-]+)', raw)\n    if not lots:\n        lots = re.findall(r'lot[:\\\
          s]*([A-Za-z0-9\\-]+)', raw, flags=re.I)\n    unique_lots = []\n    for l\
          \ in lots:\n        if l not in unique_lots:\n            unique_lots.append(l)\n\
          \    # ログ行からロットに関する行を収集（最大200行まで）\n    related_lines = []\n    for line\
          \ in raw.splitlines():\n        for l in unique_lots:\n            if l\
          \ and l in line:\n                related_lines.append(line.strip())\n \
          \               break\n        if len(related_lines) >= 200:\n         \
          \   break\n    summary = \"\"\n    if unique_lots:\n        summary = \"\
          Detected lots: \" + \", \".join(unique_lots)\n    else:\n        summary\
          \ = \"No lot identifiers detected in the provided logs.\"\n    summary =\
          \ summary + \"\\n\\nRelated log lines (up to 200):\\n\" + \"\\\\n\".join(related_lines)\n\
          \    # 出力は文字列にして上位ノード（抽出・LLM）で参照可能にする\n    return dict(parsed_summary=summary)\n"
        variables:
        - value_selector:
          - start
          - query
          variable: logs
        outputs:
          parsed_summary:
            type: string
            children: null
      height: 90
      id: code1
      position:
        x: 380
        y: 282
      type: custom
      width: 244
    - data:
        title: 情報抽出（ロット・期間等）
        type: parameter-extractor
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
        query:
        - code1
        - parsed_summary
        parameters:
        - name: affected_lots
          type: string
          description: 影響が疑われるロットID（カンマ区切り）
          required: true
        - name: recall_start_date
          type: string
          description: 回収対象の開始日（可能ならYYYY-MM-DD）
          required: false
        - name: recall_end_date
          type: string
          description: 回収対象の終了日（可能ならYYYY-MM-DD）
          required: false
        - name: suspected_cause
          type: string
          description: ログから推定される原因（短文）
          required: false
        - name: priority_level
          type: string
          description: 推奨される優先度（高/中/低）
          required: false
        reasoning_mode: prompt
        instruction: 上記の前処理結果から、可能な限り影響ロット、回収対象期間、疑われる原因、優先度を抽出して返してください。複数ある場合はカンマ区切りで記載してください。
      height: 90
      id: extractor1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: 最終分析・回収提案（LLM）
        type: llm
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
          completion_params:
            temperature: 0.3
        prompt_template:
        - role: system
          text: 'あなたは食品製造におけるトレーサビリティとリコール対応の専門アシスタントです。

            出力は日本語で、以下を必ず含めてください:

            1) トレーサビリティチェーンの要約（生産→包装→出荷などの主要ステップを列挙）

            2) 抽出された影響ロットとその根拠（ログのどの行に基づくか簡潔に示す）

            3) 回収対象範囲の提案（ロット、期間、関連出荷先の範囲）

            4) 優先度判定と短い根拠

            5) 推奨される次のアクション（検査・隔離・通知など）

            箇条書きで整理し、最後に「要約」セクションを1段落で入れてください。

            '
        - role: user
          text: 'ユーザー入力（問題の説明）:

            {{#start.query#}}


            ログの前処理結果:

            {{#code1.parsed_summary#}}


            抽出結果:

            影響ロット: {{#extractor1.affected_lots#}}

            回収開始日: {{#extractor1.recall_start_date#}}

            回収終了日: {{#extractor1.recall_end_date#}}

            疑われる原因: {{#extractor1.suspected_cause#}}

            優先度: {{#extractor1.priority_level#}}


            上記を踏まえて、回収対象範囲とトレーサビリティチェーンのサマリを作成してください。必要ならば不足情報を特定し、確認すべき事項を箇条書きで示してください。

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