<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>画像プロンプト生成機 (履歴復元&1行化版)</title>
<style>
body { font-family: "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", sans-serif; padding: 1em; background-color: #f0f2f5; color: #333; }
.container { display: flex; flex-direction: column; gap: 20px; max-width: 800px; margin: 0 auto; background: #fff; padding: 25px; border-radius: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #444; font-size: 1.6em; margin-bottom: 10px; }
.section-box {
border: 1px solid #e1e4e8;
padding: 20px;
border-radius: 12px;
background-color: #fafbfc;
}
.section-label {
font-weight: bold;
color: #555;
display: block;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 5px;
}
/* 入力要素のデザイン */
.prompt-input, textarea, select {
width: 100%;
padding: 12px;
font-size: 1em;
border: 1px solid #ccc;
border-radius: 8px;
box-sizing: border-box;
background-color: #fff;
}
.prompt-input:focus, textarea:focus, select:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
}
/* 数値調整グリッド */
.settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.setting-item {
background: #fff;
border: 1px solid #ddd;
padding: 10px;
border-radius: 8px;
text-align: center;
}
.setting-item label {
display: block;
font-size: 0.85em;
color: #666;
margin-bottom: 5px;
font-weight: bold;
}
.setting-item input[type="number"] {
width: 100%;
padding: 8px;
text-align: center;
font-size: 1.1em;
border: 1px solid #ccc;
border-radius: 6px;
}
/* 履歴周り */
.history-section {
background-color: #f8f9fa;
border-bottom: 1px solid #eee;
padding-bottom: 15px;
margin-bottom: 15px;
}
.history-controls { display: flex; gap: 10px; align-items: center; margin-top: 5px; }
select.history-select { flex-grow: 1; padding: 8px; border: 1px solid #ddd; background-color: #fff; }
.clear-btn { font-size: 0.85em; cursor: pointer; color: #d9534f; background: none; border: 1px solid #d9534f; border-radius: 6px; padding: 6px 10px; white-space: nowrap; }
/* ランダムボタン */
.random-btn {
width: 100%;
padding: 12px;
font-size: 1em;
font-weight: bold;
color: #fff;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.random-btn:active { transform: translateY(2px); box-shadow: none; }
.random-btn:hover { opacity: 0.9; }
/* 詳細エリア */
textarea { height: 150px; line-height: 1.6; resize: vertical; }
/* 送信エリア */
.controls { display: flex; gap: 10px; align-items: center; margin-top: 10px; }
button.send-btn {
padding: 12px 25px;
cursor: pointer;
font-size: 1em;
background-color: #007bff;
color: white;
border: none;
border-radius: 8px;
font-weight: bold;
white-space: nowrap;
box-shadow: 0 4px 6px rgba(0,123,255,0.2);
}
button.send-btn:hover { background-color: #0056b3; }
button.copy-btn {
padding: 12px 25px;
cursor: pointer;
font-size: 1em;
background-color: #28a745; /* 緑色 */
color: white;
border: none;
border-radius: 8px;
font-weight: bold;
white-space: nowrap;
box-shadow: 0 4px 6px rgba(40, 167, 69, 0.2);
}
button.copy-btn:hover { background-color: #218838; }
.sub-label { font-size: 0.8em; color: #888; margin-top: -5px; margin-bottom: 10px; display:block;}
</style>
</head>
<body>
<h1>🎨 超・画像生成プロンプト作成機 (履歴&1行化)</h1>
<div class="container">
<div class="section-box history-section">
<label class="section-label">📂 生成履歴 (選択すると復元されます)</label>
<div class="history-controls">
<select id="historySelect" class="history-select" onchange="restoreHistory()">
<option value="" disabled selected>履歴から復元...</option>
</select>
<button type="button" class="clear-btn" onclick="clearHistory()">履歴削除</button>
</div>
</div>
<div class="section-box">
<label class="section-label">📌 1. 何を作りますか?(指示)</label>
<input type="text" id="instructionInput" class="prompt-input"
value="360度パノラマ画像を作って。">
</div>
<div class="section-box">
<label class="section-label">🎲 2. 要素の個数を指定(0で除外)</label>
<span class="sub-label">ジャンルを組み合わせたり、雰囲気を選んでください</span>
<div class="settings-grid">
<div class="setting-item"><label>SF背景</label><input type="number" id="n_sf_bg" value="1" min="0"></div>
<div class="setting-item"><label>SF物体</label><input type="number" id="n_sf_obj" value="0" min="0"></div>
<div class="setting-item"><label>ファンタジー背景</label><input type="number" id="n_fantasy_bg" value="0" min="0"></div>
<div class="setting-item"><label>ファンタジー物体</label><input type="number" id="n_fantasy_obj" value="0" min="0"></div>
<div class="setting-item"><label>自然背景</label><input type="number" id="n_nature_bg" value="0" min="0"></div>
<div class="setting-item"><label>自然物体</label><input type="number" id="n_nature_obj" value="0" min="0"></div>
<div class="setting-item"><label>時間</label><input type="number" id="n_time" value="1" min="0"></div>
<div class="setting-item"><label>天候</label><input type="number" id="n_weather" value="1" min="0"></div>
<div class="setting-item"><label>明るい雰囲気</label><input type="number" id="n_atm_bright" value="0" min="0"></div>
<div class="setting-item"><label>暗い雰囲気</label><input type="number" id="n_atm_dark" value="0" min="0"></div>
</div>
<button class="random-btn" onclick="generateRandomPrompt()">
設定した個数でランダム生成する!
</button>
<textarea id="detailArea" placeholder="ボタンを押すと、ここに詳細な情景が生成されます..."></textarea>
</div>
<div class="section-box" style="background-color: #eef2ff; border-color: #d0d7de;">
<label class="section-label">🚀 3. 1行にしてコピー / 開始</label>
<div class="controls">
<select id="aiSelector">
<option value="gemini">Google Gemini</option>
<option value="bing">Bing Image Creator (日本語OK)</option>
<option value="firefly">Adobe Firefly</option>
<option value="chatgpt">ChatGPT (DALL-E 3)</option>
<option value="claude">Claude</option>
<option value="perplexity">Perplexity</option>
</select>
<button class="copy-btn" onclick="handleAction(false)">コピーのみ</button>
<button class="send-btn" onclick="handleAction(true)">立ち上げて開始</button>
</div>
</div>
</div>
<script>
// ---------------------------------------------------------
// ■ データ定義
// ---------------------------------------------------------
const promptData = {
sf_bg: [
"近未来都市の摩天楼", "浮遊する空中都市", "ディストピアな地下都市", "ホログラム広告が溢れる繁華街",
"海底に沈んだ未来都市の廃墟", "植物と機械が融合したソーラーパンクな庭園", "二つの月が浮かぶ異星の空",
"アステロイドベルトの採掘基地", "ブラックホールの事象の地平線", "未知の惑星の原生林", "氷の惑星の秘密基地",
"デジタル雨が降る街", "発光するキノコの森", "磁気嵐の吹き荒れる荒野", "垂直農場の緑",
"シールド越しに見る超新星爆発", "テラフォーミングされた惑星の地表", "惑星直列の夜", "バイオルミネセンスの海",
"月面クレーターの影", "異次元への裂け目", "スペースコロニーの円筒内部", "酸性雨が降り注ぐ工業地帯",
"クリスタルで覆われた渓谷", "人工太陽に照らされた巨大地下空洞", "オーロラが輝く極地の氷原", "雲海に突き出る尖塔群",
"リングワールドの地平線", "中性子星の磁場", "データストリームが流れる電脳空間", "廃棄された宇宙船の墓場",
"大気が燃える惑星の空", "重力が崩壊した破片のフィールド", "ナノマシン構成体でできた砂漠", "無限に続くサーバーファーム",
"赤い矮星に照らされた荒野", "水没した巨大データセンター", "成層圏プラットフォームからの眺め", "オニール・シリンダーの農村エリア",
"レトロフューチャーな真空管都市", "化学汚染された極彩色の沼地", "結晶化した植物の森", "恒星のコロナ",
"ワームホールの入り口", "銀河中心の超高密度星団", "軌道エレベーターのケーブルが見える空", "反重力で浮く岩山群",
"鏡面加工された金属の大地", "巨大なパイプラインが走る荒野", "スラム化した高層建築の谷間", "人工知能が設計した幾何学的な都市",
"厚い氷の下に広がる海", "メタンの海とオレンジの空", "彗星の尾の中", "崩壊する月を見上げる地表",
"巨大なファンが回る換気口内部", "放棄されたテラフォーミング施設", "無数の培養ポッドが並ぶ巨大プラント",
"サイバー空間のグリッド", "錆びた鉄屑の山脈", "雲を突き抜ける巨大なダム", "軌道上から見た夜の地球",
"巨大な歯車が噛み合う機械都市", "プラズマの滝", "空中ハイウェイのジャンクション", "人工的な多層構造の洞窟",
"放射能で変異したジャングル", "氷河期に入った未来の都市", "砂漠に埋もれた古代のランドマーク", "巨大な眼のような星雲",
"アクリルのような透明な海", "幾何学的なクリスタルの平原", "巨大な送電塔が続く風景", "ドローンが飛び交う配送センター",
"レーザー光線が交差する戦場", "惑星リングの影が落ちる場所", "有毒な霧が立ち込めるスラム", "巨大なホログラムクジラが泳ぐ空",
"ガラス張りの海底トンネル", "雲の上に建つ白亜の塔", "巨大なパラボラアンテナの森", "人工降雪機が動くスキーリゾート",
"溶岩をエネルギーに変える発電所", "宇宙ゴミの帯", "異星の古代遺跡と二重太陽", "巨大なモノリスが並ぶ海岸",
"紫色の草が生い茂る平原", "巨大な菌糸ネットワークの森", "常に夜の都市", "空中庭園の廃墟", "ロボットだけが住む街",
"巨大なエネルギーシールドに守られたドーム", "重金属の雨が降る惑星", "光ファイバーの森", "量子もつれの視覚化空間",
"崩壊したスペースコロニーの外壁", "無限回廊", "鏡の世界", "巨大な配管が密集する路地", "スチームが噴き出す工場地帯",
"アンドロイドの廃棄場", "巨大なクレーター湖", "六角形の柱状節理の惑星", "浮遊する水の球体がある空間",
"ソーラーセイル越しに見る星の海", "虹色のガスが漂う星雲"
],
sf_obj: [
"火星の居住ドーム", "ダイソン球の巨大構造物", "ガス惑星の軌道プラットフォーム", "銀河を背景にした宇宙艦隊",
"巨大な恒星間移民船", "錆びついた巨大ロボットの残骸", "空を覆う巨大な宣伝飛行船", "宇宙を泳ぐ巨大生物",
"要塞化した移動都市", "砂漠に埋もれた宇宙船", "多層構造のハイウェイ", "エネルギー採掘リグ",
"未来のスポーツスタジアム", "軌道エレベーターのアンカー", "古代文明の黒いモノリス", "大気を浄化する巨大プラント",
"惑星を囲む巨大なリング", "墜落した軍事衛星", "成層圏まで伸びる世界樹", "シンギュラリティの塔", "巨大な螺旋構造物"
],
fantasy_bg: [
"古代遺跡が眠る密林", "クリスタルの洞窟", "妖精が住む光る森", "中世ヨーロッパ風の城下町",
"エルフの聖なる泉", "霧深い沼地", "空飛ぶ島々", "薄暗い地下ダンジョンの通路",
"グリフォンが飛び交う渓谷", "灼熱の溶岩地帯", "オーロラが輝く雪原", "巨大なキノコの森",
"精霊が集まる湖畔", "虹の架かる滝", "星降る夜の野営地", "ランタンの灯る石畳の道",
"呪われた森", "マナの奔流", "迷いの森", "オアシスの蜃気楼", "夜光虫の海", "神々の黄昏",
"彼岸花が咲き乱れる冥界の河原", "巨人の骨が散らばる荒野", "重力が歪んだ魔法地帯", "天まで届く大瀑布",
"雲海に浮かぶ天空の城郭", "朽ち果てた剣が無数に刺さる荒野(剣の墓場)", "サンゴでできた地上の森",
"水没した古代都市", "永遠に夜が続く吸血鬼の国", "ステンドグラスのような空の下", "巨大樹の枝の上に広がる村",
"見渡す限りのクリスタル砂漠", "竜巻が常に吹いている平原", "空中に浮遊する水の球体群", "黄金色に輝く麦畑と風車",
"紫色の霧に包まれた毒の沼", "ドワーフの巨大な地下採掘場", "本棚が地平線まで続く無限図書館", "鏡のような水面を持つ塩の湖",
"イバラに覆われた眠れる城の庭園", "火山灰が降り積もる灰色の世界", "星座が地上に描かれた魔法陣の広場",
"巨大な鎖で繋がれた浮遊大陸", "氷の華が咲き乱れる凍土", "七色の川が流れる谷", "ユニコーンが駆ける草原",
"月明かりに照らされた廃教会", "歯車と蒸気が動くドワーフの都", "精霊の光が舞う地下湖", "巨大な蓮の葉が浮く池",
"灼熱の砂漠にある氷のオアシス", "雷雲が渦巻くドラゴンの領域", "ガラスの花が咲く透明な草原", "時が止まったモノクロの世界",
"巨大な化石の中にある村", "虹の橋がかかる雲の上", "深海にある人魚の王国(広域)", "輝く鉱石が露出した峡谷",
"空から海へ水が落ちる世界の果て", "巨大なキノコの傘の上", "幽霊船が漂う霧の海", "五色の炎が燃える祭壇",
"古代文字が刻まれた石柱の森", "空飛ぶクジラの群れが見える空", "巨大な砂時計がある砂漠", "飴細工でできたお菓子の国",
"カボチャ畑が広がるハロウィンの里", "雪の中に温泉が湧く秘境", "大理石でできた白亜の迷宮", "巨大なランタンが浮く夜の祭",
"マンドラゴラが自生する奇妙な畑", "星の欠片が落ちている海岸", "巨大な本が開かれたような地形", "インクで描かれたような水墨画の世界",
"チェス盤のような白黒の大地", "トランプが舞う不思議の国", "煉獄の炎が燃える断崖", "天国へと続く長い階段",
"神殿の回廊", "地下深くに広がる発光苔の洞窟", "ペガサスの羽が舞う山頂", "巨大な水晶クラスターの谷",
"錬金術の廃液が流れる極彩色の川", "ルーン文字が光る黒い岩肌", "天空から鎖で吊るされた牢獄", "魔力が結晶化した森",
"ドライアドが住む新緑の森", "セイレーンが歌う岩礁地帯", "巨大な貝殻が点在する砂浜", "スライムが大量発生している草原",
"火の粉が舞う鍛冶の町", "風の精霊が通り抜ける風穴", "土の精霊が守る棚田", "光の精霊が住むプリズムの谷",
"闇の精霊が潜む影の谷", "異次元と繋がる亀裂のある空", "古代の戦争の跡が残るクレーター", "神獣が眠る巨大な祠の前"
],
fantasy_obj: [
"雲の上の神殿", "ドラゴンの巣がある火山", "ドワーフの地下要塞", "世界樹の根本", "満月の夜の古城",
"伝説の聖剣が刺さった岩", "召喚魔法陣と光の柱", "人魚が泳ぐサンゴ礁の宮殿", "氷の女王が住む水晶の城",
"砂漠に半分埋もれた巨像", "廃墟となった神殿", "雷雨の中の塔", "不動の巨大ゴーレム", "オークの砦",
"空飛ぶ帆船", "海賊船とクラーケン", "ツタの絡まる石橋", "ステンドグラスの大聖堂", "異界へのゲート",
"カボチャの馬車", "森の奥のお菓子の家", "雲を突き抜ける豆の木", "深海の沈没船", "天空の回廊",
"女神の彫像", "英雄の記念碑", "動く城", "バベルの塔のような未完の巨塔", "剣の墓場", "竜巻の中に建つ魔術師の塔"
],
nature_bg: [
"静かな湖畔のキャンプ場", "オーロラが見える雪原", "サンゴ礁が広がる海底", "桜が満開の並木道",
"紅葉が美しい日本庭園", "広大なサバンナ", "霧の立ち込める海岸", "険しい山岳地帯",
"エメラルドグリーンの透き通る海", "波打ち際の白い砂浜", "木漏れ日が差し込む深い森",
"満天の星空と天の川", "燃えるような夕焼け空", "入道雲が湧き上がる夏の空", "一面に広がるひまわり畑",
"ラベンダー畑の紫の絨毯", "雪を頂いた壮大な山脈", "熱帯雨林のジャングル", "苔むした岩と清流",
"砂丘に描かれた風紋", "マングローブの林", "竹林の小径", "雲海に浮かぶ山頂", "岩肌が露出した荒涼とした大地",
"新緑のブナ林", "風に揺れる黄金色の麦畑", "色とりどりの高山植物の群生", "薄明光線が降り注ぐ谷",
"月明かりに照らされた海", "紅葉で真っ赤に染まる山肌", "落ち葉の絨毯", "秋のすすき野原",
"野生の馬が走る草原", "ホタルが飛び交う小川", "イチョウ並木のトンネル", "ブドウ畑の丘",
"サボテンの生える砂漠", "霧氷のついた枝", "夜明け前の蒼い世界", "湿原の木道", "菜の花畑とローカル線",
"棚田の夕暮れ", "茶畑の幾何学模様", "塩湖の鏡張り", "バオバブの並木道", "入江の漁村", "嵐の海",
"雪解け水が流れる川", "水芭蕉の群生地", "ネモフィラの青い丘", "コスモス畑", "彼岸花が咲く畦道",
"樹氷の森", "流氷の海", "リアス式海岸", "干潟の夕景", "朝靄に包まれた牧場", "サトウキビ畑", "パイナップル畑",
"五色の石が転がる河原", "真っ白な石灰岩の棚田", "コバルトブルーの温泉地帯", "極夜の氷原"
],
nature_obj: [
"グランドキャニオンのような渓谷", "大迫力の巨大な滝", "水面に映る逆さ富士", "鍾乳洞の神秘的な空間",
"噴煙を上げる火山", "切り立ったフィヨルド", "カルスト台地の奇岩", "ダブルレインボー", "皆既日食の瞬間",
"流れ星が降り注ぐ夜", "紫色の雷光", "桜吹雪が舞う川沿い", "銀世界に佇む一本松", "凍りついた滝",
"渡り鳥の群れ", "クジラが泳ぐ大海原", "藤棚の下", "蜃気楼が見える地平線", "水平線に沈む太陽",
"青の洞窟", "孤島のリゾート", "氷河の崩落", "オアシスの泉", "間欠泉の噴出", "セコイアの巨木",
"断崖絶壁の灯台", "火口湖のエメラルドグリーン", "渓谷の吊り橋", "風車のある風景", "水車小屋と小川",
"蓮の花が咲く池", "テーブルマウンテンのような台地", "柱状節理の断崖", "巨大な一枚岩(モノリス)",
"ハートの形をした浮島", "古代杉の切り株", "竜の背のような岩礁"
],
time: [
"夜明け前", "早朝", "日の出", "朝", "午前", "正午", "真昼", "午後",
"夕方", "夕暮れ", "日没", "黄昏時", "マジックアワー", "ブルーアワー",
"夜", "真夜中", "深夜", "丑三つ時"
],
weather: [
"快晴", "青空", "曇り", "霧", "濃霧", "朝霧",
"雨", "小雨", "霧雨", "天気雨", "土砂降り", "豪雨", "雷雨", "嵐", "台風",
"雪", "吹雪", "雹", "ダイヤモンドダスト",
"虹", "天使の梯子", "蜃気楼", "花吹雪", "オーロラ",
"日食", "月食", "満月", "新月", "星空", "流星群", "天の川"
],
atm_bright: [
"神々しく幻想的な光", "活気に満ち溢れている", "夢の中にいるような感覚", "昭和レトロな暖かい雰囲気",
"80年代のポップな色彩", "ヴェイパーウェイヴのような幻想的な空間", "希望に満ちた明るい未来感",
"幸福感に包まれた優しい世界", "エネルギッシュで力強い躍動感", "清涼感のある爽やかな風",
"祝祭のような賑やかな喧騒", "魔法がかかったようなキラキラした空気", "アニメーションのような鮮やかな色彩",
"ロマンチックで甘い雰囲気", "夢心地のふわふわした感覚", "おとぎ話のようなメルヘンチックな世界",
"パステルカラーの可愛らしい空間", "洗練されたラグジュアリーな空間", "ボタニカルで癒やされる空間",
"近未来的なスタイリッシュさ", "壮大な冒険の予感", "勝利のファンファーレが聞こえる高揚感",
"トロピカルで開放的な空気", "コメディタッチの陽気な世界", "聖なる祝福に満ちたオーラ"
],
atm_dark: [
"ノスタルジックなセピア色の世界", "色あせた古い写真のような質感", "退廃的で不気味な空気感",
"孤独で寂しい雰囲気", "緊張感のある張り詰めた空気", "ゾクッとするような恐怖感",
"狂気に満ちたサイケデリックな空間", "ゴシックで重厚な空気", "絶望的な終末感", "闇に飲み込まれそうな気配",
"神秘的で厳かな静寂", "異次元のような浮遊感", "幽玄で儚い美しさ", "古代の神話のような荘厳さ",
"映画のワンシーンのようなドラマチックな構図", "孤独で静謐な時間", "世界から取り残されたような寂しさ",
"音のない静止した世界", "哀愁漂う夕暮れの空気", "冷たく無機質な質感", "ハードボイルドで渋い世界観",
"鉄と油の匂いがする無骨な雰囲気", "戦場のような張り詰めた緊張感", "スチームパンクな蒸気の煙る空気",
"ミニマルで整然とした美しさ", "カオスで雑多なエネルギー", "瞑想的な深い精神世界",
"記憶の断片のような曖昧なイメージ", "クリスタルのように透き通った空気", "嵐の前の不穏な静けさ",
"白昼夢のような非現実感", "インダストリアルな荒廃感", "監獄のような息苦しい閉塞感",
"呪われた不浄な空気", "深淵から見つめられている気配", "電子ドラッグのような陶酔感"
]
};
// ---------------------------------------------------------
// ■ 履歴管理機能 (Object保存版)
// ---------------------------------------------------------
const STORAGE_KEY = 'ai_image_full_history_v6';
window.onload = function() { loadHistory(); };
// 履歴には「指示(instruction)」と「詳細(details)」の両方を保存
function saveToHistory(inst, det) {
if (!inst && !det) return;
let history = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
// 同じ組み合わせがあれば削除して先頭へ (重複回避)
const newItem = { instruction: inst, details: det };
const jsonItem = JSON.stringify(newItem);
// 既存の履歴から同一内容を探して削除(単純な文字比較)
history = history.filter(item => JSON.stringify(item) !== jsonItem);
// 先頭に追加
history.unshift(newItem);
// 最大20件まで
if (history.length > 20) history.pop();
localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
loadHistory();
}
function loadHistory() {
const historySelect = document.getElementById('historySelect');
const history = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
historySelect.innerHTML = '<option value="" disabled selected>履歴から復元...</option>';
history.forEach((item, index) => {
const option = document.createElement('option');
// valueには配列のインデックスを入れる
option.value = index;
// 表示名は「指示 + 詳細」の一部を表示
let displayText = `[${item.instruction}] ${item.details.replace(/\n/g, ' ')}`;
if (displayText.length > 60) displayText = displayText.substring(0, 60) + "...";
option.text = displayText;
historySelect.appendChild(option);
});
}
function restoreHistory() {
const historySelect = document.getElementById('historySelect');
const index = historySelect.value;
const history = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
if (history[index]) {
document.getElementById('instructionInput').value = history[index].instruction;
document.getElementById('detailArea').value = history[index].details;
}
}
function clearHistory() {
if(confirm("履歴をすべて削除しますか?")) {
localStorage.removeItem(STORAGE_KEY);
loadHistory();
}
}
// ---------------------------------------------------------
// ■ ランダム生成機能
// ---------------------------------------------------------
function generateRandomPrompt() {
const detailArea = document.getElementById('detailArea');
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
let allParts = [];
// UIのIDとデータキーの紐付け
const config = [
{ id: 'n_sf_bg', data: promptData.sf_bg },
{ id: 'n_sf_obj', data: promptData.sf_obj },
{ id: 'n_fantasy_bg', data: promptData.fantasy_bg },
{ id: 'n_fantasy_obj',data: promptData.fantasy_obj },
{ id: 'n_nature_bg', data: promptData.nature_bg },
{ id: 'n_nature_obj', data: promptData.nature_obj },
{ id: 'n_time', data: promptData.time },
{ id: 'n_weather', data: promptData.weather },
{ id: 'n_atm_bright', data: promptData.atm_bright },
{ id: 'n_atm_dark', data: promptData.atm_dark }
];
config.forEach(item => {
const count = parseInt(document.getElementById(item.id).value) || 0;
for(let i = 0; i < count; i++) {
allParts.push(pick(item.data));
}
});
if (allParts.length === 0) {
detailArea.value = "(要素が選択されていません。数値を1以上に設定してください)";
return;
}
// テキストエリア上では見やすく改行を残す
detailArea.value = allParts.join("。\n") + "。";
// エフェクト
detailArea.style.borderColor = "#007bff";
setTimeout(() => detailArea.style.borderColor = "#ccc", 300);
}
// ---------------------------------------------------------
// ■ アクション処理 (1行化 & 保存 & コピー/起動)
// ---------------------------------------------------------
function handleAction(isLaunch) {
const instruction = document.getElementById('instructionInput').value.trim();
const details = document.getElementById('detailArea').value.trim();
if (!instruction || !details) {
alert("指示と詳細の両方が必要です。");
return;
}
// 1. 履歴に保存 (元の改行ありの状態で保存)
saveToHistory(instruction, details);
// 2. 1行化処理 (改行をスペースに変換)
// 指示 + スペース + 詳細 (詳細内の改行もスペース化)
const oneLineDetails = details.replace(/[\r\n]+/g, ' ');
const finalPrompt = `${instruction} ${oneLineDetails}`;
// 3. コピー or 起動
if (navigator.clipboard) {
navigator.clipboard.writeText(finalPrompt).then(() => {
if (!isLaunch) {
alert("1行にしてコピーしました!\n履歴にも保存されました。");
} else {
launchService(finalPrompt);
}
}).catch(err => {
alert("コピーに失敗しました。");
});
} else {
// クリップボードAPI非対応ブラウザ用
if (!isLaunch) {
alert("このブラウザではコピー機能が制限されています。");
} else {
launchService(finalPrompt);
}
}
}
function launchService(promptText) {
const aiService = document.getElementById('aiSelector').value;
const encodedPrompt = encodeURIComponent(promptText);
let url = "";
switch (aiService) {
case "bing": url = "https://www.bing.com/images/create"; break;
case "firefly": url = "https://firefly.adobe.com/upload/text_to_image"; break;
case "gemini": url = "https://gemini.google.com/app"; break;
case "chatgpt": url = "https://chatgpt.com/"; break;
case "claude": url = "https://claude.ai/new"; break;
case "perplexity": url = `https://www.perplexity.ai/search?q=${encodedPrompt}`; break;
}
if (aiService === 'perplexity') {
window.open(url, '_blank');
} else {
let serviceName = document.getElementById('aiSelector').options[document.getElementById('aiSelector').selectedIndex].text;
let msg = "プロンプトを1行にしてコピーしました!\n\n" + serviceName + "を別タブで開きますか?";
if(confirm(msg)) {
window.open(url, '_blank');
}
}
}
</script>
</body>
</html>
使用変数
| aiService | |
| allParts | |
| borderColor | |
| charset | |
| class | |
| clearHistory -------( Function ) | |
| config | |
| count | |
| detailArea | |
| details | |
| displayText | |
| encodedPrompt | |
| err | |
| finalPrompt | |
| generateRandomPrompt -------( Function ) | |
| handleAction -------( Function ) | |
| history | |
| historySelect | |
| i | |
| id | |
| index | |
| innerHTML | |
| instruction | |
| item | |
| jsonItem | |
| lang | |
| launchService -------( Function ) | |
| length | |
| loadHistory -------( Function ) | |
| min | |
| msg | |
| newItem | |
| onchange | |
| onclick | |
| oneLineDetails | |
| onload | |
| option | |
| pick | |
| placeholder | |
| promptData | |
| q | |
| restoreHistory -------( Function ) | |
| saveToHistory -------( Function ) | |
| serviceName | |
| STORAGE_KEY | |
| style | |
| text | |
| type | |
| url | |
| value |