Corti 嵌入式网络组件
一个网络组件和React组件库,为Corti AI助手提供嵌入式接口.
特征
- Web 组件和反应: 既可作为本地网络组件,也可以作为反应组件
- 显示/ 隐藏: 控制聊天界面的能见度
- 认证支持: 内置认证信件处理
- 类型脚本支持: 包含全部类型脚本定义
安装
npm install @corti/embedded-web
测试
运行测试前安装依赖性 :
npm install
运行完整的测试套件 :
npm test
开发时以监视模式运行测试 :
npm run test:watch
只运行嵌入式组件通信集成测试 :
npx tsc -p tsconfig.test.json && npx wtr .tmp/test-dist/test/corti-embedded.integration.test.js
在Chrimium、Firefox和WebKit进行整合测试:
npx tsc -p tsconfig.test.json && EMBEDDED_WEB_TEST_BROWSERS=chromium,firefox,webkit npx wtr .tmp/test-dist/test/corti-embedded.integration.test.js
对已安装的微软边缘频道进行集成测试 :
npx tsc -p tsconfig.test.json && EMBEDDED_WEB_TEST_BROWSERS=chromium EMBEDDED_WEB_CHROMIUM_CHANNEL=msedge npx wtr .tmp/test-dist/test/corti-embedded.integration.test.js
集成测试默认在Playwright Chromium中运行,可被扩展为Firefox,WebKit,或已安装的Edge通道. 它根据真实的iframe验证了公共网络组件 API postMessage 边界并使用本地测试跑道设置,因此不需要访问活式嵌入式助理服务.
Pull requests也在Windows GitHub Actions transfer上运行了针对Microsoft Edge的集成测试.
使用量
网络组件
<corti-embedded
id="corti-component"
baseurl="https://assistant.eu.corti.app" <!-- REQUIRED -->
></corti-embedded>
const myComponent = document.getElementById('corti-component');
const userResponse = await myComponent.auth({...});
const interaction = await myComponent.createInteraction({
"assignedUserId": null,
"encounter": {
"identifier": `encounter-${Date.now()}`,
"status": "planned",
"type": "first_consultation",
"period": {
"startedAt": "2025-11-11T16:14:59.923Z"
}
}
});
await myComponent.setInteractionOptions({
templates: {
defaultTemplate: {
behaviour: "fallback",
template: { source: "standard", id: "soap_note" },
},
},
});
await myComponent.addFacts([{"text": "Chest pain", "group": "other"}]);
await myComponent.navigate({ path: "/interactions/123" });
await myComponent.show()
一般活动收听器(网络组件)
使用 event 作为网络组件集成的犬科事件流。 遗产 embedded-event 流已删除.
- 事件细节形状
{ name: string; payload: unknown }。 。 。 . - 完整活动目录和有效载荷细节记录在:
myComponent.addEventListener("event", event => {
const { detail } = event;
console.log(detail.name, detail.payload);
});
反应组件
import React, { useRef } from "react";
import {
CortiEmbeddedReact,
type CortiEmbeddedReactRef,
type CortiEmbeddedEvent,
type CortiEmbeddedReadyEvent,
useCortiEmbeddedApi,
useCortiEmbeddedStatus,
} from "@corti/embedded-web/react";
function App() {
const cortiRef = useRef<CortiEmbeddedReactRef>(null);
const api = useCortiEmbeddedApi(cortiRef);
const { status } = useCortiEmbeddedStatus(cortiRef);
const handleReady = (event: CortiEmbeddedReadyEvent) => {
console.log("Corti component is ready!", event.detail);
};
const handleEvent = (event: CortiEmbeddedEvent) => {
console.log("Event name:", event.detail.name);
console.log("Event payload:", event.detail.payload);
};
const handleAuth = async () => {
try {
const user = await api.auth({
access_token: "your-token",
token_type: "Bearer",
// ... rest of the token response
});
console.log("Authenticated:", user);
await api.setInteractionOptions({
templates: {
defaultTemplate: {
behaviour: "fallback",
template: { source: "standard", id: "soap_note" },
},
},
});
await api.createInteraction({
encounter: {
identifier: `encounter-${Date.now()}`,
status: "planned",
type: "first_consultation",
period: { startedAt: new Date().toISOString() },
},
});
} catch (error) {
console.error("Auth failed:", error);
}
};
return (
<div style={{ height: "100vh" }}>
<button onClick={handleAuth}>Authenticate</button>
<CortiEmbeddedReact
ref={cortiRef}
baseURL="https://assistant.eu.corti.app" // REQUIRED
visibility="visible"
onReady={handleReady}
onEvent={handleEvent}
onError={event => console.error("Embedded error:", event.detail)}
style={{ width: "100%", height: "500px" }}
/>
<pre>{JSON.stringify(status, null, 2)}</pre>
</div>
);
}
显示/隐藏组件
const component = document.getElementById("corti-component");
// Show the chat interface
component.show();
// Hide the chat interface
component.hide();
API 方法(建议)
- 使用这些命名的助手执行共同的任务 。 它们提供了更明确的意图和合理的默认.
认证
在使用嵌入式应用程序之前需要认证 。 载荷传到
component.auth(...) 应直接取自您的身份代号
响应(例如,Keycloak/OIDC符号端点响应).
- API 细节和有效载荷形状 : https://docs.corti.ai/api-reference#auth 互联网档案馆的存檔,存档日期2013-12-02
- 端到端认证指导 : https://docs.corti.ai/协助/认证
使用基于用户的认证(OAuth2/OIDC). 仅限客户端的流量 不支持嵌入式应用程序 .
const authResponse = await component.auth({
// Use the full token response from your IdP
access_token: 'YOUR_JWT',
token_type: 'Bearer',
// include other token fields from your provider response (expires_in, refresh_token, etc.)
...
});
配置辅助
await component.configureApp({
ui: {
aiChat: true,
navigation: false,
},
appearance: {
primaryColor: "#000000",
},
});
设置交互选项
await component.setInteractionOptions({
mode: {
fallback: "virtual",
options: ["in-person", "virtual"],
},
spokenLanguage: {
fallback: "en",
},
templates: {
defaultTemplate: {
behaviour: "fallback",
template: { source: "standard", id: "discharge-summary" },
},
},
});
添加事实
await component.addFacts([
{ text: 'Patient reports chest pain', group: 'subjective' },
{ text: 'BP 120/80', group: 'vitals' },
],
导航
await component.navigate({ path: "/interactions/123" });
创建交互
const created = await component.createInteraction({
assignedUserId: null,
encounter: {
identifier: "enc-123",
status: "in-progress",
type: "consult",
period: { startedAt: new Date().toISOString() },
title: "Visit for cough",
},
patient: {
identifier: "pat-456",
},
});
开始记录/ 停止记录
await component.startRecording();
// ... later
await component.stopRecording();
获取状态
const status = await component.getStatus();
回返情况:
auth数字 :{ isAuthenticated, user? }applicationVersion: 嵌入式 Corti 助手的版本currentUrl: iframe 内的当前 URLinteraction: 开放式互动的细节,或nullisMedicalDevice:运行的建筑是否为医疗器械. 何时true, (中文(简体) ),medicalDevice包含buildDate, (中文(简体) ),deviceIdentifier,以及udi。 。 。 .
获得模板
const { templates } = await component.getTemplates();
每个模板都有 id, (中文(简体) ), name, (中文(简体) ), language,以及 isCustom附加可选 description, (中文(简体) ), templateType, (中文(简体) ), outputLanguages,以及 sections。 。 。 .
建筑
本构成部分使用a PostMessageHandler 工具类:
- 管理信件收听器并清理
- 使用独有的ID跟踪待决请求
- 处理响应关联
- 确保适当清理销毁部件
反应组件特性
反应组件( R)CortiEmbeddedReact)作为额外出口,提供:
- 基于 Hook 的 API 访问数字 :
useCortiEmbeddedApi(ref)暴露有实例限制的方法(auth, (中文(简体) ),navigate, (中文(简体) ),createInteraction, (中文(简体) ),showDeviceLinkQR页:1 - 一般事件流数字 :
onEvent收到包装eventCustomEvent,与event.detail形状为{ name, payload } - 状态钩数字 :
useCortiEmbeddedStatus(ref)保持最新状态/反应状态 - 多机构安全: API 方法被设定为您通过
- 反应道具: 标准反应道具如
className, (中文(简体) ),style等 (中文(简体) ).
反应组件导入
import {
CortiEmbeddedReact,
CortiEmbedded, // Web component also available
type CortiEmbeddedReactRef,
useCortiEmbeddedApi,
useCortiEmbeddedStatus,
} from "@corti/embedded-web/react";
事件收听器设置
- 使用
onEvent作为包装的全副听者event流线. onEvent接收原始数据eventCustomEvent,以及event.detail形状如下:{ name: string; payload: unknown }。 。 。 .- 通用流包括:
embedded.ready以及我们文件中列出的其他已转发的嵌入事件. onReady是原始事物的方便倾听者embedded.readyCustomEvent。 。 。 .error.triggered未通过onEvent它会去onError换句话说.- 完整活动目录和有效载荷细节记录在:
onEvent, (中文(简体) ),onReady,以及onError穿过生地CustomEvent。 。 。 .
<CortiEmbeddedReact
baseURL="https://assistant.eu.corti.app"
onEvent={event => {
console.log(event.detail.name, event.detail.payload);
}}
onReady={event => console.log("Ready", event.detail)}
onError={event => console.error(event.detail)}
/>
API 方法( 反应)
使用具有相同组件的 API 钩:
import React, { useRef } from 'react';
import {
CortiEmbeddedReact,
type CortiEmbeddedReactRef,
useCortiEmbeddedApi,
} from '@corti/embedded-web/react';
function Example() {
const ref = useRef<CortiEmbeddedReactRef>(null);
const api = useCortiEmbeddedApi(ref);
const run = async () => {
await api.auth({ access_token: '...', token_type: 'Bearer' });
const created = await api.createInteraction({ encounter: { ... } });
await api.navigate({ path: `/session/${created.id}` });
};
return (
<>
<button onClick={() => void run()}>Run</button>
<CortiEmbeddedReact ref={ref} baseURL="https://assistant.eu.corti.app" />
</>
);
}
详细反应用法示例见 文件/反应-使用.md。 。 。 .
关于配置迁移细节,见 文件/移民指南.md 财务报告和审定财务报表 文件/折旧时间线.md。 。 。 .
软件包结构
- 默认导出仅限网页部分(
dist/web-bundle.js,可读非最小捆绑) - 反应导出:网络组件+反应组件(
@corti/embedded-web/react(中文(简体) ) - 无依赖关系: Web 组件捆绑没有外部依赖性
- 同伴依赖关系: React 组件仅要求作为对等依赖的 React