| <script lang="ts"> | |
| import type { GradioClient, TextGenerationParams, TextGenerationResult } from '$lib/types'; | |
| interface Props { | |
| client: GradioClient | null; | |
| } | |
| let { client = null }: Props = $props(); | |
| let params: TextGenerationParams = $state({ | |
| prompt: "", | |
| maxTokens: 200, | |
| temperature: 1.0, | |
| topP: 0.7, | |
| presencePenalty: 0.1, | |
| countPenalty: 0.1 | |
| }); | |
| let isGenerating = $state(false); | |
| let result: TextGenerationResult | null = $state(null); | |
| let error: string | null = $state(null); | |
| async function handleSubmit(e: Event) { | |
| e.preventDefault(); | |
| if (!client || !params.prompt.trim()) { | |
| error = "Please enter a prompt."; | |
| return; | |
| } | |
| isGenerating = true; | |
| error = null; | |
| result = null; | |
| try { | |
| const output = await client.predict(0, [ | |
| params.prompt, | |
| params.maxTokens, | |
| params.temperature, | |
| params.topP, | |
| params.presencePenalty, | |
| params.countPenalty | |
| ]); | |
| const generatedText = output.data[0]; | |
| result = { | |
| text: generatedText, | |
| prompt: params.prompt | |
| }; | |
| } catch (err) { | |
| console.error(err); | |
| error = `Text generation failed: ${err}`; | |
| } finally { | |
| isGenerating = false; | |
| } | |
| } | |
| </script> | |
| <form class="text-form" onsubmit={handleSubmit}> | |
| <h3>Generate Text with RWKV</h3> | |
| <label for="textPrompt">Prompt</label> | |
| <textarea | |
| id="textPrompt" | |
| bind:value={params.prompt} | |
| rows="4" | |
| placeholder="Enter your prompt here..." | |
| disabled={isGenerating} | |
| ></textarea> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label for="maxTokens">Max Tokens</label> | |
| <input | |
| type="number" | |
| id="maxTokens" | |
| bind:value={params.maxTokens} | |
| min="10" | |
| max="1000" | |
| step="10" | |
| disabled={isGenerating} | |
| /> | |
| </div> | |
| <div class="input-group"> | |
| <label for="temperature">Temperature</label> | |
| <input | |
| type="number" | |
| id="temperature" | |
| bind:value={params.temperature} | |
| min="0.2" | |
| max="2.0" | |
| step="0.1" | |
| disabled={isGenerating} | |
| /> | |
| </div> | |
| </div> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label for="topP">Top P</label> | |
| <input | |
| type="number" | |
| id="topP" | |
| bind:value={params.topP} | |
| min="0.0" | |
| max="1.0" | |
| step="0.05" | |
| disabled={isGenerating} | |
| /> | |
| </div> | |
| <div class="input-group"> | |
| <label for="presencePenalty">Presence Penalty</label> | |
| <input | |
| type="number" | |
| id="presencePenalty" | |
| bind:value={params.presencePenalty} | |
| min="0.0" | |
| max="1.0" | |
| step="0.1" | |
| disabled={isGenerating} | |
| /> | |
| </div> | |
| </div> | |
| <label for="countPenalty">Count Penalty</label> | |
| <input | |
| type="number" | |
| id="countPenalty" | |
| bind:value={params.countPenalty} | |
| min="0.0" | |
| max="1.0" | |
| step="0.1" | |
| disabled={isGenerating} | |
| /> | |
| <button | |
| type="submit" | |
| class="generate-button" | |
| disabled={isGenerating || !client} | |
| > | |
| {isGenerating ? 'Generating Text…' : 'Generate Text'} | |
| </button> | |
| </form> | |
| {#if error} | |
| <div class="error-message">{error}</div> | |
| {/if} | |
| {#if result} | |
| <div class="text-result"> | |
| <h4>Generated Text</h4> | |
| <p><strong>Prompt:</strong> {result.prompt.substring(0, 100)}{result.prompt.length > 100 ? '...' : ''}</p> | |
| <p><strong>Generated:</strong></p> | |
| <div class="generated-text">{result.text}</div> | |
| </div> | |
| {/if} | |
| <style> | |
| .text-form { | |
| margin-top: 2rem; | |
| padding-top: 2rem; | |
| border-top: 1px solid #eee; | |
| } | |
| h3 { | |
| margin-top: 0; | |
| margin-bottom: 1.5rem; | |
| } | |
| label { | |
| font-weight: 600; | |
| margin-bottom: 0.25rem; | |
| display: block; | |
| } | |
| textarea { | |
| width: 100%; | |
| padding: 0.5rem; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| box-sizing: border-box; | |
| margin-bottom: 1rem; | |
| font-family: inherit; | |
| resize: vertical; | |
| } | |
| input[type="number"] { | |
| width: 100%; | |
| padding: 0.5rem 0.75rem; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| box-sizing: border-box; | |
| margin-bottom: 1rem; | |
| } | |
| .input-row { | |
| display: flex; | |
| gap: 1rem; | |
| } | |
| .input-group { | |
| flex: 1; | |
| } | |
| .generate-button { | |
| background: #007bff; | |
| color: #fff; | |
| border: none; | |
| padding: 0.6rem 1.4rem; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| transition: background-color 0.2s; | |
| } | |
| .generate-button:hover:not(:disabled) { | |
| background: #0056b3; | |
| } | |
| .generate-button:disabled { | |
| background: #9ac7ff; | |
| cursor: not-allowed; | |
| } | |
| .text-result { | |
| background: #f8f9fa; | |
| padding: 1rem; | |
| border-radius: 6px; | |
| margin-top: 1rem; | |
| } | |
| .text-result h4 { | |
| margin-top: 0; | |
| } | |
| .generated-text { | |
| white-space: pre-wrap; | |
| font-family: monospace; | |
| background: #fff; | |
| padding: 1rem; | |
| border-radius: 4px; | |
| border: 1px solid #ddd; | |
| } | |
| .error-message { | |
| color: #dc3545; | |
| margin-top: 1rem; | |
| padding: 0.5rem; | |
| background: #f8d7da; | |
| border-radius: 4px; | |
| } | |
| </style> |