async function getModelList() { const url = 'https://generativelanguage.googleapis.com/v1beta/models?key=' + document.getElementById('apiKey').value; const response = await fetch(url); const data = await response.json(); return data.models .filter(x => x.supportedGenerationMethods.includes("generateContent")) .filter(x => { const versionMatch = x.name.match(/gemini-(\d+\.\d+)/); return versionMatch && parseFloat(versionMatch[1]) >= 1.5; }); } function generatePrompt() { if (!document.getElementById('apiKey').value) { alert("APIキーを入力してください"); return; } let query = document.getElementById('query').value; let textFormat = 'str'; if (document.getElementById('splitStringsSwitch').checked) { query = Array.from(document.getElementById('query').value).join(":::"); //textFormat = 'array, # テキストは1character(not word)ずつ格納した配列にして返すこと。 Example: ["I", "t", " ", "i", "s", " ", "a", " ", "p", "e", "n", "."], ["こ", "れ", "は", " ", "ペ", "ン", "で", "す", "。"], '; } let anotherLanguage = ""; if (!["en", "ja"].includes(i18next.language)) { anotherLanguage = `, { "language": "${i18next.language}", "text": ${textFormat}, "title": str }`; } const selectedEndpoint = document.getElementById('endpointSelect').value; const url = `https://generativelanguage.googleapis.com/v1beta/${selectedEndpoint}:generateContent?key=` + document.getElementById('apiKey').value; const text = `「 ${query} 」をテーマに画像生成AIに送るプロンプトを考えてください。 背景や小物のディテイール、構図、視覚効果など視覚的な情報のみに言及すること。 その上で長文を日本語と英語で返信してください。 返答は以下のフォーマットのjson形式でのみ行う。json以外の内容をレスポンスに含めないこと。 \`\`\`json { "results": [ { "language": "en", "text": ${textFormat} # ${document.getElementById('characterCount').value}文字程度, "title": str }, { "language": "danbooru", "tags": [str], }, { "language": "ja", "text": ${textFormat}, "title": str }${anotherLanguage} ] } \`\`\` `; const payload = { contents: [ { parts: [ { text: text } ] } ], generation_config: { max_output_tokens: 4095, temperature: 1, top_p: 1, top_k: 32 }, safetySettings: [ { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE" } ] }; console.debug(text); // モーダルを表示 const loadingModal = new bootstrap.Modal(document.getElementById('loadingModal')); loadingModal.show(); // ローディングアイコンを表示 document.getElementById('loading').classList.remove('d-none'); // generatePromptボタンを無効化 document.getElementById('generatePromptButton').disabled = true; document.getElementById('generatePromptButton').classList.remove('btn-primary'); document.getElementById('generatePromptButton').classList.remove('btn-danger'); document.getElementById('generatePromptButton').classList.add('btn-secondary'); fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }) .then(response => response.json()) .then(data => { console.debug(data.candidates[0].content); // レスポンスからテキストを抽出 const responseText = data.candidates[0].content.parts[0].text console.debug(responseText); let jsonString = responseText.replace(/```json|```/g, '').trim(); jsonString = jsonString.replace(/\n/g, ''); console.debug(jsonString); // JSONをパース const parsedData = JSON5.parse(jsonString); // 結果を表示 console.debug(parsedData); let promptEn = parsedData.results.find(x => x.language === 'en').text; let promptMyLanguage = parsedData.results.find(x => x.language === i18next.language).text; [promptEn, promptMyLanguage] = [promptEn, promptMyLanguage].map(x => { return Array.isArray(x) ? x.join("") : x; }); promptMyLanguage = promptMyLanguage.replace(/\。 ?/g, '。\n\n'); document.getElementById('promptMyLanguage').value = promptMyLanguage; promptEn = promptEn.replace(/\. ?/g, '.\n\n'); promptEn = promptEn.replace(/^ */g, ''); promptEn = applyReplacements(promptEn); document.getElementById('promptEn').value = promptEn; let danbooruTags = parsedData.results.find(x => x.language === 'danbooru'); if (danbooruTags.tags) { danbooruTags = danbooruTags.tags.map(x => applyReplacements(x.replace("_", " "))); document.getElementById('danbooruTags').value = danbooruTags.join(", "); } if (danbooruTags.text) { danbooruTags = danbooruTags.text.map(x => applyReplacements(x.replace("_", " "))); document.getElementById('danbooruTags').value = danbooruTags.join(", "); } const title = parsedData.results.find(x => x.language === i18next.language).title; // ローディングアイコンを非表示 document.getElementById('loading').classList.add('d-none'); document.getElementById('generatePromptButton').disabled = false; document.getElementById('generatePromptButton').classList.remove('btn-secondary'); document.getElementById('generatePromptButton').classList.add('btn-primary'); document.getElementById('query').value = query; saveToUserStorage(true); saveToHistory(title); // 履歴に保存 }) .catch(error => { console.error(error); // エラー時の処理 document.getElementById('generatePromptButton').classList.remove('btn-secondary'); document.getElementById('generatePromptButton').classList.add('btn-danger'); }) .finally(() => { document.getElementById('query').value = query; // ローディングアイコンを非表示 document.getElementById('loading').classList.add('d-none'); document.getElementById('generatePromptButton').disabled = false; document.getElementById('generatePromptButton').classList.remove('btn-secondary'); if (!document.getElementById('generatePromptButton').classList.contains('btn-danger')) { document.getElementById('generatePromptButton').classList.add('btn-primary'); } // モーダルを非表示 setTimeout(() => { loadingModal.hide(); }, 500); }); }; function applyReplacements(text) { const replacements = getReplacements(); for (const [search, replace] of replacements) { text = text.replace(new RegExp(search, 'g'), replace); } return text; } function getReplacements() { const replacementList = document.getElementById('replacementList'); const replacements = []; for (const set of replacementList.children) { const search = set.querySelector('.replacement-search').value; const replace = set.querySelector('.replacement-replace').value; if (search && replace) { replacements.push([search, replace]); } } return replacements; } // 置換セットの追加と削除の処理 document.getElementById('addReplacementButton').addEventListener('click', addReplacementSet); function addReplacementSet() { const replacementList = document.getElementById('replacementList'); const newSet = document.createElement('div'); newSet.className = 'replacement-set mb-2'; newSet.innerHTML = ` `; replacementList.appendChild(newSet); newSet.querySelector('.remove-replacement').addEventListener('click', function() { replacementList.removeChild(newSet); }); } // ページ読み込み時に保存された置換セットを復元 window.addEventListener('load', function() { const savedReplacements = JSON.parse(localStorage.getItem('replacements') || '[]'); for (const [search, replace] of savedReplacements) { addReplacementSet(); const lastSet = document.getElementById('replacementList').lastElementChild; lastSet.querySelector('.replacement-search').value = search; lastSet.querySelector('.replacement-replace').value = replace; } }); // ページを離れる前に置換セットを保存 window.addEventListener('beforeunload', function() { localStorage.setItem('replacements', JSON.stringify(getReplacements())); });