const logEl = document.getElementById("log"); function log(msg){ logEl.textContent += msg + "\n"; } async function postJSON(url, body){ const res = await fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(body) }); let data = null; const ct = (res.headers.get("content-type") || "").toLowerCase(); if (ct.includes("application/json")) { try { data = await res.json(); } catch(e){ data = {ok:false, error:`Invalid JSON: ${e.message}`}; } } else { const text = await res.text(); data = {ok:false, error:`HTTP ${res.status} ${res.statusText}: ${text.slice(0,500)}`}; } return { status: res.status, data }; } async function postForm(url, formData){ const res = await fetch(url, { method: "POST", body: formData }); let data = null; const ct = (res.headers.get("content-type") || "").toLowerCase(); if (ct.includes("application/json")) { try { data = await res.json(); } catch(e){ data = {ok:false, error:`Invalid JSON: ${e.message}`}; } } else { const text = await res.text(); data = {ok:false, error:`HTTP ${res.status} ${res.statusText}: ${text.slice(0,500)}`}; } return { status: res.status, data }; } document.getElementById("btnIngestEdinet").onclick = async () => { const edinetCode = document.getElementById("edinetCode").value.trim(); const edinetDate = document.getElementById("edinetDate").value.trim(); const out = document.getElementById("ingestEdinetResult"); out.textContent = "実行中…"; const {data} = await postJSON("/ingest/edinet", {edinet_code: edinetCode, date: edinetDate}); if(data.ok){ out.textContent = `投入チャンク数: ${data.ingested_chunks}`; } else { out.textContent = "エラー: " + (data.error || "unknown"); } log("[EDINET] " + JSON.stringify(data)); }; document.getElementById("btnIngestUpload").onclick = async () => { const files = document.getElementById("pdfFiles").files; const out = document.getElementById("ingestUploadResult"); if(!files || files.length === 0){ out.textContent = "PDFを選択してください"; return; } out.textContent = "アップロード中…"; try{ const fd = new FormData(); for(const f of files){ fd.append("files", f, f.name); } const {data} = await postForm("/ingest/upload", fd); if(data.ok){ out.textContent = `保存:${data.saved?.length||0} / チャンク:${data.ingested_chunks}`; } else { out.textContent = "エラー: " + (data.error || "unknown"); } log("[UPLOAD] " + JSON.stringify(data)); }catch(e){ out.textContent = "エラー: " + e.message; log("[UPLOAD][ERR] " + e.message); } }; document.getElementById("btnGenerate").onclick = async () => { const q = document.getElementById("query").value.trim(); const st = document.getElementById("generateStatus"); const dl = document.getElementById("downloadLinks"); st.textContent = "生成中…(初回はモデル呼出で時間がかかる場合があります)"; dl.innerHTML = ""; const {data} = await postJSON("/generate/all", {query: q}); if(data.ok){ st.textContent = "生成完了"; const a1 = document.createElement("a"); a1.href = data.pptx; a1.textContent = "PPTXをダウンロード"; const a2 = document.createElement("a"); a2.href = data.qa_csv; a2.textContent = "Q&A CSVをダウンロード"; dl.appendChild(a1); dl.appendChild(document.createTextNode(" / ")); dl.appendChild(a2); }else{ st.textContent = "エラー: " + (data.error || "unknown"); } log("[GENERATE] " + JSON.stringify(data)); };