Documentation Index
Fetch the complete documentation index at: https://docs.langbot.app/llms.txt
Use this file to discover all available pages before exploring further.
Pageコンポーネントを使用すると、プラグインはLangBot WebUIのサイドバーにカスタムビジュアルページを登録できます。ページはiframeサンドボックス内で実行され、Page SDKを介してホストと通信し、プラグインのバックエンドAPIを呼び出すことができます。
ユースケース
- 管理パネル:プラグインに視覚的な設定やデータ管理インターフェースを提供(例:FAQ管理、分析ダッシュボード)
- データ表示:ランタイムの統計データ、ログ、チャートなどを表示
- インタラクティブツール:フォーム、エディタなどの対話式インターフェースを提供
ページコンポーネントの追加
プラグインディレクトリでコマンドを実行します:
ページ名を入力すると、components/pages/ディレクトリにページファイルが生成されます:
├── components
│ └── pages
│ └── dashboard
│ ├── dashboard.yaml # ページマニフェスト
│ ├── dashboard.py # バックエンドハンドラー
│ ├── index.html # ページエントリポイント
│ └── i18n # 翻訳ファイル(オプション)
│ ├── en_US.json
│ └── ja_JP.json
manifest.yamlにもコンポーネント検出設定が追加されます:
spec:
components:
Page:
fromDirs:
- path: components/pages/
maxDepth: 2
マニフェストファイル:ページ
apiVersion: v1 # 変更しないでください
kind: Page # 変更しないでください
metadata:
name: dashboard # プラグイン内で一意のページID
label:
en_US: Dashboard # WebUIサイドバーに表示される名前、多言語対応
ja_JP: ダッシュボード
spec:
path: index.html # HTMLエントリファイル(このYAMLファイルからの相対パス)
execution:
python:
path: dashboard.py # バックエンドハンドラーファイル
attr: DashboardPage # ハンドラークラス名
バックエンド処理
PageコンポーネントのバックエンドハンドラーはPage基底クラスを継承し、handle_apiメソッドを実装してフロントエンドページからのAPIリクエストを処理します。
from langbot_plugin.api.definition.components.page import Page, PageRequest, PageResponse
class DashboardPage(Page):
async def handle_api(self, request: PageRequest) -> PageResponse:
# request.endpoint: APIエンドポイントパス(例:'/stats')
# request.method: HTTPメソッド(GET、POST、PUT、DELETE)
# request.body: リクエストボディ(解析済みJSON、またはNone)
if request.endpoint == '/stats' and request.method == 'GET':
# self.pluginでプラグインインスタンスの共有状態にアクセス
return PageResponse.ok({
'total': len(self.plugin.entries),
})
return PageResponse.fail(f'不明なエンドポイント: {request.endpoint}')
| フィールド | 型 | 説明 |
|---|
endpoint | str | APIエンドポイントパス(例:'/entries') |
method | str | HTTPメソッド(GET、POST、PUT、DELETE) |
body | Any | リクエストボディ(解析済みJSON、またはNone) |
| メソッド | 説明 |
|---|
PageResponse.ok(data) | 成功レスポンス。dataはJSON変換可能な任意の値 |
PageResponse.fail(error) | エラーレスポンス。errorはエラーメッセージ文字列 |
フロントエンドページ開発
HTMLファイルにPage SDKを読み込んで、プラグインバックエンドと通信します:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
background: var(--langbot-bg, #ffffff);
color: var(--langbot-text, #0a0a0a);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding: 24px;
}
</style>
</head>
<body>
<h1 data-i18n="title">ダッシュボード</h1>
<p id="stats"></p>
<script src="/api/v1/plugins/_sdk/page-sdk.js"></script>
<script>
langbot.onReady(async function(ctx) {
// バックエンドAPIを呼び出す
var data = await langbot.api('/stats', null, 'GET');
document.getElementById('stats').textContent = '合計: ' + data.total;
});
</script>
</body>
</html>
Page SDK API
| メソッド | 説明 |
|---|
langbot.onReady(callback) | SDK準備完了時に呼ばれる。callbackはctx(themeとlanguageを含む)を受け取る |
langbot.api(endpoint, body?, method?) | プラグインのhandle_apiを呼び出す。Promiseを返す |
langbot.t(key, fallback?) | 翻訳文字列を取得 |
langbot.onThemeChange(callback) | テーマ変更時のコールバック |
langbot.onLanguageChange(callback) | 言語変更時のコールバック |
langbot.applyI18n() | data-i18n翻訳を手動で再適用 |
ダークモード
SDKはページにCSSカスタムプロパティを自動設定します。直接使用できます:
| CSS変数 | 用途 |
|---|
--langbot-bg | ページ背景色 |
--langbot-bg-card | カード背景色 |
--langbot-text | メインテキスト色 |
--langbot-text-muted | サブテキスト色 |
--langbot-border | ボーダー色 |
--langbot-accent | アクセント色 |
ページi18n
ページディレクトリ内にi18n/ディレクトリを作成し、JSON翻訳ファイルを配置します:
pages/dashboard/
├── index.html
└── i18n/
├── en_US.json
└── ja_JP.json
翻訳ファイルはフラットなJSONキーバリューペアです:
{
"title": "ダッシュボード",
"totalEntries": "エントリ数"
}
HTML要素にdata-i18n属性を追加すると、SDKが自動的にテキストを翻訳します:
<h1 data-i18n="title">Dashboard</h1>
完全な例:FAQ管理ページ
FAQエントリのCRUD操作を実装した完全なPageコンポーネントの例です。
バックエンドハンドラー(components/pages/manager/manager.py):
from langbot_plugin.api.definition.components.page import Page, PageRequest, PageResponse
class ManagerPage(Page):
async def handle_api(self, request: PageRequest) -> PageResponse:
plugin = self.plugin
if request.endpoint == '/entries' and request.method == 'GET':
return PageResponse.ok({'entries': plugin.entries})
if request.endpoint == '/entries' and request.method == 'POST':
question = (request.body or {}).get('question', '').strip()
answer = (request.body or {}).get('answer', '').strip()
if not question or not answer:
return PageResponse.fail('質問と回答は必須です')
entry = plugin.add_entry(question, answer)
await plugin.persist()
return PageResponse.ok({'entry': entry})
if request.endpoint == '/entries' and request.method == 'DELETE':
entry_id = (request.body or {}).get('id', '')
if plugin.delete_entry(entry_id):
await plugin.persist()
return PageResponse.ok({'deleted': entry_id})
return PageResponse.fail('エントリが見つかりません')
return PageResponse.fail(f'不明: {request.method} {request.endpoint}')
フロントエンドページ(components/pages/manager/index.html)ではlangbot.api()でバックエンドを呼び出します:
// エントリを読み込む
var data = await langbot.api('/entries', null, 'GET');
// エントリを追加
await langbot.api('/entries', { question: '...', answer: '...' }, 'POST');
// エントリを削除
await langbot.api('/entries', { id: '...' }, 'DELETE');
完全なサンプルコードはFAQManagerプラグインを参照してください。
注意事項
- ページは
sandbox="allow-scripts allow-forms"のiframe内で実行され、ポップアップを開いたり親ページをナビゲートすることはできません
self.pluginでプラグインインスタンスの共有状態にアクセスできます — PageとToolコンポーネントはデータを共有できます
PageResponse.ok()とPageResponse.fail()を使用してレスポンスを構築し、一貫したフォーマットを確保してください
- Page SDKの
<script>タグは、langbotオブジェクトを使用するコードの前に配置する必要があります