Site Builder
Editing:
tools-promptinator-okkk.php
writable 0666
<?php /********************************************************************** * Promptinator — Business AI Tool * ------------------------------------------------------------------- * • Same secure cookie‑encrypted key storage as earlier versions * • UI re‑structured per July‑2025 design review **********************************************************************/ /* ============== 1. configuration & helpers ======================== */ define('COOKIE_NAME','openai_key'); define('COOKIE_TTL', 30*24*3600); // 30 days define('SECRET', __FILE__); // file‑bound key function enc(string $v):string{ $meth='aes-128-ctr'; $k=substr(hash('sha256',SECRET,true),0,16); $iv=random_bytes(openssl_cipher_iv_length($meth)); return base64_encode(openssl_encrypt($v,$meth,$k,0,$iv)."::$iv"); } function dec(string $c):string{ [$ct,$iv]=explode('::',base64_decode($c),2)+['','']; $meth='aes-128-ctr'; $k=substr(hash('sha256',SECRET,true),0,16); return openssl_decrypt($ct,$meth,$k,0,$iv)?:''; } /* ============== 2. save / delete key ============================== */ $msg=''; 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'=>5 ]]); if(@file_get_contents('https://api.openai.com/v1/models',false,$ctx)){ setcookie(COOKIE_NAME,enc($raw),time()+COOKIE_TTL,'/','',isset($_SERVER['HTTPS']),true); header('Location: '.$_SERVER['REQUEST_URI']);exit; }else $msg='❌ Invalid key.'; } if(isset($_GET['delete_key'])){ setcookie(COOKIE_NAME,'',time()-3600,'/','',isset($_SERVER['HTTPS']),true); header('Location: '.$_SERVER['PHP_SELF']);exit; } /* ============== 3. query params / defaults ======================== */ $models = ['gpt-3.5-turbo','gpt-4o-mini','gpt-4']; $controlOpts = ['B','C','Dtxt']; $model = in_array($_GET['model']??'',$models)?$_GET['model']:'gpt-3.5-turbo'; $type = in_array($_GET['type'] ??'',$controlOpts)?$_GET['type'] :'B'; $scope = $_GET['scope'] ?? 'general'; $word = trim($_GET['word'] ?? ''); $count = max(1,min(15,intval($_GET['count']??5))); $keyCookie=$_COOKIE[COOKIE_NAME]??''; $key =$keyCookie?dec($keyCookie):''; /* ============== 4. generate candidate list (unchanged) ============ */ $items=[]; if($key && $word && in_array($type,['B','C','Dtxt'])){ $payload=[ 'model'=>$model, 'messages'=>[ ['role'=>'system','content'=>"You are a helpful assistant that replies ONLY with a comma‑separated list of {$scope} variations, no extra words."], ['role'=>'user','content'=>"List up to {$count} {$scope} variations for '{$word}'"] ], 'temperature'=>0.3, 'max_tokens'=>60, 'stop'=>["\n"] ]; $ch=curl_init('https://api.openai.com/v1/chat/completions'); curl_setopt_array($ch,[ CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.$key,'Content-Type: application/json'], CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>json_encode($payload), CURLOPT_TIMEOUT=>15 ]); $resp=curl_exec($ch); curl_close($ch); $raw=array_filter(array_map('trim',explode(',',$resp?json_decode($resp,true)['choices'][0]['message']['content']:'') )); array_unshift($raw,$word); $items=array_slice(array_unique($raw),0,$count); } ?> <!doctype html> <html lang="en"><head><meta charset="utf-8"> <title>Promptinator – AI Toolbox</title> <meta name=viewport content="width=device-width,initial-scale=1"> <style> :root{ --bg:#f1f4fb; --brand:#004cff; --brand-d:#0841c4; --card:#fff; --shadow:0 6px 30px rgba(0,0,0,.08); --dark:#121720;--green:#5af287; --gold:#ffb63b; --red:#e24d4b; --radius:26px; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif; } /* ======= layout =================================================== */ body{margin:0;background:var(--bg);color:#111;min-height:100vh;display:flex;flex-direction:column} .top-bar{background:var(--dark);color:#fff;padding:.9rem 1.4rem;display:flex;flex-wrap:wrap;gap:.9rem;align-items:center} .top-bar h1{margin:0;font-size:1.25rem;color:var(--gold);flex:none} .top-bar form{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;margin-left:auto} .top-bar input[type=password]{padding:.55rem .8rem;border-radius:9px;border:none;font-size:.95rem;width:210px} .top-bar select{padding:.55rem .8rem;border-radius:9px;border:none;background:#1e2430;color:#fff;font-size:.95rem} .top-bar button{padding:.55rem 1rem;border:none;border-radius:8px;background:var(--brand);color:#fff;cursor:pointer} .status-pill{display:flex;align-items:center;gap:.35ch;font-weight:600;font-size:.9rem} .status-pill i{display:inline-block;width:.55rem;height:.55rem;border-radius:50%} .status-ok i{background:var(--green)} .status-bad{color:var(--red)} .del-key{color:var(--red);font-weight:700;margin-left:.4rem;cursor:pointer} main{width:100%;max-width:900px;margin:2.2rem auto;padding:0 1rem;flex:1} .tool-card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:2rem;display:grid;gap:1.6rem} /* ======= form ===================================================== */ #cfg{display:grid;gap:1.4rem;grid-template-columns:1fr 1fr} #cfg .full{grid-column:1/-1} label{font-weight:600;font-size:.95rem} select,input[type=text]{width:100%;padding:.7rem 1rem;border:1px solid #d0d6e7;border-radius:10px;font-size:1rem} select:focus,input:focus{outline:none;border-color:var(--brand)} #gen{justify-self:start;padding:.75rem 2rem;background:var(--brand);color:#fff;border:none;border-radius:10px;font-size:1rem;cursor:pointer} #tokens{display:flex;flex-wrap:wrap;gap:.5rem} .token{position:relative;background:#e8efff;color:#003c9e;padding:.45rem 1.4rem .45rem .9rem;border-radius:20px;font-weight:600} .token .remove{position:absolute;right:4px;top:1px;cursor:pointer;color:var(--red)} #shortcode{background:#0d111a;color:#fff;border-radius:10px;padding:1.3rem;font-family:ui-monospace,monospace;font-size:.95rem;white-space:pre-wrap;word-break:break-all} .action-row{display:flex;gap:1rem} .action-row button{padding:.65rem 1.3rem;background:var(--brand);color:#fff;border:none;border-radius:9px;cursor:pointer;flex:1} .action-row button:hover{background:var(--brand-d)} .action-row .csv{display:none} /* ======= welcome ================================================== */ .welcome{padding:3rem 2rem;text-align:center} .welcome h2{margin-top:0} .welcome p{max-width:500px;margin:.7rem auto 1rem} /* ======= responsive ============================================== */ @media(max-width:640px){ #cfg{grid-template-columns:1fr} #gen{justify-self:stretch;text-align:center} .top-bar form{margin-left:0;width:100%} } </style> </head> <body> <!-- ======= NAV / BREADCRUMBS (uses same style as earlier pages) ======= --> <div style="background:#eee;padding:.6rem 1rem;font-weight:600"> <a href="/members/dashboard.php" style="color:#004cff;text-decoration:none">Dashboard</a> » <a href="/ai-tools/tools.php" style="color:#004cff;text-decoration:none">AI Toolbox</a> » Promptinator <a href="/<?=$_SESSION['slug']??''?>/" style="float:right">View Site</a> </div> <!-- ==================== TOP BAR (key & model) ======================== --> <div class="top-bar"> <h1>Promptinator</h1> <?php if(!$key): ?> <form method="post" autocomplete="off"> <input type="password" name="api_key" placeholder="sk-..." required> <button name="save_key">Save Key</button> </form> <?php if($msg): ?><span class="status-pill status-bad"><?=$msg?></span><?php endif;?> <?php else: ?> <div class="status-pill status-ok"> <i></i> API key saved <a href="?delete_key=1" class="del-key" title="Delete key">×</a> </div> <form id="modelForm" method="get"> <input type="hidden" name="type" value="<?=htmlspecialchars($type)?>"> <input type="hidden" name="word" value="<?=htmlspecialchars($word)?>"> <input type="hidden" name="scope" value="<?=htmlspecialchars($scope)?>"> <input type="hidden" name="count" value="<?=$count?>"> <select name="model" onchange="this.form.submit()"> <?php foreach($models as $m): ?> <option value="<?=$m?>" <?=$m===$model?'selected':''?>><?=$m?></option> <?php endforeach;?> </select> </form> <?php endif;?> </div> <main> <?php if(!$key): ?> <div class="tool-card welcome"> <h2>Get started</h2> <p>Save your OpenAI API key in the bar above to unlock Promptinator.</p> </div> <?php else: ?> <div class="tool-card"> <!-- ============= GENERATION FORM ============ --> <h2>Generate options</h2> <form id="cfg" method="get" autocomplete="off"> <input type="hidden" name="model" value="<?=htmlspecialchars($model)?>"> <input type="hidden" id="typeHidden" name="type" value="<?=htmlspecialchars($type)?>"> <div class="full"> <label for="seed">Seed word <span id="mic-btn" style="cursor:pointer">🎤</span></label> <input id="seed" name="word" value="<?=htmlspecialchars($word)?>" placeholder="e.g. shoes"> </div> <div> <label for="scope">Relation</label> <select id="scope" name="scope"> <?php foreach(['general','broad','narrow','longtail','shorttail'] as $rel): ?> <option value="<?=$rel?>" <?=$rel===$scope?'selected':''?>><?=$rel?></option> <?php endforeach;?> </select> </div> <div> <label for="count">Count</label> <select id="count" name="count"> <?php for($i=1;$i<=15;$i++): ?> <option value="<?=$i?>" <?=$i===$count?'selected':''?>><?=$i?></option> <?php endfor;?> </select> </div> <div> <label for="ctype">Control type</label> <select id="ctype"> <option value="B" <?=$type==='B'?'selected':''?>>Radio</option> <option value="C" <?=$type==='C'?'selected':''?>>Checkbox</option> <option value="Dtxt" <?=$type==='Dtxt'?'selected':''?>>Dropdown Text</option> </select> </div> <button id="gen" class="full">Generate</button> </form> <!-- ============= TOKENS / DEFAULT / SHORTCODE ============ --> <div id="tokens-area" style="<?= $items? '':'display:none'?>"> <h3>Tokens</h3> <div id="tokens"></div> <label for="def">Default value</label> <select id="def" style="width:100%;padding:.7rem 1rem;border:1px solid #d0d6e7;border-radius:10px"></select> <pre id="shortcode"></pre> <div class="action-row"> <button class="copy" onclick="copyTxt('shortcode')">Copy Shortcode</button> <button class="copy csv" id="csvBtn" onclick="copyCsv()">Copy CSV</button> </div> </div> </div> <?php endif;?> </main> <script> (()=>{ /* ---------- helpers ----------- */ const $=q=>document.querySelector(q); const items = <?=json_encode($items,JSON_UNESCAPED_SLASHES)?>; const tokensBox = $('#tokens'); const defSel = $('#def'); const scEl = $('#shortcode'); const csvBtn = $('#csvBtn'); function renderTokens(){ tokensBox.innerHTML=''; items.forEach((t,i)=>{ const s=document.createElement('span');s.className='token';s.textContent=t; const x=document.createElement('span');x.className='remove';x.textContent='×'; x.onclick=()=>{items.splice(i,1);updateAll();}; s.appendChild(x);tokensBox.appendChild(s); }); } function renderDefault(){ defSel.innerHTML=''; items.forEach(t=>{ const o=document.createElement('option');o.value=t;o.textContent=t;defSel.appendChild(o); }); defSel.value=items[0]||''; } function updateShortcode(){ const t = $('#typeHidden').value; const ps = items.join('|'); const df = items[0]||''; const opt = $('#seed').value.trim()||'seed'; const prefix = (t==='Dtxt')?'D':t; scEl.textContent=`[${prefix}-${opt}-|${ps}|~${df}~]`; } function updateAll(){ renderTokens();renderDefault();updateShortcode(); $('#tokens-area').style.display = items.length?'block':'none'; csvBtn.style.display = items.length?'block':'none'; } /* ---------- initial ----------- */ updateAll(); /* ---------- plain‑JS control‑type switch (no reload) -------- */ $('#ctype').onchange=e=>{ $('#typeHidden').value=e.target.value; updateShortcode(); }; /* ---------- default picker re‑order ------------------------- */ defSel.onchange=()=>{ const v=defSel.value; const idx=items.indexOf(v); if(idx>0){items.splice(idx,1);items.unshift(v);} updateAll(); }; /* ---------- copy helpers ------------------------------------ */ window.copyTxt=id=>{ navigator.clipboard.writeText($( '#'+id ).textContent).then(()=>{ const btn=event.target;const old=btn.textContent;btn.textContent='✔ Copied'; setTimeout(()=>btn.textContent=old,1200); }); }; window.copyCsv=()=>{ navigator.clipboard.writeText(items.join(', ')).then(()=>{ const old=csvBtn.textContent;csvBtn.textContent='✔ Copied'; setTimeout(()=>csvBtn.textContent=old,1200); }); }; /* ---------- Mic (unchanged) --------------------------------- */ const mic = $('#mic-btn'); if(mic){ const SpeechRecognition = window.SpeechRecognition||window.webkitSpeechRecognition; if(!SpeechRecognition){mic.style.display='none';} else{ const rec=new SpeechRecognition();rec.lang='en-US';rec.interimResults=false; mic.onclick=()=>{ mic.textContent='🎤…'; try{rec.start();}catch{} }; rec.onresult=e=>{ $('#seed').value=e.results[0][0].transcript; mic.textContent='🎤';updateShortcode(); }; } } })(); </script> </body></html>
Save changes
Create folder
writable 0777
Create
Cancel