Spaces:
Running
Running
Download plugins/_telegram_integration/webui/config.html from Leon4gr45/openoperator: direct link, hf CLI and curl.
- Browser
- Download file 24.2 kB
-
https://huggingface.co/spaces/Leon4gr45/openoperator/resolve/main/plugins/_telegram_integration/webui/config.html
- Command line
-
hf download hf://spaces/Leon4gr45/openoperator/plugins/_telegram_integration/webui/config.html
-
curl -L -o config.html https://huggingface.co/spaces/Leon4gr45/openoperator/resolve/main/plugins/_telegram_integration/webui/config.html
24.2 kB
| <html> | |
| <head> | |
| <title>Telegram Integration</title> | |
| <script type="module"> | |
| import { store } from "/plugins/_telegram_integration/webui/telegram-config-store.js"; | |
| </script> | |
| </head> | |
| <body> | |
| <div x-data x-init="$store.telegramConfig.init(config, context)" x-destroy="$store.telegramConfig.cleanup()"> | |
| <template x-if="config"> | |
| <div class="tg-page"> | |
| <div class="section-title">Telegram</div> | |
| <template x-if="$store.telegramConfig.didInit && $store.telegramConfig.bots.length === 0"> | |
| <div class="tg-empty"> | |
| <div class="tg-empty-title">Start with one bot</div> | |
| <div class="tg-empty-copy"> | |
| Most setups only need a bot token, one allowed user, and the default polling mode. | |
| </div> | |
| <button class="btn btn-field" @click="$store.telegramConfig.addBot()"> | |
| Connect a bot | |
| </button> | |
| </div> | |
| </template> | |
| <template x-for="(bot, idx) in $store.telegramConfig.bots" :key="idx"> | |
| <div class="tg-card"> | |
| <div class="tg-card-header" @click="$store.telegramConfig.toggleEditing(idx)"> | |
| <div class="tg-card-heading"> | |
| <div class="tg-card-title" x-text="$store.telegramConfig.botTitle(bot, idx)"></div> | |
| <div class="tg-card-subtitle" x-text="$store.telegramConfig.botSubtitle(bot)"></div> | |
| </div> | |
| <div class="tg-card-actions"> | |
| <span class="tg-status-pill" :class="'tone-' + $store.telegramConfig.botStatusTone(bot)" | |
| x-text="$store.telegramConfig.botStatusLabel(bot)"></span> | |
| <button class="btn btn-action delete" | |
| @click.stop="$confirmClick($event, () => $store.telegramConfig.removeBot(idx))" title="Remove bot"> | |
| <x-icon name="delete"></x-icon> | |
| </button> | |
| <x-icon class="tg-card-chevron" | |
| :class="{ 'is-open': $store.telegramConfig.editing === idx }" name="expand_more"></x-icon> | |
| </div> | |
| </div> | |
| <template x-if="$store.telegramConfig.editing === idx"> | |
| <div class="tg-card-body"> | |
| <div class="tg-step-header"> | |
| <div class="tg-step-copy"> | |
| <div class="tg-step-title" x-text="$store.telegramConfig.currentStepMeta().title"></div> | |
| <div class="tg-step-description" x-text="$store.telegramConfig.currentStepMeta().description"></div> | |
| </div> | |
| <div class="tg-step-dots" aria-hidden="true"> | |
| <template x-for="(step, stepIdx) in $store.telegramConfig.steps" :key="step.title"> | |
| <button type="button" class="tg-step-dot" | |
| :class="{ 'is-active': $store.telegramConfig.currentStep === stepIdx }" | |
| @click="$store.telegramConfig.setStep(stepIdx)"></button> | |
| </template> | |
| </div> | |
| </div> | |
| <template x-if="$store.telegramConfig.currentStep === 0"> | |
| <div class="tg-step-panel"> | |
| <div class="tg-token-row"> | |
| <div class="tg-qr-card"> | |
| <div class="tg-qr-title">Scan to open @BotFather</div> | |
| <img class="tg-qr-image" :src="$store.telegramConfig.botFatherQr" | |
| alt="Scan to open @BotFather" /> | |
| </div> | |
| <div class="tg-token-card"> | |
| <div class="tg-token-steps"> | |
| <div class="tg-token-steps-title">Create your bot</div> | |
| <ol class="tg-token-steps-list"> | |
| <li>Open <a href="https://t.me/BotFather" target="_blank" rel="noopener">@BotFather</a></li> | |
| <li>Send <strong>/newbot</strong> and follow the prompts</li> | |
| <li>Paste the token here</li> | |
| </ol> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Bot token</div> | |
| <div class="field-description">Paste the token you got from @BotFather.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" class="masked-text-input" autocomplete="off" x-model="bot.token" | |
| placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <template x-if="$store.telegramConfig.currentStep === 1"> | |
| <div class="tg-step-panel"> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Turn on this bot</div> | |
| <div class="field-description">Enable message polling when you are ready for the bot to go live. | |
| </div> | |
| </div> | |
| <div class="field-control"> | |
| <label class="toggle"> | |
| <input type="checkbox" x-model="bot.enabled" /> | |
| <span class="toggler"></span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Bot name</div> | |
| <div class="field-description">A friendly internal label so you can tell bots apart.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" x-model="bot.name" placeholder="support_bot" /> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Delivery mode</div> | |
| <div class="field-description">Polling is the simplest option. Webhook is for public HTTPS | |
| setups.</div> | |
| </div> | |
| <div class="field-control"> | |
| <select x-model="bot.mode"> | |
| <option value="polling">Polling</option> | |
| <option value="webhook">Webhook</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="field" x-show="bot.mode === 'webhook'"> | |
| <div class="field-label"> | |
| <div class="field-title">Webhook URL</div> | |
| <div class="field-description">Your public Agent Zero base URL, for example | |
| https://yourdomain.com.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" x-model="bot.webhook_url" placeholder="https://yourdomain.com" /> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Allowed users</div> | |
| <div class="field-description">Comma-separated @usernames or numeric IDs. Leave empty only if | |
| you truly want open access.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" :value="$store.telegramConfig.whitelistText(bot)" | |
| @input="$store.telegramConfig.setWhitelist(bot, $event.target.value)" | |
| placeholder="@yourname, 123456789" /> | |
| </div> | |
| </div> | |
| <div class="tg-warning" x-show="$store.telegramConfig.accessWarning(bot)"> | |
| <span x-text="$store.telegramConfig.accessWarning(bot)"></span> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Default project</div> | |
| <div class="field-description">Optional fallback project for conversations from this bot.</div> | |
| </div> | |
| <div class="field-control"> | |
| <select :value="bot.default_project" @change="bot.default_project = $event.target.value"> | |
| <option value="">No project</option> | |
| <template x-for="proj in $store.telegramConfig.projects" :key="proj.name"> | |
| <option :value="proj.name" x-text="proj.title || proj.name" | |
| :selected="bot.default_project === proj.name"></option> | |
| </template> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <template x-if="$store.telegramConfig.currentStep === 2"> | |
| <div class="tg-step-panel"> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Group behavior</div> | |
| <div class="field-description">Choose whether the bot replies only when invited into the | |
| conversation or to everything in a group.</div> | |
| </div> | |
| <div class="field-control"> | |
| <select x-model="bot.group_mode"> | |
| <option value="mention">Reply when @mentioned or replied to</option> | |
| <option value="all">Reply to every group message</option> | |
| <option value="off">Ignore group messages</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="field" x-show="bot.group_mode !== 'off'"> | |
| <div class="field-label"> | |
| <div class="field-title">Welcome new members</div> | |
| <div class="field-description">Send a greeting when someone joins the group.</div> | |
| </div> | |
| <div class="field-control"> | |
| <label class="toggle"> | |
| <input type="checkbox" x-model="bot.welcome_enabled" /> | |
| <span class="toggler"></span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="field" x-show="bot.group_mode !== 'off' && bot.welcome_enabled"> | |
| <div class="field-label"> | |
| <div class="field-title">Welcome message</div> | |
| <div class="field-description">Use {name} for the new member's name.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" x-model="bot.welcome_message" placeholder="Welcome, {name}!" /> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Agent instructions</div> | |
| <div class="field-description">Extra guidance for how the agent should reply in Telegram chats. | |
| </div> | |
| </div> | |
| <div class="field-control"> | |
| <textarea x-model="bot.agent_instructions" rows="3" | |
| placeholder="Reply in a concise, mobile-friendly way."></textarea> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <div class="tg-test-panel"> | |
| <div class="tg-test-copy"> | |
| <div class="tg-test-title">Check the connection</div> | |
| <div class="tg-test-description" x-text="$store.telegramConfig.testIntro()"></div> | |
| </div> | |
| <button class="btn btn-field" @click.stop="$store.telegramConfig.testConnection(idx)" | |
| :disabled="$store.telegramConfig.testing === idx || !$store.telegramConfig.canTest(bot)"> | |
| <span x-text="$store.telegramConfig.testButtonLabel(bot, idx)"></span> | |
| </button> | |
| </div> | |
| <template x-if="$store.telegramConfig.testResults && $store.telegramConfig.testResultsFor === idx"> | |
| <div class="tg-results" :class="{ 'is-error': !$store.telegramConfig.testResults.success }"> | |
| <template x-for="result in $store.telegramConfig.testResults.results" | |
| :key="result.test + result.message"> | |
| <div class="tg-result-row"> | |
| <span class="tg-result-icon" x-text="result.ok ? '✓' : '✗'"></span> | |
| <div class="tg-result-copy"> | |
| <div class="tg-result-title" x-text="$store.telegramConfig.resultTitle(result)"></div> | |
| <div class="tg-result-message" x-text="$store.telegramConfig.resultMessage(result)"></div> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| </template> | |
| <template x-if="$store.telegramConfig.currentStep > 0"> | |
| <details class="tg-advanced"> | |
| <summary> | |
| <span>Advanced</span> | |
| <x-icon class="tg-advanced-chevron" | |
| aria-hidden="true" name="keyboard_arrow_down"></x-icon> | |
| </summary> | |
| <div class="tg-advanced-body"> | |
| <div class="field" x-show="bot.mode === 'webhook'"> | |
| <div class="field-label"> | |
| <div class="field-title">Webhook secret</div> | |
| <div class="field-description">Optional shared secret for webhook verification.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" class="masked-text-input" autocomplete="off" x-model="bot.webhook_secret" /> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Message notifications</div> | |
| <div class="field-description">Show a WebUI notification for each incoming Telegram message. | |
| </div> | |
| </div> | |
| <div class="field-control"> | |
| <label class="toggle"> | |
| <input type="checkbox" x-model="bot.notify_messages" /> | |
| <span class="toggler"></span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">User project mapping</div> | |
| <div class="field-description">Map specific Telegram user IDs to projects with user_id=project | |
| entries.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="text" :value="$store.telegramConfig.userProjectsText(bot)" | |
| @input="$store.telegramConfig.setUserProjects(bot, $event.target.value)" | |
| placeholder="123456=my_project, 789012=other_project" /> | |
| </div> | |
| </div> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Attachment max age</div> | |
| <div class="field-description">How long to keep downloaded attachments. Use 0 to keep them | |
| forever.</div> | |
| </div> | |
| <div class="field-control"> | |
| <input type="number" x-model.number="bot.attachment_max_age_hours" min="0" step="1" | |
| placeholder="0" /> | |
| </div> | |
| </div> | |
| </div> | |
| </details> | |
| </template> | |
| </div> | |
| </template> | |
| </div> | |
| </template> | |
| <template x-if="$store.telegramConfig.bots.length > 0"> | |
| <button class="btn btn-field tg-add-btn" @click="$store.telegramConfig.addBot()"> | |
| Connect another bot | |
| </button> | |
| </template> | |
| </div> | |
| </template> | |
| </div> | |
| <style> | |
| .tg-page { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.9rem; | |
| } | |
| .tg-advanced summary { | |
| cursor: pointer; | |
| list-style: none; | |
| font-weight: 700; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| } | |
| .tg-advanced summary::-webkit-details-marker { | |
| display: none; | |
| } | |
| .tg-guide-card, | |
| .tg-empty, | |
| .tg-card { | |
| border-radius: 0.5rem; | |
| } | |
| .tg-empty-title, | |
| .tg-step-title, | |
| .tg-test-title, | |
| .tg-qr-title { | |
| font-weight: 700; | |
| } | |
| .tg-empty-copy, | |
| .tg-step-description, | |
| .tg-info-box, | |
| .tg-test-description, | |
| .tg-result-message, | |
| .tg-card-subtitle { | |
| color: var(--color-text-secondary); | |
| line-height: 1.5; | |
| } | |
| .tg-empty { | |
| padding: 1rem; | |
| } | |
| .tg-empty-copy { | |
| margin-top: 0.35rem; | |
| margin-bottom: 0.9rem; | |
| } | |
| .tg-card-header { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 1rem; | |
| align-items: flex-start; | |
| padding: var(--spacing-sm) 0; | |
| border-bottom: 1px solid var(--color-border); | |
| cursor: pointer; | |
| } | |
| .tg-card-heading { | |
| min-width: 0; | |
| flex: 1 1 auto; | |
| } | |
| .tg-card-title { | |
| font-weight: 700; | |
| line-height: 1.35; | |
| overflow-wrap: anywhere; | |
| } | |
| .tg-card-subtitle { | |
| margin-top: 0.3rem; | |
| font-size: var(--font-size-small); | |
| } | |
| .tg-card-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.45rem; | |
| flex: 0 0 auto; | |
| } | |
| .tg-card-chevron { | |
| transition: transform 0.18s ease; | |
| opacity: 0.7; | |
| } | |
| .tg-card-chevron.is-open { | |
| transform: rotate(180deg); | |
| } | |
| .tg-card-body { | |
| border-top: 1px solid color-mix(in srgb, var(--color-border) 88%, white 12%); | |
| } | |
| .tg-step-header { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 1rem; | |
| align-items: flex-start; | |
| margin: 1rem 0; | |
| } | |
| .tg-step-dots { | |
| display: flex; | |
| gap: 0.5rem; | |
| flex-wrap: wrap; | |
| justify-content: flex-end; | |
| align-items: center; | |
| } | |
| .tg-step-dot { | |
| width: 0.85rem; | |
| height: 0.85rem; | |
| border-radius: 999px; | |
| border: 1px solid var(--color-border); | |
| background: transparent; | |
| cursor: pointer; | |
| padding: 0; | |
| } | |
| .tg-step-dot.is-active { | |
| background: rgba(59, 130, 246, 0.9); | |
| border-color: rgba(59, 130, 246, 0.9); | |
| } | |
| .tg-step-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.2rem; | |
| } | |
| .tg-token-row { | |
| display: grid; | |
| grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr); | |
| gap: 1rem; | |
| align-items: stretch; | |
| } | |
| .tg-qr-card, | |
| .tg-token-card { | |
| border-radius: 0.5rem; | |
| background: color-mix(in srgb, var(--color-background) 90%, white 10%); | |
| padding: 1rem; | |
| } | |
| .tg-qr-card { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| text-align: center; | |
| gap: 0.8rem; | |
| } | |
| .tg-qr-image { | |
| width: 150px; | |
| height: 150px; | |
| border-radius: 0.5rem; | |
| image-rendering: pixelated; | |
| } | |
| .tg-token-steps { | |
| margin-bottom: 0.9rem; | |
| } | |
| .tg-token-steps-title { | |
| font-weight: 700; | |
| margin-bottom: 0.45rem; | |
| } | |
| .tg-token-steps-list { | |
| margin: 0; | |
| padding-left: 1.15rem; | |
| color: var(--color-text-secondary); | |
| line-height: 1.55; | |
| } | |
| .tg-token-steps-list a { | |
| color: var(--color-highlight); | |
| } | |
| .tg-info-box, | |
| .tg-warning { | |
| margin-bottom: 0.9rem; | |
| padding: 0.8rem 0.9rem; | |
| border-radius: 12px; | |
| font-size: var(--font-size-small); | |
| } | |
| .tg-info-box { | |
| background: color-mix(in srgb, #3b82f6 12%, var(--color-background) 88%); | |
| } | |
| .tg-warning { | |
| background: color-mix(in srgb, #f59e0b 14%, var(--color-background) 86%); | |
| } | |
| .tg-advanced { | |
| margin-top: 0.95rem; | |
| border: 1px solid color-mix(in srgb, var(--color-border) 88%, white 12%); | |
| border-radius: 14px; | |
| overflow: hidden; | |
| } | |
| .tg-advanced summary { | |
| padding: 0.9rem 1rem; | |
| background: color-mix(in srgb, var(--color-background) 88%, white 12%); | |
| } | |
| .tg-advanced-chevron { | |
| margin-left: auto; | |
| flex: 0 0 auto; | |
| transition: transform 0.18s ease, opacity 0.18s ease; | |
| opacity: 0.72; | |
| } | |
| .tg-advanced[open] .tg-advanced-chevron { | |
| transform: rotate(180deg); | |
| opacity: 1; | |
| } | |
| .tg-advanced-body { | |
| padding: 1rem; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.2rem; | |
| } | |
| .tg-test-panel { | |
| margin-top: 1rem; | |
| padding: var(--spacing-xs) 0; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| gap: 1rem; | |
| } | |
| .tg-test-copy, | |
| .tg-result-copy { | |
| min-width: 0; | |
| } | |
| .tg-results { | |
| margin-top: 0.9rem; | |
| border-radius: 14px; | |
| border: 1px solid color-mix(in srgb, #22c55e 28%, var(--color-border) 72%); | |
| background: color-mix(in srgb, #22c55e 8%, var(--color-background) 92%); | |
| padding: 0.35rem 0.9rem; | |
| } | |
| .tg-results.is-error { | |
| border-color: color-mix(in srgb, #ef4444 28%, var(--color-border) 72%); | |
| background: color-mix(in srgb, #ef4444 8%, var(--color-background) 92%); | |
| } | |
| .tg-result-row { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 0.8rem; | |
| padding: 0.7rem 0; | |
| } | |
| .tg-result-row+.tg-result-row { | |
| border-top: 1px solid color-mix(in srgb, var(--color-border) 85%, white 15%); | |
| } | |
| .tg-result-icon { | |
| width: 1.25rem; | |
| font-weight: 800; | |
| line-height: 1.3; | |
| } | |
| .tg-result-title { | |
| font-weight: 700; | |
| margin-bottom: 0.18rem; | |
| } | |
| .tg-status-pill { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-width: 5.25rem; | |
| padding: 0.35rem 0.7rem; | |
| border-radius: 999px; | |
| font-size: 0.8rem; | |
| font-weight: 700; | |
| } | |
| .tg-status-pill.tone-success { | |
| background: rgba(34, 197, 94, 0.14); | |
| color: #7ee7a4; | |
| } | |
| .tg-status-pill.tone-ready { | |
| background: rgba(59, 130, 246, 0.16); | |
| color: #93c5fd; | |
| } | |
| .tg-status-pill.tone-warning { | |
| background: rgba(245, 158, 11, 0.16); | |
| color: #fcd34d; | |
| } | |
| .tg-status-pill.tone-muted { | |
| background: rgba(148, 163, 184, 0.14); | |
| color: #cbd5e1; | |
| } | |
| .tg-add-btn { | |
| align-self: flex-start; | |
| } | |
| @media (max-width: 900px) { | |
| .tg-token-row { | |
| grid-template-columns: minmax(0, 1fr); | |
| } | |
| } | |
| @media (max-width: 640px) { | |
| .tg-card-header, | |
| .tg-step-header, | |
| .tg-test-panel { | |
| flex-direction: column; | |
| align-items: stretch; | |
| } | |
| .tg-card-actions, | |
| .tg-step-dots { | |
| width: 100%; | |
| justify-content: space-between; | |
| } | |
| .tg-status-pill { | |
| min-width: 0; | |
| } | |
| } | |
| </style> | |
| </body> | |
| </html> | |