営業時間:10:00~21:30 ご予約・お問い合わせ

カイロブラクティック健寿

ご感想アンケート

import React, { useState } from ‘react’; import { Sparkles, Copy, RefreshCw, Check, ChevronRight, MapPin, User, Stethoscope, Smile, ThumbsUp, ClipboardList } from ‘lucide-react’; // ========================================== // ★設定エリア:ここにAPIキーを入力してください // ========================================== // 患者様のスマホで動作させるため、ここに直接キーを記述します。 // ※Web公開する際は、Google Cloud Consoleでこのキーに対して「リファラー制限(公開URLのみ許可)」を設定することを強く推奨します。 const GEMINI_API_KEY = “AIzaSyCn6feb9Uw2E2Gkhnt37nB9uEdBv4wpjiw”; // 例: “AIzaSy…” const CLINIC_INFO = { name: “カイロプラクティック健寿 岡山大元院”, reviewUrl: “https://g.page/r/CZEKJ4dn49BcEBM/review”, // 口コミ投稿用リンク keywords: [“岡山”, “整体”, “自律神経”, “首こり”, “肩こり”, “改善”, “おすすめ”, “ストレートネック”], }; // ========================================== // 質問データの定義 const QUESTIONS = [ { id: ‘symptoms’, title: ‘Q1. 気になる症状・お悩みは?’, subtitle: ‘当てはまるものを全て選んでください’, icon: , type: ‘multi’, options: [ “首こり”, “肩こり”, “頭痛・頭重感”, “眠れない・不眠”, “疲れが取れない”, “めまい・ふらつき”, “やる気が出ない”, “背中・腰の痛み”, “自律神経の乱れ”, “病院で異常なし”, “姿勢が悪い” ] }, { id: ‘changes’, title: ‘Q2. 施術後の変化・感想は?’, subtitle: ‘施術を受けてどう感じましたか?’, icon: , type: ‘multi’, options: [ “体が軽くなった”, “痛みが和らいだ”, “頭がスッキリした”, “視界が明るくなった”, “リラックスできた”, “ポカポカ温まった”, “動きやすくなった”, “姿勢が良くなった”, “呼吸が深くなった” ] }, { id: ‘goodPoints’, title: ‘Q3. 当院の良かった点は?’, subtitle: ‘印象に残ったことがあれば教えてください’, icon: , type: ‘multi’, options: [ “説明が分かりやすい”, “話をよく聞いてくれる”, “負担が少なかった”, “先生が話しやすい”, “院内がきれい”, “対応が丁寧”, “原因が分かった”, “予約が取りやすい” ] }, { id: ‘demographics’, title: ‘Q4. 年代・性別を教えてください’, subtitle: ‘集計のために使用します’, icon: , type: ‘demographics’, ages: [“10代”, “20代”, “30代”, “40代”, “50代”, “60代以上”], genders: [“女性”, “男性”, “無回答”] } ]; export default function ReviewGeneratorAppMobile() { const [step, setStep] = useState(0); // 0:Welcome, 1-4:Questions, 5:Loading, 6:Result // 回答データを管理するState const [answers, setAnswers] = useState({ symptoms: [], changes: [], goodPoints: [], age: ”, gender: ”, freeText: ” }); const [generatedReviews, setGeneratedReviews] = useState([]); const [error, setError] = useState(”); const [copiedIndex, setCopiedIndex] = useState(null); // 複数選択の切り替えロジック const toggleOption = (qId, option) => { setAnswers(prev => { const currentList = prev[qId] || []; if (currentList.includes(option)) { return { …prev, [qId]: currentList.filter(item => item !== option) }; } else { return { …prev, [qId]: […currentList, option] }; } }); }; // 年代・性別の選択ロジック const setDemographic = (type, value) => { setAnswers(prev => ({ …prev, [type]: value })); }; // コピー処理 const handleCopy = (text, index) => { const textArea = document.createElement(“textarea”); textArea.value = text; textArea.style.position = “fixed”; textArea.style.left = “-9999px”; textArea.style.top = “0”; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { const successful = document.execCommand(‘copy’); document.body.removeChild(textArea); if (successful) { setCopiedIndex(index); setTimeout(() => setCopiedIndex(null), 2000); return; } } catch (err) { document.body.removeChild(textArea); } if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text) .then(() => { setCopiedIndex(index); setTimeout(() => setCopiedIndex(null), 2000); }) .catch(err => { console.error(‘Copy failed’, err); alert(‘コピーに失敗しました。手動でコピーしてください。’); }); } else { alert(‘お使いの環境では自動コピーがサポートされていません。’); } }; // プロンプト作成関数 const createPrompt = () => { const demo = `${answers.age} ${answers.gender}`.trim() || “未回答”; const symptoms = answers.symptoms.join(‘、’); const changes = answers.changes.join(‘、’); const goodPoints = answers.goodPoints.join(‘、’); return ` # 役割 あなたは「${CLINIC_INFO.name}」に通う患者です。 これからGoogleマップに投稿するための口コミを作成します。 # 患者データ – 年代・性別: ${demo} – 悩み: ${symptoms} – 変化: ${changes} – 良かった点: ${goodPoints} # 必須条件 1. 文字数は300〜450文字程度。 2. MEOキーワード[${CLINIC_INFO.keywords.join(‘, ‘)}]を文脈の中で自然に使用すること。 3. 文体は自然な日本語とし、${demo}という属性はあくまで参考程度にとどめること(過剰な役割演技や、不自然な若者言葉・絵文字の多用は避ける)。 4. 箇条書きではなく、自然な体験談として書くこと。 5. **重要: 適度に改行を入れて、スマホで読みやすい。ということを意識すること。** 6. 「心からおすすめできる」など、サクラに見えるような過剰な表現はしないこと # 成果物 以下の3パターンの口コミ案を作成してください。冒頭の挨拶は不要です。本文のみを出力してください。 フォーマットはJSON形式で、keysは “patternA”, “patternB”, “patternC” としてください。 {“patternA”: “…”, “patternB”: “…”, “patternC”: “…”} `; }; // Gemini API呼び出し const generateReview = async () => { setStep(5); // Loading画面へ // APIキーがない場合はデモモード if (!GEMINI_API_KEY) { setTimeout(() => { setGeneratedReviews([ { title: “パターンA”, content: “(デモモード:APIキー未設定)\n岡山で自律神経専門の整体を探して、健寿さんに伺いました。\n\nずっと首こりと頭痛に悩んでいましたが、施術を受けて本当に体が軽くなりました!ボキボキしない優しい施術で、先生の説明もとても分かりやすかったです。\n\n院内も静かでリラックスできました。同じように悩んでいる方におすすめです。” }, { title: “パターンB”, content: “(デモモード)\n仕事の疲れが取れず、眠れない日が続いていたのが嘘のようです。\n\n施術が終わった瞬間、視界がパッと明るくなり、重かった背中がスッキリしました。先生がじっくり話を聞いてくれたので安心感も抜群です。\n\n岡山の整体ならここをおすすめします!” }, { title: “パターンC”, content: “(デモモード)\n丁寧な対応ありがとうございました。\n\n首の痛みが和らぎ、久しぶりにぐっすり眠れそうです。自律神経のケアの大切さがよく分かりました。\n\nまた通わせていただきます。” } ]); setStep(6); }, 1500); return; } try { const prompt = createPrompt(); const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${GEMINI_API_KEY}`, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }], generationConfig: { responseMimeType: “application/json” } }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); const text = data.candidates[0].content.parts[0].text; const json = JSON.parse(text); setGeneratedReviews([ { title: “パターンA”, content: json.patternA || text }, { title: “パターンB”, content: json.patternB || text }, { title: “パターンC”, content: json.patternC || text } ]); setStep(6); } catch (e) { setError(“エラーが発生しました: ” + e.message); setStep(6); } }; // — UIコンポーネント — // 1. ウェルカム画面 if (step === 0) { return (

{CLINIC_INFO.name}

施術後のアンケート

本日はご来院ありがとうございます。
より良い施術を提供するため、
簡単なアンケートにご協力をお願いいたします。
(所要時間:約1分)

); } // 2. 質問画面 (Step 1-4) if (step >= 1 && step <= 4) { const qIndex = step - 1; const question = QUESTIONS[qIndex]; let canProceed = false; if (question.type === 'demographics') { canProceed = answers.age !== '' && answers.gender !== ''; } else { canProceed = (answers[question.id] || []).length > 0; } return (
{question.icon} STEP {step}/4

{question.title}

{question.subtitle}

{question.type === ‘demographics’ ? (

年代

{question.ages.map(age => ( ))}

性別

{question.genders.map(gender => ( ))}
) : (
{question.options.map((option) => { const isSelected = (answers[question.id] || []).includes(option); return ( ); })}
)}
{step > 1 && ( )}
); } // 3. ローディング画面 if (step === 5) { return (

回答を送信しています…

ご協力ありがとうございます。
結果をまとめています。

); } // 4. 結果画面 if (step === 6) { return (

ご協力ありがとうございました

もしよろしければ、以下の文章をコピーして
投稿いただけると大変励みになります。
(横にスワイプして選べます)

{error && (
{error}
)}
{generatedReviews.map((review, index) => (
{review.title}
{review.content}
))}
Googleマップで投稿して応援する
); } }