|
<!DOCTYPE html>
|
|
<html lang="ja">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>LLM Client</title>
|
|
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
|
|
crossorigin="anonymous">
|
|
<style>
|
|
#mainContent textarea.form-control {
|
|
min-height: 40vh;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.accordion-button:not(.collapsed) {
|
|
background-color: #212529;
|
|
color: #fff;
|
|
}
|
|
|
|
.navbar-toggler {
|
|
display: block !important;
|
|
}
|
|
|
|
|
|
@keyframes redFlashBg {
|
|
|
|
0%,
|
|
100% {
|
|
background-color: initial;
|
|
}
|
|
|
|
50% {
|
|
background-color: rgba(255, 0, 0, 0.5);
|
|
}
|
|
}
|
|
|
|
@keyframes redFlashFg {
|
|
|
|
0%,
|
|
100% {
|
|
color: initial;
|
|
}
|
|
|
|
50% {
|
|
color: red;
|
|
}
|
|
}
|
|
|
|
.red-flash-bg {
|
|
animation: redFlashBg 0.5s infinite;
|
|
}
|
|
|
|
.red-flash-fg {
|
|
animation: redFlashFg 0.5s infinite;
|
|
}
|
|
|
|
@keyframes greenFlashBg {
|
|
|
|
0%,
|
|
100% {
|
|
background-color: initial;
|
|
}
|
|
|
|
50% {
|
|
background-color: rgba(0, 255, 0, 0.5);
|
|
}
|
|
}
|
|
|
|
@keyframes greenFlashFg {
|
|
|
|
0%,
|
|
100% {
|
|
color: initial;
|
|
}
|
|
|
|
50% {
|
|
color: green;
|
|
}
|
|
}
|
|
|
|
.green-flash-bg {
|
|
animation: greenFlashBg 0.5s infinite;
|
|
}
|
|
|
|
.green-flash-fg {
|
|
animation: greenFlashFg 0.5s infinite;
|
|
}
|
|
|
|
|
|
.navbar {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
|
|
#mainContent {
|
|
padding-top: 1rem;
|
|
}
|
|
|
|
@media (max-width: 991.98px) {
|
|
.navbar-brand {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.btn-sm {
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1400px) {}
|
|
|
|
|
|
#indexOffcanvas .offcanvas-body ul {
|
|
padding-left: 0;
|
|
}
|
|
|
|
#indexOffcanvas .offcanvas-body li {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
#indexOffcanvas .offcanvas-body a {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
#indexOffcanvas .offcanvas-body .toggle-btn {
|
|
padding: 0.1rem 0.3rem;
|
|
font-size: 0.8rem;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body data-bs-theme="dark">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12 text-center">
|
|
<a class="navbar-brand" href="#">
|
|
<i class="fa-brands fa-google"></i>
|
|
<i class="fa-solid fa-robot d-none"></i>
|
|
LLM Client
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="row w-100">
|
|
<div class="col-3 d-flex justify-content-end">
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas"
|
|
data-bs-target="#settingsOffcanvas" aria-controls="settingsOffcanvas">
|
|
<i class="fas fa-list"></i>
|
|
</button>
|
|
</div>
|
|
<div class="col-6 d-flex justify-content-center">
|
|
<button id="prevAccordion" class="btn btn-outline-light">
|
|
<i class="fas fa-chevron-left"></i> 前へ
|
|
</button>
|
|
<button id="requestButton" class="btn btn-primary" onclick="Request()">
|
|
生成
|
|
</button>
|
|
<button id="stopButton" class="btn btn-danger d-none" onclick="stopGeneration()">
|
|
中止
|
|
</button>
|
|
<button id="nextAccordion" class="btn btn-outline-light">
|
|
次へ <i class="fas fa-chevron-right"></i>
|
|
</button>
|
|
</div>
|
|
<div class="col-3 d-flex justify-content-start">
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#indexOffcanvas"
|
|
aria-controls="indexOffcanvas">
|
|
<i class="fas fa-book"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="container">
|
|
<div class="row justify-content-center">
|
|
<div id="mainContent">
|
|
<div class="mt-3">
|
|
<div class="accordion" id="mainAccordion">
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#promptsCollapse">
|
|
基本設定
|
|
</button>
|
|
</h2>
|
|
<div id="promptsCollapse" class="accordion-collapse collapse"
|
|
data-bs-parent="#mainAccordion">
|
|
<div class="accordion-body">
|
|
<textarea class="form-control mb-2" id="generatePrompt"
|
|
placeholder="システムプロンプトを入力"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#content1Collapse">
|
|
小説内容 (入力)
|
|
</button>
|
|
</h2>
|
|
<div id="content1Collapse" class="accordion-collapse collapse"
|
|
data-bs-parent="#mainAccordion">
|
|
<div class="accordion-body">
|
|
<textarea class="form-control mb-2" id="novelContent1"
|
|
placeholder="ここに小説の本文を入力してください"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#nextPromptCollapse">
|
|
次の展開
|
|
</button>
|
|
</h2>
|
|
<div id="nextPromptCollapse" class="accordion-collapse collapse"
|
|
data-bs-parent="#mainAccordion">
|
|
<div class="accordion-body">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<textarea class="form-control me-2" id="nextPrompt" placeholder="次の展開を指示"
|
|
rows="1"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#content2Collapse">
|
|
小説内容 (出力)
|
|
</button>
|
|
</h2>
|
|
<div id="content2Collapse" class="accordion-collapse collapse"
|
|
data-bs-parent="#mainAccordion">
|
|
<div class="accordion-body">
|
|
<textarea class="form-control" id="novelContent2"
|
|
placeholder="ここに続きが表示されます。"></textarea>
|
|
<button id="moveToInputButton" class="btn btn-primary mt-2" onclick="moveToInput()">
|
|
入力欄に追記
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-12 d-flex justify-content-end">
|
|
<input type="text" class="form-control d-inline-block w-auto me-2" id="savedTitle"
|
|
placeholder="タイトル">
|
|
<button id="saveButton" class="btn btn-secondary me-2" onclick="saveToJson()">
|
|
保存
|
|
</button>
|
|
<button id="loadButton" class="btn btn-secondary" onclick="loadFromJson()">
|
|
読込
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="offcanvas offcanvas-start" tabindex="-1" id="settingsOffcanvas"
|
|
aria-labelledby="settingsOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="settingsOffcanvasLabel">設定</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<div class="accordion" id="settingsAccordion">
|
|
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#apiSettings">
|
|
API設定
|
|
</button>
|
|
</h2>
|
|
<div id="apiSettings" class="accordion-collapse collapse show" data-bs-parent="#settingsAccordion">
|
|
<div class="accordion-body">
|
|
<h5>エンドポイント</h5>
|
|
<select class="form-select mb-2" id="endpointSelect">
|
|
<option value="models/gemini-1.5-pro-002">gemini-1.5-pro-002</option>
|
|
<option value="models/gemini-1.5-flash-002">gemini-1.5-flash-002</option>
|
|
<option value="models/gemini-1.5-pro-latest">gemini-1.5-pro-latest</option>
|
|
<option value="models/gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
|
|
<option value="restart">Restart</option>
|
|
<option value="openai">OpenAI Compatible</option>
|
|
</select>
|
|
|
|
<h5>Gemini API Key</h5>
|
|
<p class="text-muted">エンドポイントがGeminiの場合は必須</p>
|
|
<input type="text" class="form-control mb-2" id="geminiApiKey" placeholder="Gemini API Key">
|
|
|
|
<h5 class="mt-3">OpenAI Compatible設定</h5>
|
|
<p class="text-muted">エンドポイントがOpenAI Compatibleの場合は必須</p>
|
|
<input type="text" class="form-control mb-2" id="openaiEndpoint"
|
|
placeholder="OpenAI Endpoint">
|
|
<textarea class="form-control mb-2" id="openaiHeaders"
|
|
placeholder="OpenAI Headers (JSON形式)"></textarea>
|
|
<textarea class="form-control mb-2" id="openaiJsonBody"
|
|
placeholder="OpenAI Body (JSON形式)"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#generationSettings">
|
|
生成設定
|
|
</button>
|
|
</h2>
|
|
<div id="generationSettings" class="accordion-collapse collapse"
|
|
data-bs-parent="#settingsAccordion">
|
|
<div class="accordion-body">
|
|
<div class="mb-2">
|
|
<label for="characterCount" class="form-label">文字数</label>
|
|
<input type="range" class="form-range" id="characterCount" min="64" max="8192"
|
|
value="4096" step="64">
|
|
<input type="number" class="form-control" id="characterCountInput" value="4096" min="64"
|
|
max="8192" step="64">
|
|
</div>
|
|
<div class="mb-2">
|
|
<label for="encodeLength" class="form-label">エンコード長</label>
|
|
<input type="range" class="form-range" id="encodeLength" placeholder="エンコード長" min="1"
|
|
max="16" value="4">
|
|
<input type="number" class="form-control" id="encodeLengthInput" placeholder="エンコード長"
|
|
min="1" max="16" value="4">
|
|
</div>
|
|
<div class="form-check mb-2 form-switch">
|
|
<input class="form-check-input" type="checkbox" id="summerizedPromptToggle">
|
|
<label class="form-check-label" for="summerizedPromptToggle">Summerize</label>
|
|
</div>
|
|
<div class="form-check mb-2 form-switch">
|
|
<input class="form-check-input" type="checkbox" id="partialEncodeToggle">
|
|
<label class="form-check-label" for="partialEncodeToggle">Encode</label>
|
|
</div>
|
|
<div class="form-check mb-2 form-switch">
|
|
<input class="form-check-input" type="checkbox" id="streamToggle" checked>
|
|
<label class="form-check-label" for="streamToggle">Stream</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#otherSettings">
|
|
その他の設定
|
|
</button>
|
|
</h2>
|
|
<div id="otherSettings" class="accordion-collapse collapse" data-bs-parent="#settingsAccordion">
|
|
<div class="accordion-body">
|
|
<h5>メモ欄</h5>
|
|
<textarea class="form-control mb-2" id="memo" placeholder="メモ用項目。生成に一切影響しません。"
|
|
rows="5"></textarea>
|
|
|
|
<button id="formatTextButton" class="btn btn-primary mb-2" onclick="formatText()">
|
|
<i class="fa-solid fa-align-left"></i> 改行を整理
|
|
</button>
|
|
|
|
<h5 class="mt-3">デバッグ</h5>
|
|
<button id="debugButton" class="btn btn-secondary mb-2" onclick="debugPrompt()">
|
|
<i class="fa-solid fa-bug"></i> payload
|
|
</button>
|
|
<button id="summaryButton" class="btn btn-secondary mb-2" onclick="console.log(createSummarizedText())">
|
|
<i class="fa-solid fa-bug"></i> 要約
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="offcanvas offcanvas-end" tabindex="-1" id="indexOffcanvas" aria-labelledby="indexOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="indexOffcanvasLabel">目次</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
<script src="gemini.js"></script>
|
|
</body>
|
|
|
|
</html> |