fix: local generation, regenerate button, API via ?api=
This commit is contained in:
parent
43d99a9468
commit
2c520a96c0
159
script.js
159
script.js
@ -1,4 +1,6 @@
|
|||||||
const API_URL = window.location.origin + '/api';
|
// Настройка: если запустили server.py на другом хосте/порте,
|
||||||
|
// укажите URL здесь или добавьте ?api=http://host:8000 к URL страницы
|
||||||
|
const API_URL = new URLSearchParams(window.location.search).get('api') || '';
|
||||||
|
|
||||||
const promptInput = document.getElementById('promptInput');
|
const promptInput = document.getElementById('promptInput');
|
||||||
const tempSlider = document.getElementById('tempSlider');
|
const tempSlider = document.getElementById('tempSlider');
|
||||||
@ -10,94 +12,113 @@ const generate5Btn = document.getElementById('generate5Btn');
|
|||||||
const outputArea = document.getElementById('outputArea');
|
const outputArea = document.getElementById('outputArea');
|
||||||
const statusMsg = document.getElementById('statusMsg');
|
const statusMsg = document.getElementById('statusMsg');
|
||||||
|
|
||||||
tempSlider.addEventListener('input', () => {
|
tempSlider.addEventListener('input', () => { tempVal.textContent = tempSlider.value; });
|
||||||
tempVal.textContent = tempSlider.value;
|
topkSlider.addEventListener('input', () => { topkVal.textContent = topkSlider.value; });
|
||||||
});
|
|
||||||
|
|
||||||
topkSlider.addEventListener('input', () => {
|
|
||||||
topkVal.textContent = topkSlider.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
generateBtn.addEventListener('click', () => generate(1));
|
generateBtn.addEventListener('click', () => generate(1));
|
||||||
generate5Btn.addEventListener('click', () => generate(5));
|
generate5Btn.addEventListener('click', () => generate(5));
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Client-side clickbait generator (fallback / default)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const TEMPLATES = [
|
||||||
|
'этот секрет знают единицы',
|
||||||
|
'врачи в шоке от этого открытия',
|
||||||
|
'ты не поверишь что произошло дальше',
|
||||||
|
'всего один ингредиент меняет всё',
|
||||||
|
'вот почему никто не говорит об этом',
|
||||||
|
'результат превзошёл все ожидания',
|
||||||
|
'это должен знать каждый',
|
||||||
|
'никто не ожидал такого поворота',
|
||||||
|
'учёные озадачены этим феноменом',
|
||||||
|
'это изменит вашу жизнь навсегда',
|
||||||
|
'вы будете в шоке от правды',
|
||||||
|
'самое важное о чём молчат СМИ',
|
||||||
|
'это открытие перевернуло науку',
|
||||||
|
'простые вещи которые творят чудеса',
|
||||||
|
'теперь это знает весь мир',
|
||||||
|
'о чём вам не расскажут в школе',
|
||||||
|
'главный секрет успешных людей',
|
||||||
|
'это работает безотказно',
|
||||||
|
'вы упускаете это каждый день',
|
||||||
|
'пора узнать правду'
|
||||||
|
];
|
||||||
|
|
||||||
|
const PREFIXES = ['', 'невероятно но ', 'шокирующе но ', 'оказывается ', 'представьте себе '];
|
||||||
|
|
||||||
|
function pick(arr, seed) {
|
||||||
|
const idx = Math.abs(seed * 7 + seed * seed * 31) % arr.length;
|
||||||
|
return arr[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
function localGenerate(prompt, temperature, top_k, count) {
|
||||||
|
const now = Date.now();
|
||||||
|
const results = [];
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const seed = now + i * 137 + Math.floor(temperature * 100) + top_k;
|
||||||
|
const prefix = pick(PREFIXES, seed + 3);
|
||||||
|
const template = prompt
|
||||||
|
? `${prompt} — ${pick(TEMPLATES, seed + 7)}`
|
||||||
|
: pick(TEMPLATES, seed + 11);
|
||||||
|
const extra = temperature > 1.3
|
||||||
|
? (pick(['невероятно', 'шокирующе', 'фантастически'], seed + 19) + ' ')
|
||||||
|
: '';
|
||||||
|
results.push(prefix + extra + template);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Main generation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async function generate(count) {
|
async function generate(count) {
|
||||||
const prompt = promptInput.value.trim();
|
const prompt = promptInput.value.trim();
|
||||||
const temperature = parseFloat(tempSlider.value);
|
const temperature = parseFloat(tempSlider.value);
|
||||||
const top_k = parseInt(topkSlider.value);
|
const top_k = parseInt(topkSlider.value);
|
||||||
|
|
||||||
outputArea.innerHTML = '';
|
outputArea.innerHTML = '';
|
||||||
statusMsg.textContent = 'Генерация...';
|
statusMsg.textContent = '⚡ Генерируем...';
|
||||||
statusMsg.className = 'status-msg';
|
statusMsg.className = 'status-msg';
|
||||||
|
|
||||||
try {
|
let texts;
|
||||||
const res = await fetch(`${API_URL}/generate`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
prompt,
|
|
||||||
temperature,
|
|
||||||
top_k,
|
|
||||||
num_samples: count
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
if (API_URL) {
|
||||||
const err = await res.json().catch(() => ({}));
|
try {
|
||||||
throw new Error(err.detail || `Ошибка ${res.status}`);
|
const res = await fetch(`${API_URL}/generate`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ prompt, temperature, top_k, num_samples: count })
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const data = await res.json();
|
||||||
|
texts = data.texts;
|
||||||
|
} catch {
|
||||||
|
texts = localGenerate(prompt, temperature, top_k, count);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
const data = await res.json();
|
texts = localGenerate(prompt, temperature, top_k, count);
|
||||||
statusMsg.textContent = '';
|
|
||||||
statusMsg.className = 'status-msg';
|
|
||||||
|
|
||||||
data.texts.forEach((text, i) => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.className = 'gen-output-item';
|
|
||||||
if (count > 1) {
|
|
||||||
div.innerHTML = `<span class="gen-badge">#${i + 1}</span>${text}...😱`;
|
|
||||||
} else {
|
|
||||||
div.textContent = `${text}...😱`;
|
|
||||||
}
|
|
||||||
outputArea.appendChild(div);
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
statusMsg.textContent = '❌ Сервер недоступен. Запустите API: python server.py';
|
|
||||||
statusMsg.className = 'status-msg error';
|
|
||||||
fallbackGenerate(count, prompt, temperature, top_k);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function fallbackGenerate(count, prompt, temperature, top_k) {
|
statusMsg.textContent = '';
|
||||||
const templates = [
|
statusMsg.className = 'status-msg';
|
||||||
prompt
|
|
||||||
? `${prompt} — этот секрет знают единицы`
|
|
||||||
: 'Этот секрет знают единицы',
|
|
||||||
prompt
|
|
||||||
? `${prompt} — врачи в шоке от открытия`
|
|
||||||
: 'Врачи в шоке от этого открытия',
|
|
||||||
prompt
|
|
||||||
? `${prompt} — ты не поверишь что произошло`
|
|
||||||
: 'Ты не поверишь что произошло дальше',
|
|
||||||
prompt
|
|
||||||
? `${prompt} — всего один ингредиент меняет всё`
|
|
||||||
: 'Всего один ингредиент меняет всё',
|
|
||||||
prompt
|
|
||||||
? `${prompt} — вот почему никто не говорит об этом`
|
|
||||||
: 'Вот почему никто не говорит об этом'
|
|
||||||
];
|
|
||||||
|
|
||||||
outputArea.innerHTML = '';
|
texts.forEach((text, i) => {
|
||||||
for (let i = 0; i < count && i < templates.length; i++) {
|
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'gen-output-item';
|
div.className = 'gen-output-item';
|
||||||
if (count > 1) {
|
div.style.animationDelay = `${i * 0.08}s`;
|
||||||
div.innerHTML = `<span class="gen-badge">#${i + 1}</span>${templates[i]}...😱`;
|
const label = count > 1 ? `<span class="gen-badge">#${i + 1}</span>` : '';
|
||||||
} else {
|
div.innerHTML = `${label}${text}...😱`;
|
||||||
div.textContent = `${templates[i]}...😱`;
|
|
||||||
}
|
|
||||||
outputArea.appendChild(div);
|
outputArea.appendChild(div);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
// Regenerate button
|
||||||
|
const reBtn = document.createElement('button');
|
||||||
|
reBtn.className = 'btn btn-secondary btn-regenerate';
|
||||||
|
reBtn.textContent = '🔄 Сгенерировать ещё';
|
||||||
|
reBtn.addEventListener('click', () => generate(count));
|
||||||
|
outputArea.appendChild(reBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example tabs
|
// Example tabs
|
||||||
|
|||||||
11
style.css
11
style.css
@ -127,6 +127,17 @@ body {
|
|||||||
color: var(--cyan);
|
color: var(--cyan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-regenerate {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gen-output .btn-regenerate {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sections */
|
/* Sections */
|
||||||
.section {
|
.section {
|
||||||
padding: 80px 0;
|
padding: 80px 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user