gggg / templates /index.html
enotkrutoy's picture
Update templates/index.html
6510699 verified
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Улучшенный Хакерский Веб Интерфейс</title>
<style>
body {
background-color: #1e1e1e;
color: #ffffff;
font-family: 'Courier New', Courier, monospace;
margin: 0;
padding: 20px;
}
h1 {
color: #ff4d4d;
}
#input-container {
margin-bottom: 20px;
}
input, textarea {
width: 100%;
padding: 10px;
margin-bottom: 10px;
background-color: #333;
color: #fff;
border: none;
border-radius: 5px;
box-sizing: border-box;
}
button {
padding: 10px 20px;
background-color: #ff4d4d;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #cc3333;
}
#loading-indicator {
display: none;
color: #ffcc00;
font-weight: bold;
margin-bottom: 10px;
}
#response-container, #final-answer {
margin-top: 20px;
white-space: pre-wrap;
}
.step {
border-bottom: 1px solid #555;
padding: 10px 0;
}
.step:last-child {
border-bottom: none;
}
.step-title {
font-weight: bold;
color: #ffcc00;
}
.error {
color: #ff4d4d;
font-weight: bold;
margin-top: 20px;
}
</style>
</head>
<body>
<h1>Улучшенный Хакерский Веб Интерфейс</h1>
<div id="input-container">
<input type="text" id="api-endpoint" placeholder="Введите URL API (например, https://your-api.com/chat)" value="https://api.example.com/chat/completions" />
<input type="text" id="api-key" placeholder="Введите ключ API (если требуется)" />
<textarea id="prompt" placeholder="Введите запрос..." rows="4"></textarea>
<textarea id="context" placeholder="Введите контекст (необязательно)..." rows="2"></textarea>
<button id="start-btn">Запустить генерацию</button>
<div id="loading-indicator">Загрузка...</div>
</div>
<div id="response-container"></div>
<div id="final-answer"></div>
<script>
// Конфигурация
const CONFIG = {
DEFAULT_MAX_TOKENS: 6000,
FINAL_MAX_TOKENS: 6000,
RETRY_DELAY: 1000, // в мс
MAX_RETRIES: 3,
MODELS: {
intermediate: "qwen-2.5-32b",
final: "deepseek-r1-distill-llama-70b"
},
TEMPERATURE: 0.5
};
// Асинхронная функция задержки
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Функция валидации ввода
function validateInputs() {
const apiEndpoint = document.getElementById("api-endpoint").value.trim();
const prompt = document.getElementById("prompt").value.trim();
if (!apiEndpoint) {
throw new Error("Введите URL API!");
}
if (!prompt) {
throw new Error("Введите запрос!");
}
return { apiEndpoint, prompt };
}
// Парсинг JSON-ответа с валидацией ключей
function parseJsonResponse(rawResponse) {
try {
const parsed = JSON.parse(rawResponse);
const requiredKeys = ["title", "content", "next_action"];
for (const key of requiredKeys) {
if (!(key in parsed)) {
throw new Error(`Отсутствует ключ "${key}"`);
}
}
return parsed;
} catch (e) {
throw new Error(`Invalid JSON: ${e.message}, content: ${rawResponse}`);
}
}
// Функция вызова API с повторными попытками и улучшенной обработкой ошибок
async function makeApiCall(messages, maxTokens, isFinalAnswer = false) {
const apiEndpoint = document.getElementById("api-endpoint").value.trim() || "https://api.example.com/chat/completions";
const model = isFinalAnswer ? CONFIG.MODELS.final : CONFIG.MODELS.intermediate;
const responseType = isFinalAnswer ? "text" : "json_object";
let attempt = 0;
let lastError = null;
while (attempt < CONFIG.MAX_RETRIES) {
try {
const response = await fetch(apiEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": document.getElementById("api-key").value.trim() || ""
},
body: JSON.stringify({
model: model,
messages: messages,
max_tokens: maxTokens,
temperature: CONFIG.TEMPERATURE,
response_format: { type: responseType }
})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Ошибка API: ${response.status} ${response.statusText}. Подробности: ${errorText}`);
}
const data = await response.json();
const messageContent = data.choices[0].message.content;
if (isFinalAnswer) {
return messageContent;
} else {
return parseJsonResponse(messageContent);
}
} catch (error) {
lastError = error;
console.error(`Попытка ${attempt + 1} не удалась:`, error);
attempt++;
if (attempt < CONFIG.MAX_RETRIES) {
await delay(CONFIG.RETRY_DELAY);
}
}
}
if (isFinalAnswer) {
return `Error: Не удалось получить финальный ответ за ${CONFIG.MAX_RETRIES} попыток. Ошибка: ${lastError.message}`;
} else {
return {
title: "Error",
content: `Не удалось сгенерировать шаг за ${CONFIG.MAX_RETRIES} попыток. Ошибка: ${lastError.message}`,
next_action: "final_answer"
};
}
}
// Генерация цепочки рассуждений с отображением шагов
async function generateResponse(prompt, context) {
const responseContainer = document.getElementById("response-container");
const finalAnswerContainer = document.getElementById("final-answer");
responseContainer.innerHTML = "";
finalAnswerContainer.innerHTML = "";
const systemMessage = `Вы – интеллектуальный помощник, эксперт по разработке на Python, который анализирует и объясняет свои рассуждения шаг за шагом на русском языке.
Формат ответа: строгий JSON без дополнительного текста.
Обязательные ключи:
"title": краткое название шага,
"content": описание действий,
"next_action": "continue" или "final_answer".
Пример:
{"title": "Анализ задачи", "content": "Выделение ключевых элементов...", "next_action": "continue"}
Дополнительные требования: используйте русский язык и избегайте Unicode-кодировок (например, пишите "Привет", а не "\\u041f\\u0440\\u0438...")`;
const userContent = context ? `Я хотел бы узнать про autogen. Контекст: ${context}. ${prompt}` : prompt;
const messages = [
{ role: "system", content: systemMessage },
{ role: "user", content: userContent },
{ role: "assistant", content: "Спасибо! Начинаю анализ..." }
];
let stepCount = 1;
let totalThinkingTime = 0;
while (stepCount <= 25) {
document.getElementById("loading-indicator").style.display = "block";
const stepStart = performance.now();
const stepData = await makeApiCall(messages, CONFIG.DEFAULT_MAX_TOKENS);
const elapsed = (performance.now() - stepStart) / 1000;
totalThinkingTime += elapsed;
document.getElementById("loading-indicator").style.display = "none";
const stepDiv = document.createElement("div");
stepDiv.className = "step";
stepDiv.innerHTML = `<div class="step-title">Step ${stepCount}: ${stepData.title}</div>
<div>${stepData.content}</div>
<div>(Время: ${elapsed.toFixed(2)} сек)</div>`;
responseContainer.appendChild(stepDiv);
messages.push({ role: "assistant", content: JSON.stringify(stepData, null, 2) });
if (stepData.next_action === "final_answer") break;
stepCount++;
}
messages.push({
role: "user",
content: "Предоставьте окончательный ответ без формата JSON, сохранив исходное форматирование из подсказки."
});
document.getElementById("loading-indicator").style.display = "block";
const finalStart = performance.now();
const finalAnswer = await makeApiCall(messages, CONFIG.FINAL_MAX_TOKENS, true);
const finalElapsed = (performance.now() - finalStart) / 1000;
totalThinkingTime += finalElapsed;
document.getElementById("loading-indicator").style.display = "none";
const finalDiv = document.createElement("div");
finalDiv.innerHTML = `<div class="step-title">Final Answer</div>
<div>${finalAnswer}</div>
<div>(Время: ${finalElapsed.toFixed(2)} сек)</div>
<div>Общее время обработки: ${totalThinkingTime.toFixed(2)} сек</div>`;
finalAnswerContainer.appendChild(finalDiv);
}
// Обработчик события запуска
document.getElementById("start-btn").addEventListener("click", () => {
try {
const { apiEndpoint, prompt } = validateInputs();
generateResponse(prompt, document.getElementById("context").value.trim()).catch(error => {
document.getElementById("response-container").innerHTML = `<div class="error">Ошибка: ${error.message}</div>`;
});
} catch (e) {
alert(e.message);
}
});
</script>
</body>
</html>