Skip to content

gemini #31

@nattachain-cloud

Description

@nattachain-cloud

`import React, { useState, useEffect } from 'react';
import {
Lightbulb, BookOpen, Users, FileText, Target, Database, Loader2,
ArrowRight, Layers, FileCheck, Sparkles, ArrowRightCircle,
ShieldAlert, Landmark, BookMarked, ClipboardList, BookText,
History, Trash2
} from 'lucide-react';
import { initializeApp } from 'firebase/app';
import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth';
import { getFirestore, collection, addDoc, onSnapshot, deleteDoc, doc } from 'firebase/firestore';

const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';

export default function App() {
const [keyword, setKeyword] = useState('');
const [category, setCategory] = useState('การเมือง');
const [researchType, setResearchType] = useState('เชิงปริมาณ');

const [searchResults, setSearchResults] = useState([]);
const [isSearching, setIsSearching] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
const [searchError, setSearchError] = useState('');

const [aiLoading, setAiLoading] = useState(false);
const [aiResult, setAiResult] = useState(null);
const [aiError, setAiError] = useState('');

const [draftLoading, setDraftLoading] = useState(false);
const [fullDraftResult, setFullDraftResult] = useState(null);
const [draftError, setDraftError] = useState('');

const [user, setUser] = useState(null);
const [history, setHistory] = useState([]);

// ตั้งค่าการยืนยันตัวตนแบบไม่ระบุตัวตน (เพื่อแยกข้อมูลของแต่ละเครื่อง)
useEffect(() => {
const initAuth = async () => {
try {
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {
await signInWithCustomToken(auth, __initial_auth_token);
} else {
await signInAnonymously(auth);
}
} catch (error) {
console.error("Auth error:", error);
}
};
initAuth();
const unsubscribe = onAuthStateChanged(auth, setUser);
return () => unsubscribe();
}, []);

// ดึงข้อมูลประวัติการค้นหาจากฐานข้อมูลคลาวด์ส่วนตัวของผู้ใช้
useEffect(() => {
if (!user) return;
const historyRef = collection(db, 'artifacts', appId, 'users', user.uid, 'searchHistory');
const unsubscribe = onSnapshot(historyRef, (snapshot) => {
const historyData = [];
snapshot.forEach((doc) => {
historyData.push({ id: doc.id, ...doc.data() });
});
// เรียงลำดับจากใหม่ไปเก่า และแสดงแค่ 5 รายการล่าสุด
historyData.sort((a, b) => b.createdAt - a.createdAt);
setHistory(historyData.slice(0, 5));
}, (error) => {
console.error("Firestore error:", error);
});
return () => unsubscribe();
}, [user]);

const saveToHistory = async (kw, cat, type) => {
if (!user) return;
try {
const historyRef = collection(db, 'artifacts', appId, 'users', user.uid, 'searchHistory');
// ลบคำค้นหาเดิมออกถ้ามีซ้ำ เพื่อให้ขยับขึ้นมาอยู่บนสุด
const existing = history.find(h => h.keyword.toLowerCase() === kw.toLowerCase());
if (existing) {
await deleteDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'searchHistory', existing.id));
}
// บันทึกคำค้นหาใหม่
await addDoc(historyRef, {
keyword: kw,
category: cat,
researchType: type,
createdAt: Date.now()
});
} catch (error) {
console.error("Error saving history:", error);
}
};

const applyHistoryItem = (item) => {
setKeyword(item.keyword);
setCategory(item.category);
setResearchType(item.researchType);
};

const handleClearHistory = async () => {
if (!user) return;
try {
for (const item of history) {
await deleteDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'searchHistory', item.id));
}
} catch (error) {
console.error("Error clearing history:", error);
}
};

const apiKey = "";
const apiEndpoint = https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${apiKey};

const fetchWithRetry = async (payload, maxRetries = 5) => {
const delays = [1000, 2000, 4000, 8000, 16000];
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(apiEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (response.ok) return await response.json();
if (i < maxRetries - 1) await new Promise(resolve => setTimeout(resolve, delays[i]));
} catch (networkError) {
if (i === maxRetries - 1) throw networkError;
await new Promise(resolve => setTimeout(resolve, delays[i]));
}
}
throw new Error('ขออภัย เซิร์ฟเวอร์ AI หนาแน่นหรือไม่ตอบสนอง โปรดลองใหม่อีกครั้ง');
};

const handleGenerateIdeas = async (e) => {
if (e) e.preventDefault();
if (!keyword.trim()) return;

setIsSearching(true);
setHasSearched(true);
setSearchResults([]);
setSearchError('');
setAiResult(null); 
setFullDraftResult(null); 

const prompt = `ในฐานะนักวิชาการระดับสูง จงคิดค้นไอเดีย "หัวข้อวิจัยที่น่าสนใจ ทันสมัย และมีโอกาสนำไปใช้ประโยชน์ได้จริงเชิงวิชาการ" จำนวน 5 หัวข้อ ที่เจาะลึกเกี่ยวกับประเด็น "${keyword}" ในหมวดหมู่ "${category}" (รูปแบบการวิจัย: ${researchType}) พร้อมอธิบายจุดเด่นสั้นๆ ว่าทำไมหัวข้อนี้น่าทำในมุมมองวิชาการ`;

const payload = {
  contents: [{ parts: [{ text: prompt }] }],
  generationConfig: {
    responseMimeType: "application/json",
    responseSchema: {
      type: "ARRAY",
      items: {
        type: "OBJECT",
        properties: {
          title: { type: "STRING", description: "ชื่อหัวข้อวิจัยที่สละสลวย น่าสนใจ ตามหลักวิชาการ" },
          reason: { type: "STRING", description: "ความสำคัญของปัญหา/จุดเด่นเชิงวิชาการ (1-2 บรรทัด)" }
        },
        required: ["title", "reason"]
      }
    }
  }
};

try {
  const result = await fetchWithRetry(payload);
  const textResponse = result.candidates?.[0]?.content?.parts?.[0]?.text;
  if (textResponse) {
    setSearchResults(JSON.parse(textResponse));
    saveToHistory(keyword, category, researchType);
  } else {
    throw new Error('ไม่พบข้อมูลไอเดีย');
  }
} catch (err) {
  setSearchError(err.message || 'เกิดข้อผิดพลาดในการสร้างไอเดียหัวข้อ');
} finally {
  setIsSearching(false);
}

};

const generateFullDraft = async (overrideKeyword = null) => {
const currentKeyword = (typeof overrideKeyword === 'string') ? overrideKeyword : keyword;

if (!currentKeyword.trim()) {
  setAiError('กรุณาระบุคีย์เวิร์ดหรือเลือกหัวข้อที่สนใจก่อน');
  return;
}

window.scrollTo({ top: 0, behavior: 'smooth' });

setAiLoading(true);
setAiError('');
setAiResult(null);
setFullDraftResult(null); 

const prompt = `ในฐานะนักวิชาการและนักวิจัยมืออาชีพที่มีทักษะการเล่าเรื่อง (Storytelling) จงสังเคราะห์ "โครงร่างงานวิจัยเบื้องต้น" ที่เกี่ยวข้องกับหัวข้อ/ประเด็น: "${currentKeyword}" (หมวดหมู่: ${category}, รูปแบบการวิจัย: ${researchType})

ข้อกำหนดสำคัญ: 
- Academic Tone: ใช้ภาษาที่เป็นทางการ สละสลวย
- Research Design Alignment: เนื้อหาต้องสอดคล้องกับรูปแบบการวิจัย (${researchType})

โดยต้องมีองค์ประกอบดังนี้:
1. ชื่อเรื่องหลัก 
2. ตัวอย่างหัวข้อวิจัยทางเลือก (3-5 หัวข้อ)
3. ความเป็นมาและความสำคัญของปัญหา 
4. วัตถุประสงค์การวิจัย (เป็นข้อๆ)
5. แนวคิดและทฤษฎีที่ใช้ (2-3 ทฤษฎี)
6. กรอบแนวคิดในการวิจัย 
7. ระเบียบวิธีวิจัย (วิธีวิทยา, ประชากร/กลุ่มตัวอย่าง, เครื่องมือที่ใช้)
8. การประเมินความเป็นไปได้`;

const payload = {
  contents: [{ parts: [{ text: prompt }] }],
  generationConfig: {
    responseMimeType: "application/json",
    responseSchema: {
      type: "OBJECT",
      properties: {
        topic: { type: "STRING" },
        suggested_topics: { type: "ARRAY", items: { type: "STRING" } },
        background: { type: "STRING" },
        objectives: { type: "ARRAY", items: { type: "STRING" } },
        theories: { type: "ARRAY", items: { type: "OBJECT", properties: { name: { type: "STRING" }, description: { type: "STRING" } } } },
        conceptual_framework: { type: "OBJECT", properties: { independent_variables: { type: "ARRAY", items: { type: "STRING" } }, dependent_variables: { type: "ARRAY", items: { type: "STRING" } } } },
        methodology: { type: "STRING" },
        target_group: { type: "STRING" },
        instruments: { type: "STRING" },
        feasibility: { type: "STRING" }
      },
      required: ["topic", "suggested_topics", "background", "objectives", "theories", "conceptual_framework", "methodology", "target_group", "instruments", "feasibility"]
    }
  }
};

try {
  const result = await fetchWithRetry(payload);
  const textResponse = result.candidates?.[0]?.content?.parts?.[0]?.text;
  if (textResponse) {
    setAiResult(JSON.parse(textResponse));
  } else {
    throw new Error('ไม่ได้รับข้อมูลเนื้อหาจาก AI');
  }
} catch (err) {
  setAiError(err.message || 'เกิดข้อผิดพลาดในการเชื่อมต่อกับระบบ AI');
} finally {
  setAiLoading(false);
}

};

const handleSelectTopicForDraft = (selectedTitle) => {
setKeyword(selectedTitle);
generateFullDraft(selectedTitle);
};

const generateFullProposal = async () => {
if (!aiResult) return;

setDraftLoading(true);
setDraftError('');
setFullDraftResult(null);

setTimeout(() => {
  window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
}, 100);

const prompt = `ในฐานะนักวิชาการระดับสูง จงนำโครงร่างวิจัยต่อไปนี้มาขยายความและเขียนเป็น "เค้าโครงข้อเสนอโครงการวิจัยฉบับสมบูรณ์ (Research Proposal)" (บทที่ 1-3 และภาคผนวก) ด้วยภาษาทางวิชาการ (Academic Tone) ที่สละสลวยและถูกต้องตามระเบียบวิธีวิจัยรูปแบบ: ${researchType}

ข้อมูลตั้งต้น:
- ชื่อเรื่อง: ${aiResult.topic}
- วัตถุประสงค์: ${aiResult.objectives.join(', ')}
- ทฤษฎีที่ใช้: ${aiResult.theories.map(t => t.name).join(', ')}
- รูปแบบและเครื่องมือ: ${aiResult.methodology} / ${aiResult.instruments}

จงเขียนเนื้อหาแบ่งเป็น 4 ส่วนดังนี้:
1. บทที่ 1 บทนำ: ประกอบด้วย ความเป็นมาและความสำคัญของปัญหา (เกริ่นให้น่าสนใจ), วัตถุประสงค์การวิจัย, ขอบเขตการวิจัย (ด้านเนื้อหา พื้นที่ เวลา), และประโยชน์ที่คาดว่าจะได้รับ
2. บทที่ 2 แนวคิด ทฤษฎี และงานวิจัยที่เกี่ยวข้อง: ขยายความทฤษฎีที่ระบุไว้ให้เห็นภาพ และอธิบายว่าทฤษฎีเหล่านี้เชื่อมโยงสู่กรอบแนวคิดการวิจัยอย่างไร
3. บทที่ 3 ระเบียบวิธีวิจัย: อธิบายให้ชัดเจนถึง รูปแบบการวิจัย (${researchType}), ประชากรและกลุ่มตัวอย่าง (หรือผู้ให้ข้อมูลหลัก), การสร้างเครื่องมือวิจัย, การเก็บรวบรวมข้อมูล, และการวิเคราะห์ข้อมูล
4. ภาคผนวก (เครื่องมือวิจัย): ร่างโครงสร้าง "แบบสอบถาม" (ถ้าเป็นเชิงปริมาณ) หรือ "ร่างแนวคำถามสัมภาษณ์แบบกึ่งโครงสร้าง" (ถ้าเป็นเชิงคุณภาพ) โดยให้มีข้อคำถามที่สอดคล้องกับวัตถุประสงค์ อย่างน้อย 5-8 ข้อ`;

const payload = {
  contents: [{ parts: [{ text: prompt }] }],
  generationConfig: {
    responseMimeType: "application/json",
    responseSchema: {
      type: "OBJECT",
      properties: {
        chapter1: { type: "STRING", description: "เนื้อหาบทที่ 1 บทนำ แบบครบถ้วนสมบูรณ์" },
        chapter2: { type: "STRING", description: "เนื้อหาบทที่ 2 แนวคิด ทฤษฎี และงานวิจัยที่เกี่ยวข้อง" },
        chapter3: { type: "STRING", description: "เนื้อหาบทที่ 3 ระเบียบวิธีวิจัย แบบละเอียด" },
        appendix: { type: "STRING", description: "เนื้อหาภาคผนวก ร่างแบบสอบถาม หรือ แบบสัมภาษณ์" }
      },
      required: ["chapter1", "chapter2", "chapter3", "appendix"]
    }
  }
};

try {
  const result = await fetchWithRetry(payload, 3);
  const textResponse = result.candidates?.[0]?.content?.parts?.[0]?.text;
  if (textResponse) {
    setFullDraftResult(JSON.parse(textResponse));
  } else {
    throw new Error('ไม่ได้รับข้อมูลเอกสารจาก AI');
  }
} catch (err) {
  setDraftError(err.message || 'เกิดข้อผิดพลาดในการสร้างเอกสารบทที่ 1-3');
} finally {
  setDraftLoading(false);
}

};

const indTitle = researchType === 'เชิงคุณภาพ' ? 'ปัจจัย/บริบท (Context/Factors)' : researchType === 'แบบผสมผสาน' ? 'ตัวแปร/ปัจจัย (Variables/Factors)' : 'ตัวแปรอิสระ (Independent Variables)';
const depTitle = researchType === 'เชิงคุณภาพ' ? 'ปรากฏการณ์ที่ศึกษา (Phenomenon)' : researchType === 'แบบผสมผสาน' ? 'ผลลัพธ์/ปรากฏการณ์ (Outcomes/Phenomena)' : 'ตัวแปรตาม (Dependent Variables)';

return (


    <header className="bg-slate-900 text-white p-6 md:p-8 rounded-lg shadow-md border-b-4 border-amber-600 flex flex-col md:flex-row items-center justify-between gap-4">
      <div className="flex items-center gap-4">
        <div className="bg-slate-800 p-3 rounded-md border border-slate-700">
          <Landmark className="w-8 h-8 text-amber-500" />
        </div>
        <div>
          <h1 className="text-2xl md:text-3xl font-serif font-bold tracking-wide">
            Smart Research Portal <span className="text-sm font-sans bg-slate-800 text-amber-500 px-2 py-1 rounded ml-2 border border-slate-700">v3.0</span>
          </h1>
          <p className="text-slate-300 mt-1 text-sm font-medium">ระบบสังเคราะห์และคัดสรรโครงร่างงานวิจัยอัจฉริยะ (Academic Edition)</p>
        </div>
      </div>
      <div className="text-left md:text-right border-t md:border-t-0 border-slate-700 pt-4 md:pt-0 w-full md:w-auto">
        <p className="text-[10px] font-bold text-slate-400 uppercase tracking-widest mb-0.5">Designed By</p>
        <p className="text-sm font-bold text-amber-500">บัณฑิตศึกษา สาขาวิชารัฐศาสตร์</p>
        <p className="text-xs text-slate-300">มหาวิทยาลัยราชภัฏนครสวรรค์</p>
      </div>
    </header>

    <div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-start">
      
      <div className="lg:col-span-4 space-y-6 sticky top-6">
        
        <div className="bg-white p-6 rounded-lg shadow-sm border border-slate-300">
          <div className="flex items-center gap-2 mb-5 text-slate-800">
            <span className="bg-slate-800 text-white font-bold px-3 py-1 rounded-sm text-xs tracking-wider uppercase">Step 1</span>
            <h2 className="text-lg font-serif font-bold flex items-center gap-2">
              <Sparkles className="w-5 h-5 text-amber-600" />
              กำหนดประเด็นที่สนใจ
            </h2>
          </div>
          
          <form onSubmit={handleGenerateIdeas} className="space-y-4">
            <div>
              <label className="block text-sm font-bold text-slate-700 mb-1">หมวดหมู่งานวิจัย</label>
              <select 
                value={category} 
                onChange={(e) => setCategory(e.target.value)}
                className="w-full border-slate-300 rounded-md shadow-sm p-2.5 bg-slate-50 focus:ring-slate-800 focus:border-slate-800 border outline-none transition-all text-sm"
              >
                <option value="การเมือง">การเมือง (Politics)</option>
                <option value="การบริหารภาครัฐ">การบริหารภาครัฐ (Public Administration)</option>
                <option value="การปกครองท้องถิ่น">การปกครองท้องถิ่น (Local Government)</option>
                <option value="การพัฒนาเมือง">การพัฒนาเมือง (Urban Development)</option>
                <option value="รัฐธรรมนูญและสถาบันทางการเมือง">รัฐธรรมนูญและสถาบันทางการเมือง (Constitution & Political Institutions)</option>
                <option value="การพัฒนาเศรษฐกิจและสังคม">การพัฒนาเศรษฐกิจและสังคม (Economic & Social Development)</option>
                <option value="ความเหลื่อมล้ำทางสังคม">ความเหลื่อมล้ำทางสังคม (Social Inequality)</option>
                <option value="การพัฒนาเชิงพื้นที่">การพัฒนาเชิงพื้นที่ (Spatial Development)</option>
              </select>
            </div>
            <div>
              <label className="block text-sm font-bold text-slate-700 mb-1">รูปแบบการวิจัย (Research Design)</label>
              <select 
                value={researchType} 
                onChange={(e) => setResearchType(e.target.value)}
                className="w-full border-slate-300 rounded-md shadow-sm p-2.5 bg-slate-50 focus:ring-slate-800 focus:border-slate-800 border outline-none transition-all text-sm"
              >
                <option value="เชิงปริมาณ">วิจัยเชิงปริมาณ (Quantitative Research)</option>
                <option value="เชิงคุณภาพ">วิจัยเชิงคุณภาพ (Qualitative Research)</option>
                <option value="แบบผสมผสาน">วิจัยแบบผสมผสาน (Mixed Methods)</option>
              </select>
            </div>
            <div>
              <label className="block text-sm font-bold text-slate-700 mb-1">ประเด็นกว้างๆ / คำค้นหา</label>
              <input 
                type="text" 
                value={keyword}
                onChange={(e) => setKeyword(e.target.value)}
                placeholder="เช่น นโยบายสาธารณะ, สมาร์ทซิตี้, ท้องถิ่น..."
                className="w-full border-slate-300 rounded-md shadow-sm p-2.5 bg-slate-50 focus:ring-slate-800 focus:border-slate-800 border outline-none transition-all text-sm"
              />
            </div>
            <button 
              type="submit" 
              disabled={isSearching || !keyword.trim()}
              className="w-full bg-slate-800 hover:bg-slate-700 text-white font-medium py-2.5 rounded-md transition-colors flex items-center justify-center gap-2 disabled:opacity-50 mt-2"
            >
              {isSearching ? <Loader2 className="w-5 h-5 animate-spin" /> : <Lightbulb className="w-5 h-5" />}
              {isSearching ? 'กำลังประมวลผลวิชาการ...' : 'วิเคราะห์ 5 หัวข้อวิจัย'}
            </button>
          </form>

          {/* ส่วนแสดงประวัติการค้นหา */}
          {history.length > 0 && (
            <div className="mt-8 pt-5 border-t border-slate-200 animate-in fade-in">
              <div className="flex items-center justify-between mb-3">
                <h3 className="text-xs font-bold text-slate-500 uppercase tracking-wider flex items-center gap-1.5">
                  <History className="w-4 h-4" /> ประวัติการค้นหาล่าสุด
                </h3>
                <button onClick={handleClearHistory} className="text-slate-400 hover:text-rose-500 transition-colors p-1" title="ลบประวัติ">
                  <Trash2 className="w-4 h-4" />
                </button>
              </div>
              <div className="flex flex-col gap-2">
                {history.map((item) => (
                  <button
                    key={item.id}
                    onClick={() => applyHistoryItem(item)}
                    className="text-left p-3 bg-slate-50 hover:bg-amber-50 hover:border-amber-200 border border-slate-200 rounded-md transition-all group flex flex-col gap-1"
                  >
                    <span className="text-sm font-bold text-slate-700 group-hover:text-amber-800 line-clamp-1">{item.keyword}</span>
                    <span className="text-[10px] text-slate-500 font-medium">{item.category} • {item.researchType}</span>
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>

        {hasSearched && (
          <div className="bg-white p-6 rounded-lg shadow-sm border border-slate-300 animate-in fade-in slide-in-from-top-2">
            <h3 className="text-md font-serif font-bold mb-4 text-slate-800 flex justify-between items-center border-b border-slate-200 pb-2">
              <span>ข้อเสนอแนะหัวข้อวิจัย</span>
            </h3>
            
            {isSearching ? (
              <div className="flex flex-col items-center justify-center py-10 text-slate-500">
                <Loader2 className="w-8 h-8 animate-spin text-slate-800 mb-4" />
                <p className="text-sm font-medium">กำลังทบทวนวรรณกรรม...</p>
              </div>
            ) : searchError ? (
              <div className="bg-red-50 text-red-700 p-4 rounded-md text-sm border border-red-200">{searchError}</div>
            ) : searchResults.length > 0 ? (
              <div className="space-y-4 max-h-[500px] overflow-y-auto pr-2" style={{ scrollbarWidth: 'thin' }}>
                {searchResults.map((item, index) => (
                  <div key={index} className="p-4 border border-slate-200 rounded-md hover:border-slate-400 hover:shadow-sm transition-all bg-slate-50 flex flex-col h-full group">
                    <h4 className="font-bold font-serif text-slate-900 text-sm leading-snug mb-2 group-hover:text-amber-700 transition-colors">{item.title}</h4>
                    <p className="text-xs text-slate-600 leading-relaxed mb-4 flex-grow"><span className="font-bold text-slate-800">นัยสำคัญ: </span>{item.reason}</p>
                    <button 
                      onClick={() => handleSelectTopicForDraft(item.title)}
                      className="mt-auto w-full bg-white border border-slate-300 hover:bg-slate-800 hover:text-white text-slate-700 text-xs font-bold py-2 rounded-md transition-all flex items-center justify-center gap-1.5"
                    >
                      <ArrowRightCircle className="w-4 h-4" /> เลือกหัวข้อนี้ (Step 2)
                    </button>
                  </div>
                ))}
              </div>
            ) : null}
          </div>
        )}
      </div>

      <div className="lg:col-span-8 space-y-6">
        
        <div className="bg-slate-800 p-6 md:p-8 rounded-lg shadow-md text-white border-t-4 border-amber-600 relative overflow-hidden">
          <div className="absolute top-0 right-0 p-8 opacity-5 pointer-events-none">
            <BookOpen className="w-48 h-48" />
          </div>
          
          <div className="relative z-10 flex flex-col md:flex-row md:items-center justify-between gap-6">
            <div className="flex-1">
              <div className="flex items-center gap-2 mb-3 text-amber-500">
                <span className="bg-amber-500/10 text-amber-500 font-bold px-3 py-1 rounded-sm text-xs border border-amber-500/20 uppercase tracking-wider">Step 2</span>
              </div>
              <h2 className="text-2xl font-serif font-bold flex items-center gap-3 mb-2">
                สังเคราะห์โครงร่างงานวิจัยเบื้องต้น
              </h2>
              <p className="text-slate-300 text-sm md:text-base max-w-xl leading-relaxed">
                ระบบจะทำการวางโครงสร้างงานวิจัย (Background, Theories, Conceptual Framework) โดยอัตโนมัติ
              </p>
            </div>
            <button 
              onClick={() => generateFullDraft()}
              disabled={aiLoading || !keyword.trim()}
              className="bg-amber-600 hover:bg-amber-700 text-white font-bold py-3 px-6 rounded-md transition-colors shadow-sm disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 w-full md:w-auto shrink-0 h-fit"
            >
              {aiLoading ? <><Loader2 className="w-5 h-5 animate-spin" /> กำลังสร้างโครงร่าง...</> : <><FileCheck className="w-5 h-5" /> ร่างกรอบแนวคิด</>}
            </button>
          </div>
          {aiError && <p className="text-rose-200 text-sm mt-4 bg-rose-900/50 inline-block px-4 py-2 rounded-md border border-rose-800">{aiError}</p>}
        </div>

        {aiResult && (
          <div className="bg-white rounded-lg shadow-sm border border-slate-300 overflow-hidden animate-in fade-in slide-in-from-bottom-4 duration-500">
            <div className="bg-slate-50 px-6 md:px-8 py-8 border-b border-slate-300">
              <div className="flex items-center gap-2 text-sm font-bold text-slate-500 uppercase tracking-widest mb-4">
                <Layers className="w-4 h-4" />
                โครงร่างข้อเสนอโครงการวิจัย (Framework)
              </div>
              <h1 className="text-2xl md:text-3xl font-serif font-bold text-slate-900 leading-tight">{aiResult.topic}</h1>
            </div>

            <div className="p-6 md:p-8 space-y-8">
              <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
                <div className="space-y-3">
                  <h3 className="text-lg font-serif font-bold text-slate-900 border-b-2 border-slate-800 pb-2">ความเป็นมาของปัญหา</h3>
                  <p className="text-slate-700 text-sm leading-relaxed text-justify whitespace-pre-line">{aiResult.background}</p>
                </div>
                <div className="space-y-3">
                  <h3 className="text-lg font-serif font-bold text-slate-900 border-b-2 border-slate-800 pb-2">วัตถุประสงค์การวิจัย</h3>
                  <ul className="space-y-2">
                    {aiResult.objectives?.map((obj, i) => (
                      <li key={i} className="flex items-start gap-2 text-sm text-slate-700">
                        <span className="w-4 h-4 rounded-full bg-slate-200 text-slate-800 flex items-center justify-center text-[10px] font-bold shrink-0 mt-0.5">{i+1}</span>
                        <span className="leading-relaxed">{obj}</span>
                      </li>
                    ))}
                  </ul>
                </div>
              </div>

              <div className="space-y-4">
                <h3 className="text-lg font-serif font-bold text-slate-900 flex items-center gap-2 border-b-2 border-slate-800 pb-2">
                  <Layers className="w-5 h-5 text-slate-700" />
                  กรอบแนวคิดในการวิจัย (Conceptual Framework)
                </h3>
                <div className="bg-white p-6 rounded-lg border border-slate-200 flex flex-col md:flex-row items-center justify-center gap-6 md:gap-12 bg-slate-50/50">
                  <div className="bg-white rounded-md border border-slate-300 shadow-sm w-full md:w-64 overflow-hidden">
                    <h4 className="text-center font-bold text-slate-800 text-sm bg-slate-100 py-2 border-b border-slate-300">{indTitle}</h4>
                    <ul className="p-4 space-y-2">
                      {(aiResult.conceptual_framework?.independent_variables || []).map((v, i) => (
                        <li key={i} className="text-sm text-slate-700 flex items-start gap-2"><div className="w-1.5 h-1.5 rounded-sm bg-slate-800 mt-1.5 shrink-0"></div><span className="leading-snug">{v}</span></li>
                      ))}
                    </ul>
                  </div>
                  <ArrowRight className="w-8 h-8 text-slate-400 hidden md:block" />
                  <div className="bg-white rounded-md border border-slate-300 shadow-sm w-full md:w-64 overflow-hidden">
                    <h4 className="text-center font-bold text-slate-800 text-sm bg-slate-100 py-2 border-b border-slate-300">{depTitle}</h4>
                    <ul className="p-4 space-y-2">
                      {(aiResult.conceptual_framework?.dependent_variables || []).map((v, i) => (
                        <li key={i} className="text-sm text-slate-700 flex items-start gap-2"><div className="w-1.5 h-1.5 rounded-sm bg-slate-800 mt-1.5 shrink-0"></div><span className="leading-snug">{v}</span></li>
                      ))}
                    </ul>
                  </div>
                </div>
              </div>
            </div>
          </div>
        )}

        {aiResult && (
          <div className="bg-amber-50 p-6 md:p-8 rounded-lg shadow-sm border border-amber-200 relative overflow-hidden mt-6">
            <div className="relative z-10 flex flex-col md:flex-row md:items-center justify-between gap-6">
              <div className="flex-1">
                <div className="flex items-center gap-2 mb-3 text-amber-700">
                  <span className="bg-amber-200 text-amber-900 font-bold px-3 py-1 rounded-sm text-xs uppercase tracking-wider">Step 3</span>
                </div>
                <h2 className="text-2xl font-serif font-bold text-amber-900 flex items-center gap-3 mb-2">
                  เขียนเค้าโครงวิจัยฉบับจริง (บทที่ 1-3)
                </h2>
                <p className="text-amber-800 text-sm md:text-base max-w-xl leading-relaxed">
                  นำกรอบแนวคิดด้านบน มาแตกรายละเอียดเป็น <b>บทที่ 1 บทนำ, บทที่ 2 ทฤษฎี, บทที่ 3 ระเบียบวิธีวิจัย</b> พร้อมร่างแบบสอบถาม/คำถามสัมภาษณ์ใน <b>ภาคผนวก</b>
                </p>
              </div>

              <button 
                onClick={() => generateFullProposal()}
                disabled={draftLoading}
                className="bg-amber-600 hover:bg-amber-700 text-white font-bold py-3 px-6 rounded-md transition-colors shadow-sm disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 w-full md:w-auto shrink-0 h-fit"
              >
                {draftLoading ? <><Loader2 className="w-5 h-5 animate-spin" /> กำลังเขียนบทที่ 1-3...</> : <><BookText className="w-5 h-5" /> สร้างเค้าโครงฉบับจริง (Step 3)</>}
              </button>
            </div>
            {draftError && <p className="text-rose-600 text-sm mt-4 bg-rose-100 inline-block px-4 py-2 rounded-md border border-rose-200">{draftError}</p>}
          </div>
        )}

        {fullDraftResult && (
          <div className="space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500">
            <div className="bg-white rounded-lg shadow-sm border border-slate-300 overflow-hidden">
              <div className="bg-slate-800 text-white px-6 py-4 flex items-center gap-3">
                <BookMarked className="w-5 h-5 text-amber-500" />
                <h3 className="font-serif font-bold text-lg">บทที่ 1: บทนำ</h3>
              </div>
              <div className="p-6 md:p-8">
                <p className="text-slate-700 leading-loose text-justify whitespace-pre-line font-serif text-[15px]">
                  {fullDraftResult.chapter1}
                </p>
              </div>
            </div>

            <div className="bg-white rounded-lg shadow-sm border border-slate-300 overflow-hidden">
              <div className="bg-slate-800 text-white px-6 py-4 flex items-center gap-3">
                <BookMarked className="w-5 h-5 text-amber-500" />
                <h3 className="font-serif font-bold text-lg">บทที่ 2: แนวคิด ทฤษฎี และงานวิจัยที่เกี่ยวข้อง</h3>
              </div>
              <div className="p-6 md:p-8">
                <p className="text-slate-700 leading-loose text-justify whitespace-pre-line font-serif text-[15px]">
                  {fullDraftResult.chapter2}
                </p>
              </div>
            </div>

            <div className="bg-white rounded-lg shadow-sm border border-slate-300 overflow-hidden">
              <div className="bg-slate-800 text-white px-6 py-4 flex items-center gap-3">
                <BookMarked className="w-5 h-5 text-amber-500" />
                <h3 className="font-serif font-bold text-lg">บทที่ 3: ระเบียบวิธีวิจัย</h3>
              </div>
              <div className="p-6 md:p-8">
                <p className="text-slate-700 leading-loose text-justify whitespace-pre-line font-serif text-[15px]">
                  {fullDraftResult.chapter3}
                </p>
              </div>
            </div>

            <div className="bg-white rounded-lg shadow-sm border border-amber-300 overflow-hidden">
              <div className="bg-amber-600 text-white px-6 py-4 flex items-center gap-3">
                <ClipboardList className="w-5 h-5 text-amber-100" />
                <h3 className="font-serif font-bold text-lg">ภาคผนวก: เครื่องมือการวิจัย (ร่างแบบสอบถาม/สัมภาษณ์)</h3>
              </div>
              <div className="p-6 md:p-8 bg-amber-50/30">
                <p className="text-slate-800 leading-loose text-justify whitespace-pre-line font-serif text-[15px]">
                  {fullDraftResult.appendix}
                </p>
              </div>
            </div>
          </div>
        )}
        
      </div>
    </div>
  </div>
</div>

);
}`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions