はじめまして、形而上学うんこです。

自己紹介をしようと思ったのですが、
知らんやつの自己紹介なんて校長先生の話と同じくらい聞きたくないので
さっさと本題に移らせていただきますね。
……とは言ってみたものの、記事を書くのは面倒くさいものです。
はてなブログユーザーの皆様も、そう思ったことはありませんか?僕は思います。
しかし、ChatGPTで書くのは僕のプライドが許しませんし、
何より僕のChatGPTは頭が狂っているんです。

こりゃ駄目だ。
そこで僕は考えました。
「じゃあ記事ジェネレーターを作ればいいんじゃね!?」
というわけでやっていきたいと思います。パチパチ。
とはいえ僕は馬鹿です。どのくらい馬鹿かというと、上のChatGPTくらい馬鹿です。
そして、馬鹿なのでプログラミングがあまりできません。
しかし腐っても僕はうんこです。
流石にうんことしての常識は身につけているので、どのような仕組みを使えばよいかはすぐに分かります。
みなさんも分かりますよね!?
これでわからなかったらあなたはうんことしての常識がないので、うんこ幼稚園からやり直してください。
そう、今回使うのはマルコフ連鎖です。
まあ、僕は優しいので、マルコフ連鎖を知らない下民どもにもわかりやすく解説していきます。

この図のように、単語ごとに区切って確率的に次の言葉を導く方法です。
なので、必然的によく使われる文脈で話すようになります。
上の図でいうと、学習した文章の中で「うんこは哲学的概念だ」と書いているものより「うんこはキモい」と書いてあるもののほうが多かったので、このような結果になったと考えられます。
というか、うんこは哲学的概念だと思っている人、脳みそ腐ってんのか。
危ない危ない、炎上するところでした。みなさんも言葉遣いには気をつけましょうね!!
さあ、それでは仕組みが分かったところで
ChatGPTに作らせていきましょう!!
プログラミングはhtml,Javascript,Cssで作らせましょう。
ちなみに僕のChatGPTの名前はぬぬんと言います。以後お見知りおきを。
……なんやかんやあってプログラムができました。

そうしたら、拡張子をtxtからhtmlにして保存します。
ファイルから開くと……

できました!!!
このプログラムでは、テキスト部分に入っている文章を学習して生成します。
デフォルトではテキスト部分に適当な文章を入れています。
というわけで、早速記事を書かせていきましょう!!
物語なので記事になるのかはわかりませんが、なんとかします。

流石に支離滅裂すぎますね。
なので、「マルコフの次数」と書かれている部分を上げてみましょう。こうしたらいい感じになるはずです。

なんとか読める程度にはなりましたが、意味はわかりませんね。
まあ学習した量が少ないのもあってそれは仕方ないので、内容を楽しみましょう。
……とその前に、僕は気づきました。指定した文字数に比べて文字数が少なすぎることに。
ぬぬんになんとかしてもらいましょう。

長い文章もできましたね。
内容はアレですけど。
まあこんな感じで、皆さんもマルコフ連鎖記事ジェネレーターを作ってみるのをおすすめします。
一応プログラムを貼っておきますね↓
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>マルコフ連鎖 記事ジェネレーター</title>
<style>
:root{--bg:#fafafa;--card:#fff;--accent:#0f172a;--muted:#6b7280}
body{font-family:system-ui,-apple-system,"Hiragino Kaku Gothic ProN",Meiryo,Roboto,Arial; background:var(--bg); color:var(--accent); margin:0;padding:20px}
.wrap{max-width:980px;margin:0 auto}
header{display:flex;align-items:center;gap:12px}
h1{font-size:20px;margin:0}
.grid{display:grid;grid-template-columns:1fr 360px;gap:16px;margin-top:18px}
.card{background:var(--card);padding:14px;border-radius:10px;box-shadow:0 1px 2px rgba(0,0,0,0.04)}
textarea{width:100%;height:200px;padding:10px;border-radius:8px;border:1px solid #e6e9ee;resize:vertical}
input[type=text],select,input[type=number]{width:100%;padding:8px;border-radius:8px;border:1px solid #e6e9ee}
button{background:var(--accent);color:#fff;padding:8px 12px;border:none;border-radius:8px;cursor:pointer}
.muted{color:var(--muted);font-size:13px}
.results{display:flex;flex-direction:column;gap:8px;margin-top:10px;max-height:420px;overflow:auto}
.title{background:#f8fafc;padding:10px;border-radius:8px;border:1px solid #e6eef6;font-weight:600;white-space:pre-wrap}
.controls{display:flex;gap:8px;align-items:center;margin-top:8px;flex-wrap:wrap}
.footer{margin-top:14px;font-size:13px;color:var(--muted)}
.row{display:flex;gap:8px}
</style>
</head>
<body>
<div>
<header>
<h1>マルコフ連鎖 記事ジェネレーター(長文対応)</h1>
</header>
<div>
<main>
<div>
<label>学習テキスト</label>
<textarea>今や、一家に一台は当たり前の大人気商品、『オッチムマンソー』!
皆さんのご家庭にも、もちろん置いてあると思います。
しかし、皆さんはオッチムマンソーをしっかりと使いこなせていますか?
もはやただ濡れるだけの空間だと感じていませんか。
風呂場は毎日使う場所です。ならば少しでも快適に、少しでも楽しくしたいものです。</textarea>
<div>
<divhttps://d.hatena.ne.jp/keyword/flex">flex:1">
<label>マルコフの次数(n-gram)</label>
<select>
<option value="1">1(文字単位)</option>
<option value="2" selected>2</option>
<option value="3">3</option>
</select>
</div>
<div>
<label>生成長さ(最大10000文字)</label>
<input type="number" value="500" min="6" max="10000" />
</div>
</div>
<div>
<button>学習して生成</button>
<button>もう1回生成</button>
<button>コピー</button>
<div>文字ベース簡易マルコフ連鎖</div>
</div>
<div></div>
</div>
</main>
<aside>
<div>
<label>オプション</label>
<div>
<label>候補数</label>
<input type="number" value="1" min="1" max="5" />
</div>
<div>
<label>接頭語</label>
<input type="text" placeholder="例:衝撃の" />
</div>
<div>
<label>ランダムシード</label>
<input type="text" placeholder="空欄でランダム" />
</div>
<divhttps://d.hatena.ne.jp/keyword/flex">flex;gap:8px">
<button>TXT保存</button>
<button>クリア</button>
</div>
<div>
※ 10000文字生成は学習量が少ないと怪文書になります
</div>
</div>
</aside>
</div>
</div>
<script>
function buildChain(text, order){
const chain = new Map();
const normalized = text.replace(/\r/g,'');
for(let i=0;i<=normalized.length-order;i++){
const key = normalized.slice(i,i+order);
const next = normalized[i+order] || '';
if(!chain.has(key)) chain.set(key,);
chain.get(key).push(next);
}
return chain;
}
function seededRandom(seed){
let h = 2166136261 >>> 0;
for(let i=0;i<seed.length;i++){
h = Math.imul(h ^ seed.charCodeAt(i), 16777619) >>> 0;
}
return function(){
h += 0x6D2B79F5;
h = Math.imul(h ^ (h >>> 15), h | 1) >>> 0;
h ^= h + Math.imul(h ^ (h >>> 7), h | 61);
return ((h ^ (h >>> 14)) >>> 0) / 4294967296;
}
}
function generateFromChain(chain, order, length, rng){
const keys = Array.from(chain.keys());
if(keys.length === 0) return '';
let key = keys[Math.floor(rng()*keys.length)];
let out = key;
while(out.length < length){
const list = chain.get(key);
if(!list || list.length === 0) break;
const next = list[Math.floor(rng()*list.length)];
out += next;
key = out.slice(-order);
if(!chain.has(key)){
key = keys[Math.floor(rng()*keys.length)];
}
}
return out.slice(0, length).replace(/\n{3,}/g,"\n\n");
}
const buildBtn = document.getElementById('build');
const generateBtn = document.getElementById('generate');
const copyBtn = document.getElementById('copy');
const resultsEl = document.getElementById('results');
const sourceEl = document.getElementById('source');
const orderEl = document.getElementById('order');
const lengthEl = document.getElementById('length');
const countEl = document.getElementById('count');
const prefixEl = document.getElementById('prefix');
const seedEl = document.getElementById('seed');
const downloadTxt = document.getElementById('downloadTxt');
const clearBtn = document.getElementById('clear');
let currentChain = null;
let currentOrder = 2;
let lastResults =;
function generateMany(){
resultsEl.innerHTML = '';
lastResults =;
const cnt = Math.max(1, parseInt(countEl.value,10) || 1);
const len = Math.max(6, Math.min(10000, parseInt(lengthEl.value,10) || 200));
const prefix = prefixEl.value || '';
const seed = seedEl.value || String(Math.random());
const rng = seededRandom(seed);
for(let i=0;i<cnt;i++){
const text = prefix + generateFromChain(currentChain, currentOrder, len, rng);
const el = document.createElement('div');
el.className = 'title';
el.textContent = text;
resultsEl.appendChild(el);
lastResults.push(text);
}
}
buildBtn.addEventListener('click', ()=>{
const text = sourceEl.value.trim();
currentOrder = parseInt(orderEl.value,10);
currentChain = buildChain(text, currentOrder);
generateMany();
});
generateBtn.addEventListener('click', ()=>{
if(!currentChain){
alert('先に学習してください');
return;
}
generateMany();
});
copyBtn.addEventListener('click', ()=>{
if(!lastResults.length) return;
navigator.clipboard.writeText(lastResults.join('\n\n'));
alert('コピーしました');
});
downloadTxt.addEventListener('click', ()=>{
if(!lastResults.length) return;
const blob = new Blob([lastResults.join('\n\n')], {type:'text/plain'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'markov_text.txt';
a.click();
URL.revokeObjectURL(a.href);
});
clearBtn.addEventListener('click', ()=>{
resultsEl.innerHTML = '';
lastResults =;
});
window.addEventListener('load', ()=>{ buildBtn.click(); });
</script>
</body>
</html>
それではまた。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。