跳至主要内容

REFERENCE

SDK 範例

@asgard-js/core 與 @asgard-js/react 的用法與可以直接操作的範例。

自訂 Footer

用 renderFooter 完全取代預設 footer。當你需要客製整個輸入區(例如改成 單行 input、加上自製語音按鈕、改變排版邏輯)時用它;只是想在送出按鈕 後面加額外按鈕,請改用 footerEndActions。

  1. 取代的內建功能​

    renderFooter 是完全取代而不是疊加:

    • 內建 textarea 與自動高度
    • 送出按鈕、麥克風按鈕
    • 圖片上傳、文件上傳、export 對話紀錄
    • Drag-and-drop 上傳整合
    • IME 組字保護(避免中文打字途中按 Enter 直接送出)
    • footerEndActions 槽位

    以上元件全部不再渲染,由 renderer 自己負責。

  2. 程式範例​

    import {
    Chatbot,
    useAsgardContext,
    type ChatbotRef,
    } from "@asgard-js/react";
    import { useEffect, useRef, useState } from "react";

    function MyFooter() {
    const {
    sendMessage,
    isConnecting,
    isStopping,
    pendingInputValue,
    setPendingInputValue,
    inputPlaceholder,
    } = useAsgardContext();

    const [value, setValue] = useState("");
    const textareaRef = useRef<HTMLTextAreaElement>(null);

    // 接收外部透過 ChatbotRef.setInputValue 塞進來的文字
    useEffect(() => {
    if (pendingInputValue == null) return;
    setValue(pendingInputValue);
    setPendingInputValue(null);
    textareaRef.current?.focus();
    }, [pendingInputValue, setPendingInputValue]);

    const submit = () => {
    const text = value.trim();
    // 同時擋 isStopping:舊的 run 還沒真的結束,這時送出會有兩個 run
    // 並行寫進同一份對話紀錄。草稿保留,不要清掉。
    if (!text || isConnecting || isStopping) return;
    sendMessage?.({ text });
    setValue("");
    };

    return (
    <div className="footer">
    <textarea
    ref={textareaRef}
    placeholder={inputPlaceholder}
    value={value}
    onChange={(e) => setValue(e.target.value)}
    onKeyDown={(e) => {
    // IME 組字途中不送出
    if (
    e.key === "Enter" &&
    !e.shiftKey &&
    !e.nativeEvent.isComposing
    ) {
    e.preventDefault();
    submit();
    }
    }}
    rows={1}
    />
    <button
    onClick={submit}
    disabled={!value.trim() || isConnecting || isStopping}
    >
    送出
    </button>
    </div>
    );
    }

    function Demo() {
    const chatbotRef = useRef<ChatbotRef>(null);
    return (
    <Chatbot
    ref={chatbotRef}
    renderFooter={() => <MyFooter />}
    {...rest}
    />
    );
    }
    換掉 footer 就要自己處理停止生成

    內建 footer 已經處理好停止的整段流程;一旦你用 renderFooter 接管,那些就都變成你的責任。 兩條規則:每個送出入口都要同時擋 isStopping(不是只擋 isConnecting),而且 只有 canStop 為真時才顯示停止控制——isConnecting 一詞四義,其中只有使用者自己的回合可以停。

    完整說明見停止生成。

  3. useAsgardContext 常用欄位​

    欄位型別說明
    sendMessage(params) => void送出訊息;undefined 代表 preview / 未連線
    isConnectingboolean是否正在等待回覆,建議用它禁用送出按鈕
    isStoppingboolean已要求停止、終止事件尚未抵達;送出入口也要一起擋
    canStopboolean目前這個 run 可不可以停——只有它為真時才顯示停止控制
    canForceStopboolean停止逾時,可升級為強制停止(隱含 isStopping)
    stopGeneration(opts?) => Promise<void>要求後端暫停目前的 run
    pendingInputValuestring | null外部透過 ChatbotRef.setInputValue 推進來的文字
    setPendingInputValue(v: string | null) => void消化掉 pending 值後請把它清成 null
    inputPlaceholderstringChatbot props 傳入的 placeholder
    messagesMap<string, ConversationMessage>所有訊息(如果你要做 token 計數等用途)
  4. 與 renderMenu / ChatbotRef.setInputValue 串接​

    這個 demo 同時用了 renderMenu 列出快速提問。按鈕透過 chatbotRef.current?.setInputValue(prompt) 把文字塞進 SDK 內部的 pendingInputValue,再由你的自訂 footer 消化掉,做到「點選 → 文字填入 輸入框 → 使用者再決定要不要送」的流程。

  5. 什麼時候不要用 renderFooter​

    • 只想在送出鈕旁加按鈕:用 footerEndActions, 內建邏輯完全保留。
    • 完全跳過 Chatbot UI:用 Headless 模式,自己組裝整個畫面。

準備好開始了嗎?

想知道 Asgard 怎麼用在你的團隊?跟我們聊聊。

聯絡我們