Site Builder
Editing:
tools-writing-blogs11.php
writable 0666
<?php /***************************************************************** * Promptinator – Article Generator (v2.0 – AJAX / toolbox skin) *****************************************************************/ declare(strict_types=1); /* ---------- 1. Constants & helpers -------------------------------------- */ const COOKIE_NAME = 'openai_key'; const COOKIE_TTL = 30 * 24 * 3600; // 30 days const SECRET = __FILE__; // file‑specific pepper // root domain so cookie works on app.bestdealon.com etc. $host = $_SERVER['HTTP_HOST'] ?? ''; $cookieDomain = (!filter_var($host, FILTER_VALIDATE_IP) && preg_match('/([a-z0-9-]+\.[a-z]{2,})$/i', $host, $m)) ? '.'.$m[1] : ''; function enc(string $plain): string { $m = 'aes-128-ctr'; $k = substr(hash('sha256', SECRET, true), 0, 16); $iv= random_bytes(openssl_cipher_iv_length($m)); return base64_encode(openssl_encrypt($plain,$m,$k,0,$iv).'::'.$iv); } function dec(string $cipher): string { [$ct,$iv] = explode('::', base64_decode($cipher), 2) + [null,null]; if(!$ct||!$iv) return ''; $m='aes-128-ctr'; $k=substr(hash('sha256', SECRET, true), 0, 16); return openssl_decrypt($ct,$m,$k,0,$iv) ?: ''; } /* ---------- 2. Save / delete API key ------------------------------------ */ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['save_key'])) { $raw = trim($_POST['api_key']); $ctx = stream_context_create(['http'=>[ 'method'=>'GET', 'header'=>"Authorization: Bearer $raw\r\n", 'timeout'=>8 ]]); if (@file_get_contents('https://api.openai.com/v1/models', false, $ctx)) { setcookie(COOKIE_NAME, enc($raw), time()+COOKIE_TTL, '/', $cookieDomain, isset($_SERVER['HTTPS']), true); header('Location: '.$_SERVER['REQUEST_URI']); exit; } http_response_code(400); echo 'Invalid API key'; exit; } if (isset($_GET['logout'])) { setcookie(COOKIE_NAME,'',time()-3600,'/',$cookieDomain,isset($_SERVER['HTTPS']),true); header('Location: '.$_SERVER['PHP_SELF']); exit; } /* ---------- 3. AJAX endpoint (generate article) ------------------------- */ if ($_SERVER['REQUEST_METHOD']==='POST' && ($_GET['ajax'] ?? '')==='1') { header('Content-Type: application/json; charset=utf-8'); $topic = trim($_POST['topic'] ?? ''); $keywords = trim($_POST['keywords'] ?? ''); $linkurl = trim($_POST['linkurl'] ?? ''); $sections = max(1, intval($_POST['sections'] ?? 3)); $paras = max(1, intval($_POST['paras'] ?? 3)); $lang = $_POST['lang'] ?? 'English'; $style = $_POST['style'] ?? 'Creative'; $tone = $_POST['tone'] ?? 'Neutral'; $model = $_POST['model'] ?? 'gpt-3.5-turbo'; $key = isset($_COOKIE[COOKIE_NAME]) ? dec($_COOKIE[COOKIE_NAME]) : ''; if (!$key) { echo json_encode(['error'=>'Missing API key']); exit; } if ($topic===''){ echo json_encode(['error'=>'Topic required']); exit; } $kwTxt = $keywords ? " Include keywords: $keywords." : ''; $linkTxt= ($keywords && $linkurl) ? " Hyperlink each keyword to $linkurl." : ''; $prompt = "Write a $lang $style article in a $tone tone about «$topic». ". "Use $sections sections (each <h2>) and $paras paragraph".($paras>1?'s':''). " per section. Use <h3> where helpful.".$kwTxt.$linkTxt. " Append <p class=\"excerpt\">Excerpt: …</p>. Return ONLY HTML."; $payload=[ 'model' => $model, 'messages' => [['role'=>'user','content'=>$prompt]], 'max_tokens' => max(800,$sections*$paras*200), 'temperature'=> 0.7 ]; $ch=curl_init('https://api.openai.com/v1/chat/completions'); curl_setopt_array($ch,[ CURLOPT_RETURNTRANSFER => 1, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer '.$key, 'Content-Type: application/json' ], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_TIMEOUT => 60 ]); $raw = curl_exec($ch); $err = curl_error($ch); curl_close($ch); if(!$raw || $err){ echo json_encode(['error'=>'Network error: '.$err]); exit; } $data = json_decode($raw,true); $html = $data['choices'][0]['message']['content'] ?? ''; if(!$html){ echo json_encode(['error'=>'OpenAI reply was empty']); exit; } echo json_encode(['html'=>$html,'prompt'=>$prompt]); exit; } /* ---------- 4. Display page --------------------------------------------- */ $loggedIn = isset($_COOKIE[COOKIE_NAME]) && dec($_COOKIE[COOKIE_NAME]); $models = ['gpt-3.5-turbo','gpt-4o-mini','gpt-4']; ?> <!doctype html><html lang="en"><head> <meta charset="utf-8"><title>Promptinator • Article Generator</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> <style> :root{ --blue:#0066ff;--blue-d:#0250e0;--brand:#0f3760;--bg:#f1f4fb; --radius:.7rem; } body{background:var(--bg);margin:0;font-family:system-ui,Roboto,Arial,sans-serif;color:#222} header{background:#eee;padding:.8rem 1.2rem;font-weight:700;display:flex;justify-content:space-between;align-items:center} header nav a{color:var(--brand);text-decoration:none;margin-right:.4rem} header nav a:last-child{margin:0} .container{max-width:960px;margin:2rem auto;padding:0 1rem} #bar{display:flex;gap:1rem;flex-wrap:wrap;align-items:center;margin-bottom:1.6rem} #bar input{padding:.5rem .75rem;border:1px solid #ccd3e5;border-radius:6px;max-width:260px;width:100%} #bar select{padding:.45rem;border-radius:6px} .badge{display:flex;align-items:center;gap:.3ch;font-size:.92rem} .badge.green{color:#139f4d}.badge.red{color:#c43} .badge button{background:none;border:none;font-size:1rem;color:inherit;cursor:pointer} button.primary{background:var(--blue);color:#fff;border:none;border-radius:6px;padding:.6rem 1.3rem;font-weight:600;cursor:pointer} button.primary:hover{background:var(--blue-d)} form.grid{display:grid;gap:1.2rem} form.grid input,form.grid select{border-radius:6px} #spinner{display:none;gap:.6ch;align-items:center;margin-top:1rem;font-size:1rem} #spinner.active{display:flex} @keyframes spin{to{transform:rotate(360deg)}} #spinner svg{width:18px;height:18px;animation:spin 1s linear infinite} textarea{font-family:"Fira Code",monospace} .preview{background:#fff;border:1px solid #e2e6f0;border-radius:8px;padding:1rem;max-height:60vh;overflow:auto} @media(max-width:600px){header nav{font-size:.9rem}#bar{flex-direction:column;align-items:flex-start}} </style> </head> <body> <header> <nav> <a href="/">BestDealOn</a> » <a href="/members/dashboard.php">Dashboard</a> » <a href="/ai-tools/tools.php">AI Toolbox</a> » Article Generator </nav> <a href="/<?=$_SESSION['slug']??''?>" style="text-decoration:none">View Site</a> </header> <div class="container"> <!-- API‑key / model bar --> <div id="bar"> <?php if(!$loggedIn): ?> <form method="post" style="display:flex;gap:.6rem;flex-wrap:wrap"> <input type="password" name="api_key" placeholder="Enter OpenAI key…" required> <button class="primary" name="save_key">Save Key</button> <a href="https://platform.openai.com/api-keys" target="_blank" style="font-size:.85rem;text-decoration:underline">Get key</a> </form> <?php else: ?> <span class="badge green">● API key saved <button title="Delete key" onclick="location='?logout=1'">❌</button> </span> <select id="modelSel"><?php foreach($models as $m):?> <option value="<?=$m?>" <?=$m==='gpt-4o-mini'?'selected':''?>><?=$m?></option> <?php endforeach;?></select> <?php endif;?> </div> <?php if(!$loggedIn): ?> <article class="preview"><h2>Get started</h2><p>Save your API key to unlock Promptinator.</p></article> <?php else: ?> <!-- Generator form --> <form class="grid" id="genForm"> <label>Topic <div style="position:relative"> <input name="topic" required placeholder="e.g. Electric bicycles"> <button type="button" id="mic" style="position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:none;border:none;font-size:1.15rem">🎤</button> </div> </label> <label>Keywords (comma‑separated) <input name="keywords"> </label> <label>Link URL (optional) <input type="url" name="linkurl"> </label> <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem"> <label># Sections <select name="sections"><?php for($i=1;$i<=8;$i++):?><option><?=$i?></option><?php endfor;?></select> </label> <label># Paragraphs / section <select name="paras"><?php for($i=1;$i<=6;$i++):?><option><?=$i?></option><?php endfor;?></select> </label> <label>Language <select name="lang"><?php foreach(['English','Spanish','German','French','Italian','Portuguese','Dutch'] as $l):?><option><?=$l?></option><?php endforeach;?></select> </label> <label>Style <select name="style"><?php foreach(['Creative','Informative','Narrative','Persuasive','Analytical','Journalistic'] as $s):?><option><?=$s?></option><?php endforeach;?></select> </label> <label>Tone <select name="tone"><?php foreach(['Neutral','Cheerful','Humorous','Assertive','Inspirational','Professional','Emotional'] as $t):?><option><?=$t?></option><?php endforeach;?></select> </label> </div> <label>Prompt Preview <textarea id="prompt" readonly></textarea> </label> <button type="button" class="primary" id="copyPrompt" hidden>Copy Prompt</button> <button type="submit" class="primary" id="goBtn">Generate Article</button> <div id="spinner"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle></svg><span id="sec">0</span>s</div> </form> <!-- Results --> <section id="results" style="display:none"> <h3>HTML Source</h3> <textarea id="raw" readonly style="min-height:170px"></textarea> <button type="button" class="primary copyBtn" id="copyRaw">Copy HTML</button> <h3>Rendered Preview</h3> <div class="preview" id="render"></div> <button type="button" class="primary copyBtn" id="copyRender">Copy Rendered HTML</button> </section> <?php endif; ?> </div><!-- /.container --> <script> (()=>{ /* ----- live prompt builder & copy ----- */ const form = document.getElementById('genForm'); if(form){ const promptBox = document.getElementById('prompt'), copyPrompt= document.getElementById('copyPrompt'), modelSel = document.getElementById('modelSel'); const build = () =>{ const F= n => form.elements[n].value.trim(); if(!F('topic')){promptBox.value='';copyPrompt.hidden=true;return;} promptBox.value=`Write a ${F('lang')} ${F('style')} article in a ${F('tone')} tone about «${F('topic')}». ` +`Use ${F('sections')} sections (each <h2>) and ${F('paras')} paragraph${F('paras')>1?'s':''} per section. ` +(F('keywords')?`Include keywords: ${F('keywords')}. `:'') +(F('keywords')&&F('linkurl')?`Hyperlink each keyword to ${F('linkurl')}. `:'') +'Append <p class="excerpt">Excerpt: …</p>. Return ONLY HTML.'; copyPrompt.hidden=false; }; form.querySelectorAll('input,select').forEach(el=>el.addEventListener('input',build)); build(); copyPrompt.addEventListener('click',()=>navigator.clipboard.writeText(promptBox.value) .then(()=>flash(copyPrompt))); /* --- Mic --- */ const mic=document.getElementById('mic'); if(mic && (window.SpeechRecognition||window.webkitSpeechRecognition)){ const R = new (window.SpeechRecognition||window.webkitSpeechRecognition)(); R.lang='en-US'; R.maxAlternatives=1; mic.onclick=()=>{try{R.start();}catch{}}; R.onresult=e=>{form.elements.topic.value=e.results[0][0].transcript;build();} }else if(mic){mic.style.display='none';} } /* ----- Generate (AJAX) ----- */ if(form){ const spinner = document.getElementById('spinner'), secEl = document.getElementById('sec'), rawArea = document.getElementById('raw'), render = document.getElementById('render'), results = document.getElementById('results'), copyRaw = document.getElementById('copyRaw'), copyRend = document.getElementById('copyRender'); let timer; form.addEventListener('submit',e=>{ e.preventDefault(); const fd = new FormData(form); fd.append('model',document.getElementById('modelSel').value); spinner.classList.add('active'); let s=0; secEl.textContent='0'; timer=setInterval(()=>{secEl.textContent=++s},1000); fetch('?ajax=1',{method:'POST',body:fd}) .then(r=>r.json()) .then(j=>{ clearInterval(timer); spinner.classList.remove('active'); if(j.error){alert(j.error);return;} rawArea.value=j.html; render.innerHTML=j.html; results.style.display=''; [copyRaw,copyRend].forEach(b=>b.onclick=()=>navigator.clipboard.writeText( b===copyRaw?rawArea.value:render.innerHTML).then(()=>flash(b))); render.scrollIntoView({behavior:'smooth'}); }) .catch(err=>{clearInterval(timer);spinner.classList.remove('active');alert('Error: '+err);}); }); } function flash(btn){const t=btn.textContent;btn.textContent='Copied!';setTimeout(()=>btn.textContent=t,1200);} })(); </script> </body></html>
Save changes
Create folder
writable 0777
Create
Cancel