import gradio as gr import pandas as pd import numpy as np import os from openai import OpenAI # --- OpenAI設定 --- api_key = os.getenv("OPENAI_API_KEY") def analyze_cd_logic(m_file, p_file, target_brand): if not api_key: return "❌ OpenAI APIキーが設定されていません。Settings > Secretsを確認してください。" if m_file is None or p_file is None or not target_brand: return "⚠️ 原紙マスタ、製品マップの両方をアップロードし、銘柄名を入力してください。" client = OpenAI(api_key=api_key) try: # データ読み込み m_df = pd.read_csv(m_file.name) if '1' in m_df.columns: m_df.columns = m_df.iloc[0] m_df = m_df[1:].reset_index(drop=True) p_df = pd.read_csv(p_file.name) if '基礎情報' in p_df.columns: p_df.columns = p_df.iloc[0] p_df = p_df[1:].reset_index(drop=True) # 1. 銘柄特定ロジック mask = (m_df['親品番'].astype(str) == target_brand) | \ (m_df['銘柄名'].astype(str) == target_brand) | \ (m_df.iloc[:, 2].astype(str) == target_brand) brand_data = m_df[mask] if brand_data.empty: return f"❌ 銘柄「{target_brand}」は見つかりませんでした。" spec = brand_data.iloc[0] findings = [] # --- ロジック抽出 --- # A. 共用銘柄化(単価差) all_same_parent = m_df[m_df['親品番'] == spec['親品番']].copy() all_same_parent['price'] = pd.to_numeric(all_same_parent['仕入単価(新)'], errors='coerce') if all_same_parent['製紙会社'].nunique() > 1: findings.append(f"【共用銘柄化】同一品番内で単価乖離あり(最大差:{all_same_parent['price'].max() - all_same_parent['price'].min()}円)。安値メーカーへの集約。") # B. 環境対応(1Gナレッジ) if str(spec.get('古紙使用フラグ')) == '1': findings.append("【環境対応見直し】古紙配合品からFSC認証紙へのスペック変更。1G成功事例(▲18M)に基づくコストダウン。") # C. 一般品化 if '1' in [str(spec.get('特抄フラグ')), str(spec.get('特寸フラグ'))]: findings.append("【価値の再定義】特抄・特寸仕様を廃止し、汎用JIS規格品へ切り替え。競争環境の再構築。") # D. 坪量適正化 gram = pd.to_numeric(spec['坪量 g/㎡'], errors='coerce') if not np.isnan(gram) and gram > 70: findings.append(f"【仕様変更】現行{gram}g/㎡。製品要件を再定義し薄物化による面積単価低減。") if not findings: return "💡 明確な自動判定ロジックに該当する施策が見つかりませんでした。個別交渉を検討してください。" # OpenAIによる詳細化 prompt = f""" あなたは調達戦略スペシャリストです。以下の分析結果を、実務的な「CD施策シート」に変換してください。 交渉メール、挨拶、反論対策は一切不要です。論理性と具体的アクションのみを出力してください。 【対象銘柄】: {target_brand} ({spec['製紙会社']} / {spec['仕入単価(新)']}円) 【抽出された事実】: {"/".join(findings)} 【出力項目】 各項目について以下を記載: 1. 切り口 2. 具体的な方法 3. 現状の課題(データ根拠) 4. 提案内容と期待効果(具体的アクション) """ response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "system", "content": "論理的な調達分析官として振る舞ってください。"}, {"role": "user", "content": prompt}], temperature=0.3 ) return response.choices[0].message.content except Exception as e: return f"解析エラー: {str(e)}" # --- Gradio UI --- with gr.Blocks(title="CDG AI Strategist") as demo: gr.Markdown("# 🛡️ CDG AI Strategist - 資材1G論理分析") gr.Markdown("原紙マスタと製品マップから、利益貢献の切り口に基づいた具体的CD案を生成します。") with gr.Row(): with gr.Column(): m_input = gr.File(label="1. 原紙マスタ(CSV)をアップロード") p_input = gr.File(label="2. 製品マップ(CSV)をアップロード") brand_input = gr.Textbox(label="3. 分析対象の銘柄名を入力", placeholder="例: Jウメ70AC") btn = gr.Button("分析実行", variant="primary") with gr.Column(): output = gr.Markdown(label="CD施策詳細レポート") btn.click(fn=analyze_cd_logic, inputs=[m_input, p_input, brand_input], outputs=output) # HuggingFace用の起動設定 if __name__ == "__main__": demo.launch()