gemini_prompter / prompt.js
SenY's picture
Upload 6 files
7eff197 verified
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 = `
<input type="text" class="form-control form-control-sm replacement-search mb-1" placeholder="検索語">
<input type="text" class="form-control form-control-sm replacement-replace mb-1" placeholder="置換語">
<button class="btn btn-danger btn-sm remove-replacement">
<i class="fas fa-times"></i>
</button>
`;
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()));
});