共享成果服务
为应用和 DSH 对话工具提供 Office 生成与预览、TTS/ASR Provider 及媒体渲染。Studio 使用同一组组件;本包不依赖 Studio、其索引、机构登录或桌面壳。
Word、Excel、PowerPoint 可复用宿主的官方 Office 技能、结构校验和 LibreOffice Kit,支持旧 DOC/XLS/PPT 读取及转换、Excel 公式重算。Studio 的 Office PDF 导出使用同一转换器,原文件保留。宿主要求和格式边界见官方 Office 工作流。
版本为 @eduwork/[email protected],与 Studio 0.6.0 配套。DSH 集成目标严格为 0.2.1-rc.2;底层应用 API 要求 Node 24.18+,以及所用能力的运行环境。插件的稳定版本号不代表上游 DSH 已脱离 rc。
DSH 集成要求完整且版本一致的官方 0.2.1-rc.2 宿主,或兼容的 0.2.x 正式版。不要使用 --force 或 --legacy-peer-deps 绕过依赖冲突。
安装与配置
在 Node 项目中安装精确版本 @eduwork/[email protected]。本地验证也可安装已检查的压缩包:
npm install ./eduwork-dsh-artifact-services-0.3.0.tgz
使用 Studio 时,在同一命令中安装配套 Studio 包,只启用 Studio bundle,由其注册一次 Shared。见源码构建与 Profile 激活。普通 Node 应用直接调用下述 API;DSH Host 还需加载一次 /dsh 适配器。
Office 要求 Python 3.12+ 与本包 python/requirements.txt 中的依赖,DSH_OFFICE_PYTHON 指向解释器绝对路径。安装 npm 包不会安装 Python 库、ASR 模型或浏览器。TTS 的 system Provider 在 Windows 使用 System.Speech,在 macOS 使用系统 say;两者枚举已安装音色并输出 WAV,不需要 API Key。Mac 中文配音需要先在系统设置中安装中文语音,见平台要求。其他平台需要 Provider。端侧 ASR 要求宿主提供 whisper.cpp 可执行程序和模型,见转写说明。
源码另提供可选的 createDshTranscriptionProvider,用于把 DSH 0.1.7 的本地 speechToText 服务接到现有文件转写接口;需由宿主显式注册,尚未替换桌面默认引擎。它支持分段处理长音频,但不提供时间戳;需要时间戳时仍使用原 Provider。TTS 保持独立,Mac 当前未内置系统语音适配器。选项、准备步骤和能力限制见转写说明。
共享预览解析真实 DOCX/XLSX/PPTX 文件,保留 PPTX 固定页面坐标并使用内容哈希元数据。控件跟随宿主主题,文档内容保留原色。Studio 与对话附件使用同一预览契约;原生全屏和普通文档预览由宿主管理,对话最终文件可用时交给官方 present。预览保真度仍需用原生 Office 独立核对。
PDF/视频应用可从 @eduwork/dsh-artifact-services/runtime 导入 createMediaRuntime 并使用其 browserExecutable。固定部署应同时提供 DSH_MEDIA_NODE_ENV / DSH_MEDIA_BROWSER,兼容旧 ECNU_AGENT_NODE_ENV / ECNU_AGENT_REMOTION_BROWSER。已配置时不调用 ensureBrowser;未配置时实际渲染可准备本包浏览器,只读就绪检查不会下载。
运行时锁定 Remotion 4.0.520、mediabunny 1.55.5、React/React DOM 18.3.1,各调用方应解析到同一份 mediabunny。同入口的 getMediaFFmpegPath 从选定依赖所属环境解析 FFmpeg,不准备浏览器;可通过 {runtime} 传入已有运行时。
对话工具权限
Office 的新建、编辑、PDF 合并与提取遵守会话当前生效的文件写入权限。已有工作区写入权限时不重复确认;只读模式仍需本次审批。自定义权限预设以实际 sandbox policy 为准。项目相对路径、真实路径边界和禁止覆盖已有文件的约束仍生效,Full Access 也不会扩大 Office 工具的路径范围。
生图、TTS、ASR、固定模板音视频渲染及视频项目文件操作同样复用工作区写入权限,包括调用已配置的远程提供方。远程服务仍可能上传请求内容并消耗额度,但不会仅因此逐次要求确认。功能开关、服务可用性、凭据及工作区路径检查继续生效;权限检查本身不会请求音色接口或调用生成服务。只读模式仍需审批,运行可编辑视频项目代码也保留独立审批。其他宿主权限钩子继续执行。
应用接口(v1)
import {mkdtemp} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import {join} from 'node:path'
import {SpeechService, createSystemSpeechProvider} from '@eduwork/dsh-artifact-services/speech'
if (!['win32', 'darwin'].includes(process.platform)) throw new Error('This example requires Windows or macOS system speech')
const directory = await mkdtemp(join(tmpdir(), 'shared-speech-example-'))
const speech = new SpeechService()
const dispose = speech.register(createSystemSpeechProvider())
const system = (await speech.list()).find(provider => provider.id === 'system')
if (!system?.available || !system.voices.length) throw new Error('Install an OS voice first')
try {
const file = await speech.synthesize({
provider: 'system', voice: system.voices[0].id, text: 'Hello.', speed: 1,
directory, name: 'preview-1', signal: new AbortController().signal,
})
console.log(file.path) // Actual WAV; measured duration is also returned.
} finally { dispose() }
完整示例分别保存为 .mjs,在已安装本包的项目内运行。下列扩展示例是适配器模板,host*、工作区、执行上下文和取消信号由宿主提供。所有语音 Provider 使用统一的 voices() 与 synthesize(request):
speech.register({
id: 'my-tts', title: 'My speech service', local: false,
voices: async () => [{id: 'narrator', title: 'Narrator', language: 'zh-CN'}],
async synthesize({text, voice, speed, directory, name, signal, execution}) {
// Obtain credentials/permission through your host adapter. Use the exact
// text, observe cancellation, save a real WAV in an authorized location.
return hostSpeechAdapter.synthesize({text, voice, speed, directory, name, signal, execution})
},
})
execution 是可选、短期有效的宿主上下文,不得序列化或发给浏览器。音色与 Provider 错误直接返回,不自动改用其他音色、本机引擎或厂商。时长从实际 WAV 字节测量,不采信厂商估计。当前 Provider 边界要求 WAV,其他原生格式由适配器转换;字幕按实际合成片段同步,不承诺逐词时间戳。
DSH 扩展通过 ctx.artifactServices.registerSpeechProvider(provider) 使用同一注册表,Studio 与 speech_synthesize 都从这里调用。HTTP、凭据、机构音色目录属于 Provider 适配器,speech_synthesize 是共享工具权限边界。直接调用 Provider 的应用必须保留宿主执行上下文和权限策略。
图像生成采用相同分层:
import {ImageService} from '@eduwork/dsh-artifact-services/images'
const images = new ImageService()
const unregister = images.register({
id: 'my-images', title: 'My image service', local: false,
available: async () => hostImageAdapter.isConfigured(),
capabilities: {nativeSizes: ['1024x1024'], customSize: true,
fitModes: ['crop', 'pad'], formats: ['image/png']},
generate: request => hostImageAdapter.generate(request),
})
const catalog = await images.list()
const image = await images.generate({provider: 'my-images', prompt: 'A landscape illustration',
size: '1920x1080', fit: 'pad', projectPath: workspaceDirectory, signal, execution})
unregister()
Provider 接收 prompt、可选 size/fit、绝对 projectPath、短期 execution、sessionId 和 signal,返回真实工作区 PNG/JPEG/WebP/GIF/AVIF 的绝对 path;可附带 mime、size、requestedSize、generationSize、sourceRelativePath、sourceSize、resized、resizeWarning。
服务校验文件签名与工作区边界,规范化公开结果并移除其他字段;凭据留在宿主。原生尺寸选择和缩放由选定 Provider 负责,共享服务不强制某家厂商的尺寸列表。缩放失败应保留原图,报告实际尺寸与警告。
images.list() 返回 {id,title,local,available,capabilities}。没有可用 Provider 时报错,多个可用时要求明确选择,不自动回退。DSH 使用 ctx.artifactServices.registerImageProvider(provider);注册/注销触发 artifact-services/images-changed,凭据或配置变化后适配器调用 ctx.artifactServices.refreshImageProviders(),更新内置 artifact-images 技能可用性。采用 {skills:false} 的装配须自行维护相应能力过滤。
import {mkdtemp} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import {join} from 'node:path'
import {runOffice, normalizeOfficeRequest} from '@eduwork/dsh-artifact-services/office'
if (!process.env.DSH_OFFICE_PYTHON) throw new Error('Configure the Python runtime first')
const projectPath = await mkdtemp(join(tmpdir(), 'shared-office-example-'))
const result = await runOffice({projectPath, signal: new AbortController().signal,
environment: process.env,
request: normalizeOfficeRequest('document', {
action: 'create', output_path: 'report.docx',
spec: {blocks:[{type:'paragraph',text:'Hello.'}]},
}),
})
console.log(projectPath, result)
Office 支持文档和电子表格编辑、检查/验证、演示文稿布局、PDF 创建/合并/提取及 HTML 预览。演示文稿接受 speaker_notes;表格创建/编辑/追加支持 {type:'text',value:'=literal'} 与 {type:'formula',value:'=SUM(A1:A2)'}。普通字符串保留已有公式行为;公式验证不计算数值。renderOfficePreview() 提供有界结构化 HTML 预览,并非像素级 Office 渲染。
通过 DSH_OFFICE_PYTHON 指定已安装 python/requirements.txt 的解释器,仍接受旧 CHATECNU_WORK_OFFICE_PYTHON。隔离解释器运行本包内的 Python 源码,不运行另外维护的已安装 ecnu_agent_* 脚本。依赖准备是显式部署步骤,生成请求不会安装软件;机构素材可用 DSH_OFFICE_BRAND_ASSETS 注入,本包不内置。
import {mkdtemp} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import {join} from 'node:path'
import {renderMedia} from '@eduwork/dsh-artifact-services/media'
import {createMediaProviders} from '@eduwork/dsh-artifact-services/providers'
import {loadMusicCatalog} from '@eduwork/dsh-artifact-services/music'
const directory = await mkdtemp(join(tmpdir(), 'shared-video-example-'))
const providers = createMediaProviders()
const disposeMusic = await loadMusicCatalog(providers)
try {
const file = await renderMedia({id:'overview',kind:'video',title:'Overview',
segments:[{heading:'One idea',bullets:['A short point'],narration:''}],
options:{narration:false,subtitles:false,sceneSeconds:3,aspect:'16:9',bgm:'quiet-explanation'},
}, directory, new AbortController().signal, console.log, providers)
console.log(file.path) // A real MP4 with BGM, without narration or subtitles.
} finally { disposeMusic() }
结构化音视频与可编辑 Remotion 项目使用 lib/remotion.js。可编辑运行器保留源码编辑、暂存、完整性绑定的语音任务、完整验证、封面和质量检查帧。runVideoCommand(command, options, runtime) 是调用入口;createMediaRuntime() 解析组件自身依赖,也可注入校验过的托管运行时。旧 CLI 环境检查仍为兼容启动器保留。
DSH 装配
只加载一次 @eduwork/dsh-artifact-services/dsh。它提供 artifactServices、六个通用技能,以及启用且可用时的 artifact-images;默认十个工具,另有三个可选图像工具:
| 工具 | 职责 |
|---|---|
office_document、office_spreadsheet、office_presentation、office_pdf | Office 操作,使用工作区相对路径 |
speech_voices、speech_synthesize | Provider、音色、配乐发现及语音合成 |
image_providers、image_generate、image_edit | 配置 images.enabled:true 后提供图像发现/生成 |
speech_transcription_providers、speech_transcribe | 音频文件转写服务发现和转写 |
media_render | 结构化音视频生成 |
video_project | 可编辑项目初始化、暂存、语音任务、验证与渲染 |
不要同时注册旧 tool-office。权限、凭据和成果发布留在 DSH;工具将取消信号和原始执行上下文传给嵌套厂商工具。{skills:false} 允许产品自行管理通用技能;{bgmRoot} 可选择其他校验过的目录,默认使用随包六首配乐。
素材、构建与兼容性
- 六首器乐配乐包含乐谱 JSON、确定性合成代码、192 kbps MP3 以及哈希、音量、循环元数据,见配乐使用与许可。
templates/structured是结构化视频源码,templates/editable是可修改起始项目;它们共用渲染器。- 不含第三方音频采样或机构 Logo。Remotion 遵循自身许可证。
- Office 能力限定于已支持的 OOXML/PDF 特性,不支持宏、修订记录、动画编辑或公式计算。
- 测试需配置 Python;父仓覆盖 Office 编辑/预览/验证、Provider 契约、配乐完整性、视频运行器与浏览器检查。
图像与平台配置
DSH 服务默认关闭生图。部署方须在 ArtifactServices 插件配置中显式设置 images: { enabled: true },统一开启工具、技能与 Provider 调用。Office 和视频中的本地图片不受影响,语音与视频能力也独立于此选项。
内置系统 TTS 支持 Windows。其他平台需要注册语音 Provider 并提供兼容的原生资源,见平台要求。
图像 Provider 可选实现 edit(request),沿用 generate 的工作区、取消信号与结果契约;输入为 images 路径数组及可选 mask,通过 images.edit(request) / image_edit 调用。目录仅对实现编辑的 Provider 声明 capabilities.edit:true;不自动回退到生成。输入与输出均限制在工作区,结果须另存,复用工作区写入权限。
DSH 内部工具调用
@eduwork/dsh-artifact-services/tool-execution 导出 executeGovernedTool(ctx, input),供服务发起单个内部工具调用。0.2.2-rc.1 使用官方 ToolExecutionPipeline,旧宿主使用单调用接口;调用者应原样传递 agent、signal、toolSet、rootCallId 和 parent(如有)。模型产生的整批工具调用仍交给 DSH 执行器管理,不能用这个入口替换批次调度。