> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/transcript-ui.md).

# 转录 UI

转录系统将角色和玩家语音传递到你的场景 UI，在运行时层处理中间识别、回合组装和生命周期管理。添加 `ITranscriptListener` 用于轻量级回调，或者 `ITranscriptUI` 用于完整显示控制，或者直接使用内置的 `TranscriptUI_Chat.prefab` 即可实现零配置聊天。

### 转录系统如何工作

下图展示了转录数据如何从运行时通过控制器流向你的场景 UI。

```mermaid
graph TD
    A[IRoomTranscriptEngine] -->|TranscriptUpdateBatch| B[TranscriptUIController]
    B -->|routes to active strategy| C[ITranscriptPresentationStrategy\nChat / Subtitle]
    C -->|OnMessageUpdated / OnMessageCompleted| D[ITranscriptUI\nChatTranscriptUI / SubtitleTranscriptUI]
    D --> E[Scene UI]
    B -->|simple callbacks| F[ITranscriptListener]
    F --> G[Your Script]
```

`IRoomTranscriptEngine` 是所有转录数据的唯一可信来源。 `TranscriptUIController` 负责当前激活的呈现策略，并将数据分派给与当前 `ITranscriptUI` 模式相匹配的实现。 `ITranscriptListener` 是一条平行、更简单的路径，完全绕过策略层。

`ConvaiManager` 自动发现场景中的所有 `ITranscriptUI` 是位于 `ITranscriptListener` 实现。常见情况下你无需手动注册它们。

### 集成路径

#### ITranscriptListener — 轻量级回调

使用 `ITranscriptListener` 当你需要对转录文本做出响应，而不想构建完整的自定义 UI 时使用。例如：将转录内容送入评分系统、写入日志、驱动自定义文本组件，或根据玩家所说的内容触发场景事件。

**接口约定：**

```csharp
public interface ITranscriptListener
{
    // 可选。设置为某个角色 ID 以只接收该角色的转录。
    // 返回 null 表示不过滤。无论此值为何，始终会接收玩家转录。
    string FilterCharacterId { get; }

    void OnCharacterTranscript(string characterId, string characterName, string text, bool isFinal);
    void OnPlayerTranscript(string text, bool isFinal);
}
```

`isFinal` 为 `false` 当语音仍在识别中（部分）以及 `true` 当回合完成时。部分转录会频繁到达——除非你需要实时流式反馈，否则只处理最终转录。

**自动发现：** 添加 `ITranscriptListener` 到任何 `MonoBehaviour` 的引用。 `ConvaiManager` 在初始化期间自动发现并注册所有实现。

**多用户归属：** 对于需要知道具体是哪位玩家发言的多用户房间，请实现 `IMultiUserTranscriptListener` 上的全房间事件：

```csharp
public interface IMultiUserTranscriptListener : ITranscriptListener
{
    void OnPlayerTranscriptWithSpeaker(
        string speakerId,
        string speakerName,
        string participantId,
        string text,
        bool isFinal);
}
```

#### ITranscriptUI — 完整显示控制

使用 `ITranscriptUI` 用于构建内置聊天或字幕 UI 的完整替代方案——自定义滚动列表、3D 世界空间面板、WebGL 中的 HTML 覆盖层，或内置预制体无法提供的任何布局。

**接口约定：**

```csharp
public interface ITranscriptUI
{
    // 必须与某个 ConvaiTranscriptMode 名称匹配："Chat" 或 "Subtitle"
    string Identifier { get; }

    bool IsActive { get; }

    // 调用时机：部分和最终转录都会触发
    void DisplayMessage(TranscriptViewModel viewModel);

    // 当某个特定消息气泡应被定稿时调用
    void CompleteMessage(string messageId);

    // 当所有当前玩家消息都应被定稿时调用
    void CompletePlayerTurn();

    // 当需要清空所有已显示内容时调用
    void ClearAll();

    // 由控制器调用，用于激活或停用此 UI
    void SetActive(bool active);
}
```

`标识符` 决定哪个 `ConvaiTranscriptMode` 会激活此 UI。使用 `“聊天”` 替换聊天 UI， `“字幕”` 替换字幕 UI。

`DisplayMessage` 会对部分和最终转录都调用。检查 `viewModel.IsFinal` 来决定是继续更新气泡还是将其锁定。

**注册：** 将你的实现作为一个 `MonoBehaviour` 添加到场景中。 `ConvaiManager` 会自动发现它。若要手动控制：

| 方法                                                                     | 说明               |
| ---------------------------------------------------------------------- | ---------------- |
| `ConvaiManager.ActiveManager.RegisterTranscriptUI(ITranscriptUI ui)`   | 手动注册一个转录 UI 实现   |
| `ConvaiManager.ActiveManager.UnregisterTranscriptUI(ITranscriptUI ui)` | 手动取消注册一个转录 UI 实现 |

### 添加内置聊天 UI

SDK 随附 `TranscriptUI_Chat.prefab` —— 一个现成的、可滚动的聊天面板，带自动滚动和按发言者颜色区分的消息气泡。

{% stepper %}
{% step %}

#### 将预制体添加到你的场景中

拖动 `TranscriptUI_Chat.prefab` 到你的场景中。你可以在 `Prefabs/TranscriptUI/TranscriptUI_Chat.prefab` 在 <code class="expression">space.vars.sdk\_package\_id</code> 包中找到它。该预制体包含自己的 `Canvas` —— 不要将其嵌套在现有的 Canvas 中。

该预制体包含一个 `ChatTranscriptUI` 组件，它会自动向 `ConvaiManager` on `Awake`.
{% endstep %}

{% step %}

#### 确保场景中存在 EventSystem

聊天输入字段需要场景中存在一个 `EventSystem` 。如果你的场景中没有，请通过以下路径添加： **GameObject → UI → Event System**.
{% endstep %}

{% step %}

#### 运行你的场景

连接到角色并开始说话。角色语音会显示在一个气泡列中；你的语音会显示在另一个气泡列中。随着对话推进，面板会自动滚动到最新消息。
{% endstep %}
{% endstepper %}

{% hint style="success" %}
当 `ConvaiTranscriptMode.Chat` 是当前模式时，聊天 UI 会自动激活，这是默认值。基础设置无需额外配置。
{% endhint %}

### ConvaiTranscriptDisplay — 角色本地显示

`ConvaiTranscriptDisplay` 是一个轻量级组件，用于将单个角色的转录直接显示在该角色的 `GameObject`上。它不参与房间转录流水线，也不了解其他角色或玩家。

**Inspector 字段：**

| 字段                        | 默认值     | 说明                       |
| ------------------------- | ------- | ------------------------ |
| `_transcriptText`         | —       | `TMP_Text` 引用以渲染到        |
| `_showPartialTranscripts` | `true`  | 在部分识别期间更新文本              |
| `_appendMode`             | `false` | 追加新转录而不是替换               |
| `_clearOnNewFinal`        | `true`  | 在每次最终转录前清空缓冲区（仅追加模式）     |
| `_maxCharacters`          | `1000`  | 追加模式下保留的最大字符数。 `0` = 无限制 |

**要求：** 必须位于相同的 `GameObject` 作为 `ConvaiCharacter`。在 `Awake`.

时会自动订阅该角色的转录事件。对于按角色显示的标签——例如训练站上方漂浮的名字牌或角色模型旁的面板—— `ConvaiTranscriptDisplay` 是正确选择。若要完整对话历史或玩家转录，请使用聊天预制体或 `ITranscriptListener`.

### 切换活动转录模式

通过运行时设置服务切换转录模式。更改会立即生效——相匹配的 `ITranscriptUI` 会激活，任何之前的 UI 都会停用。

```csharp
using Convai.Runtime.Components;
using Convai.Shared.Types;

if (ConvaiManager.ActiveManager.TryGetRuntimeSettingsService(out var settings))
{
    var result = settings.Apply(new ConvaiRuntimeSettingsPatch
    {
        TranscriptMode = ConvaiTranscriptMode.Subtitle
    });

    如果 !result.Success
        Debug.LogWarning($"[Transcript] Mode switch failed: {result.ValidationMessage}");
}
```

用户也可以通过内置设置面板切换模式。参见 [设置面板](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/settings-panel.md) 了解面板在运行时可暴露哪些模式。

### 清空转录显示

调用 `ClearAll()` 在任何 `ITranscriptUI` 组件上，以销毁所有已显示的消息气泡并重置面板。这只会清除 **可视显示** —— 底层的房间回合历史在 `ConvaiManager.Transcripts` 中是只读的，不受影响。

```csharp
using Convai.Runtime.Presentation.Views.Transcript;

// 通过序列化字段（推荐）
[SerializeField] private ChatTranscriptUI _chatUI;

public void ResetForNextScenario()
{
    _chatUI.ClearAll();
}
```

```csharp
// 或者在没有直接引用时通过场景查找
FindObjectOfType<ChatTranscriptUI>()?.ClearAll();
```

{% hint style="warning" %}
`ConvaiManager` 没有公开一个全局 `ClearAll()`。请保留一个直接组件引用，使用 `FindObjectOfType`，或者实现一个中央重置控制器来持有所有已注册 UI 的引用。
{% endhint %}

**典型用例：**

* 新训练场景开始——从屏幕上清除上一场景的对话历史
* 复盘后重置——学员已经查看过聊天；在下一次会话开始前清空
* 场景切换——在加载新内容前清空，避免旧消息闪现

### 使用示例

#### 安全培训——使用 `ITranscriptListener`

一个工作场所安全培训模拟通过读取 AI 教员的最终转录来对学员回答进行评分：

```csharp
using Convai.Runtime.Presentation.Services;
using UnityEngine;

public class ComplianceScorer : MonoBehaviour, ITranscriptListener
{
    [SerializeField] private string _instructorCharacterId;
    [SerializeField] private ScoreBoard _scoreBoard;

    public string FilterCharacterId => _instructorCharacterId;

    public void OnCharacterTranscript(string characterId, string characterName, string text, bool isFinal)
    {
        // 教员提示——如有需要可记录以供参考
    }

    public void OnPlayerTranscript(string text, bool isFinal)
    {
        if (!isFinal) return;
        bool passed = text.Contains("hazard identified", System.StringComparison.OrdinalIgnoreCase);
        _scoreBoard.RecordResponse(text, passed);
    }
}
```

放置在任何 `GameObject` 的引用。 `ConvaiManager` 会自动发现并注册它。运行时，评分器会评估每条最终玩家回答，并记录学员是否正确识别了危险。

#### 博物馆信息亭——使用 `ConvaiTranscriptDisplay`

一家自然历史博物馆的信息亭会在每个展品角色的陈列柜旁物理面板上显示其语音：

* 添加 `ConvaiTranscriptDisplay` 添加到 `ConvaiCharacter` `GameObject`
* 将面板的 `TMP_Text` 到 `_transcriptText`
* 设置 `_appendMode` 关闭，并 `_clearOnNewFinal` 开启——每个新的完整句子都会替换前一个

在运行时，每个角色的语音都会在游客与其互动时显示在其专用面板上，而无需完整聊天流水线带来的 UI 开销。

#### 多用户消防演练——使用 `IMultiUserTranscriptListener`

一个多用户消防安全演练会跟踪具体是哪位学员发言以及他们说了什么，以便生成会后报告：

```csharp
using Convai.Runtime.Presentation.Services;
using System.Collections.Generic;
using UnityEngine;

public class DrillTranscriptLogger : MonoBehaviour, IMultiUserTranscriptListener
{
    private readonly List<string> _log = new();

    public string FilterCharacterId => null; // 接收所有角色

    public void OnCharacterTranscript(string characterId, string characterName, string text, bool isFinal)
    {
        if (isFinal) _log.Add($"[Instructor] {characterName}: {text}");
    }

    public void OnPlayerTranscript(string text, bool isFinal)
    {
        // 在多用户房间中使用 OnPlayerTranscriptWithSpeaker 进行归属记录
    }

    public void OnPlayerTranscriptWithSpeaker(
        string speakerId, string speakerName, string participantId, string text, bool isFinal)
    {
        if (isFinal) _log.Add($"[Trainee] {speakerName}: {text}");
    }

    public IReadOnlyList<string> GetLog() => _log;
}
```

在运行时，每条最终确定的学员发言都会按姓名归属于特定学员，从而生成按参与者划分的演练转录，供会后回顾。

### 下一步

你已经了解了转录流水线架构、两种集成路径、内置聊天预制体、按角色显示、模式切换以及显示清空。下一步是配置默认渲染的模式，以及每种模式的外观和行为。

{% content-ref url="/pages/b846767a1ed5a04b3cfb93646c3c8472baf91067" %}
[转录历史与查询](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/transcript-ui/transcript-history-and-queries.md)
{% endcontent-ref %}

{% content-ref url="/pages/6695eb978b08dbf5023b367d38af0912574c4f52" %}
[聊天与字幕模式](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/transcript-ui/chat-and-subtitle-modes.md)
{% endcontent-ref %}

{% content-ref url="/pages/dddf624ca0ae7ec32afa0c9e601f2cb7c7ab2b6a" %}
[设置面板](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/settings-panel.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/ui-and-presentation/transcript-ui.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
