umd-demo.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. <!doctype html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>UMD格式SDK演示 - AMD模块加载器</title>
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. box-sizing: border-box;
  12. }
  13. body {
  14. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  15. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  16. min-height: 100vh;
  17. padding: 20px;
  18. }
  19. .container {
  20. max-width: 800px;
  21. margin: 0 auto;
  22. background: white;
  23. border-radius: 12px;
  24. box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
  25. overflow: hidden;
  26. }
  27. .header {
  28. background: #2c3e50;
  29. color: white;
  30. padding: 30px;
  31. text-align: center;
  32. }
  33. .header h1 {
  34. font-size: 2.5rem;
  35. margin-bottom: 10px;
  36. }
  37. .header p {
  38. font-size: 1.1rem;
  39. opacity: 0.9;
  40. }
  41. .content {
  42. padding: 30px;
  43. }
  44. .demo-section {
  45. margin-bottom: 30px;
  46. }
  47. .demo-section h2 {
  48. color: #2c3e50;
  49. margin-bottom: 15px;
  50. border-bottom: 2px solid #3498db;
  51. padding-bottom: 5px;
  52. }
  53. .config-form {
  54. display: grid;
  55. gap: 15px;
  56. margin-bottom: 20px;
  57. }
  58. .form-group {
  59. display: flex;
  60. flex-direction: column;
  61. }
  62. .form-group label {
  63. font-weight: 600;
  64. margin-bottom: 5px;
  65. color: #2c3e50;
  66. }
  67. .form-group input {
  68. padding: 10px;
  69. border: 2px solid #ddd;
  70. border-radius: 6px;
  71. font-size: 14px;
  72. transition: border-color 0.3s;
  73. }
  74. .form-group input:focus {
  75. outline: none;
  76. border-color: #3498db;
  77. }
  78. .buttons {
  79. display: flex;
  80. gap: 10px;
  81. flex-wrap: wrap;
  82. }
  83. .btn {
  84. padding: 12px 20px;
  85. border: none;
  86. border-radius: 6px;
  87. font-size: 14px;
  88. font-weight: 600;
  89. cursor: pointer;
  90. transition: all 0.3s;
  91. text-decoration: none;
  92. display: inline-flex;
  93. align-items: center;
  94. justify-content: center;
  95. }
  96. .btn-primary {
  97. background: #3498db;
  98. color: white;
  99. }
  100. .btn-primary:hover {
  101. background: #2980b9;
  102. transform: translateY(-1px);
  103. }
  104. .btn-success {
  105. background: #27ae60;
  106. color: white;
  107. }
  108. .btn-success:hover {
  109. background: #229954;
  110. transform: translateY(-1px);
  111. }
  112. .btn-danger {
  113. background: #e74c3c;
  114. color: white;
  115. }
  116. .btn-danger:hover {
  117. background: #c0392b;
  118. transform: translateY(-1px);
  119. }
  120. .btn:disabled {
  121. background: #bdc3c7;
  122. cursor: not-allowed;
  123. transform: none;
  124. }
  125. .status {
  126. background: #f8f9fa;
  127. border-left: 4px solid #3498db;
  128. padding: 15px;
  129. margin: 20px 0;
  130. border-radius: 4px;
  131. }
  132. .log {
  133. background: #1a1a1a;
  134. color: #00ff00;
  135. padding: 15px;
  136. border-radius: 6px;
  137. font-family: "Courier New", monospace;
  138. font-size: 12px;
  139. max-height: 300px;
  140. overflow-y: auto;
  141. margin: 20px 0;
  142. }
  143. .log-entry {
  144. margin-bottom: 5px;
  145. line-height: 1.4;
  146. }
  147. .info-box {
  148. background: #e8f4fd;
  149. border: 1px solid #b3e0ff;
  150. border-radius: 6px;
  151. padding: 15px;
  152. margin: 20px 0;
  153. }
  154. .info-box h3 {
  155. color: #0066cc;
  156. margin-bottom: 10px;
  157. }
  158. .info-box ul {
  159. margin-left: 20px;
  160. }
  161. .info-box li {
  162. margin-bottom: 5px;
  163. }
  164. .back-link {
  165. display: inline-block;
  166. margin-top: 20px;
  167. color: #3498db;
  168. text-decoration: none;
  169. font-weight: 600;
  170. }
  171. .back-link:hover {
  172. text-decoration: underline;
  173. }
  174. .loading {
  175. color: #f39c12;
  176. }
  177. .success {
  178. color: #27ae60;
  179. }
  180. .error {
  181. color: #e74c3c;
  182. }
  183. /* 实时识别结果样式 */
  184. .realtime-display {
  185. background: #f8f9fa;
  186. border: 1px solid #e9ecef;
  187. border-radius: 8px;
  188. padding: 20px;
  189. margin: 20px 0;
  190. }
  191. .caption-container {
  192. margin-bottom: 20px;
  193. }
  194. .caption-container h3 {
  195. color: #2c3e50;
  196. margin-bottom: 10px;
  197. font-size: 16px;
  198. }
  199. .caption-text {
  200. background: white;
  201. border: 1px solid #ddd;
  202. border-radius: 6px;
  203. padding: 15px;
  204. min-height: 60px;
  205. font-size: 14px;
  206. line-height: 1.5;
  207. color: #333;
  208. }
  209. .status-info {
  210. display: grid;
  211. grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  212. gap: 15px;
  213. margin-top: 20px;
  214. padding-top: 20px;
  215. border-top: 1px solid #e9ecef;
  216. }
  217. .status-item {
  218. display: flex;
  219. justify-content: space-between;
  220. align-items: center;
  221. padding: 8px 12px;
  222. background: white;
  223. border: 1px solid #e9ecef;
  224. border-radius: 4px;
  225. }
  226. .status-item .label {
  227. font-weight: 600;
  228. color: #6c757d;
  229. }
  230. .status-item span:last-child {
  231. color: #495057;
  232. font-family: "Courier New", monospace;
  233. font-size: 12px;
  234. }
  235. </style>
  236. </head>
  237. <body>
  238. <div class="container">
  239. <div class="header">
  240. <h1>🌐 UMD格式SDK演示</h1>
  241. <p>使用AMD模块加载器演示SDK功能</p>
  242. </div>
  243. <div class="content">
  244. <div class="demo-section">
  245. <h2>📦 SDK加载状态</h2>
  246. <div class="status" id="sdkStatus">
  247. <div id="statusText">等待加载SDK...</div>
  248. </div>
  249. <div class="buttons">
  250. <button class="btn btn-primary" onclick="loadUmdSdk()" id="loadBtn">加载UMD SDK</button>
  251. </div>
  252. </div>
  253. <div class="demo-section">
  254. <h2>🔧 SDK配置</h2>
  255. <div class="config-form">
  256. <div class="form-group">
  257. <label for="appId">App ID:</label>
  258. <input
  259. type="text"
  260. id="appId"
  261. placeholder="请输入Agora App ID"
  262. value="f6ef0878d92340f88cff5c3e3d73bad2"
  263. />
  264. </div>
  265. <div class="form-group">
  266. <label for="certificate">Certificate:</label>
  267. <input
  268. type="text"
  269. id="certificate"
  270. placeholder="请输入Agora Certificate"
  271. value="d16304cc8bb34bccbae589835141926f"
  272. />
  273. </div>
  274. <div class="form-group">
  275. <label for="channel">频道名称:</label>
  276. <input
  277. type="text"
  278. id="channel"
  279. value="umd-demo-channel"
  280. placeholder="请输入频道名称"
  281. />
  282. </div>
  283. <div class="form-group">
  284. <label for="userName">用户名称:</label>
  285. <input type="text" id="userName" value="UMD Demo User" placeholder="请输入用户名称" />
  286. </div>
  287. </div>
  288. <div class="buttons">
  289. <button class="btn btn-primary" onclick="initializeSdk()" id="initBtn" disabled>
  290. 初始化SDK
  291. </button>
  292. <button
  293. class="btn btn-success"
  294. onclick="testTranscription()"
  295. id="transcribeBtn"
  296. disabled
  297. >
  298. 测试转录功能
  299. </button>
  300. <button class="btn btn-danger" onclick="cleanup()" id="cleanupBtn" disabled>
  301. 清理资源
  302. </button>
  303. </div>
  304. </div>
  305. <div class="demo-section">
  306. <h2>🎯 实时识别结果</h2>
  307. <div class="realtime-display" id="realtimeDisplay">
  308. <div class="caption-container">
  309. <h3>📝 原文识别</h3>
  310. <div class="caption-text" id="originalText">等待识别结果...</div>
  311. </div>
  312. <div class="caption-container">
  313. <h3>🌐 翻译结果</h3>
  314. <div class="caption-text" id="translatedText">等待翻译结果...</div>
  315. </div>
  316. <div class="status-info">
  317. <div class="status-item">
  318. <span class="label">任务ID:</span>
  319. <span id="taskId">未开始</span>
  320. </div>
  321. <div class="status-item">
  322. <span class="label">状态:</span>
  323. <span id="transcriptionStatus">未开始</span>
  324. </div>
  325. <div class="status-item">
  326. <span class="label">开始时间:</span>
  327. <span id="startTime">未开始</span>
  328. </div>
  329. </div>
  330. </div>
  331. </div>
  332. <div class="demo-section">
  333. <h2>📋 测试日志</h2>
  334. <div class="log" id="testLog">
  335. <div class="log-entry">欢迎使用UMD格式SDK演示页面!</div>
  336. </div>
  337. <button class="btn" onclick="clearLog()">清空日志</button>
  338. </div>
  339. <div class="info-box">
  340. <h3>💡 使用说明</h3>
  341. <p>此页面演示了UMD格式SDK的使用方式:</p>
  342. <ul>
  343. <li><strong>全局变量方式</strong>: 通过 window.SttSdkCore 访问SDK</li>
  344. <li><strong>直接script引入</strong>: 无需构建工具,直接使用</li>
  345. <li><strong>兼容性好</strong>: 支持各种浏览器环境</li>
  346. </ul>
  347. <p>UMD格式的优势:</p>
  348. <ul>
  349. <li>无需构建工具即可使用</li>
  350. <li>适合快速原型开发和演示</li>
  351. <li>兼容现代浏览器环境</li>
  352. </ul>
  353. </div>
  354. <a href="/" class="back-link">← 返回主应用</a>
  355. </div>
  356. </div>
  357. <!-- 直接使用script标签加载UMD格式的SDK -->
  358. <!-- <script src="/packages/stt-sdk-core/dist/index.umd.js"></script> -->
  359. <script src="https://unpkg.com/d8d-stt-sdk-core@1.0.0/dist/index.umd.js"></script>
  360. <script>
  361. let sdk = null
  362. let sttManager = null
  363. let rtmManager = null
  364. let rtcManager = null
  365. let isSdkInitialized = false
  366. let isRtcManagerJoined = false
  367. // 添加测试日志
  368. function addTestLog(message, type = "info") {
  369. const log = document.getElementById("testLog")
  370. const entry = document.createElement("div")
  371. entry.className = "log-entry"
  372. const timestamp = new Date().toLocaleTimeString()
  373. const prefix = type === "error" ? "❌" : type === "success" ? "✅" : "📝"
  374. entry.innerHTML = `<span class="${type}">${prefix} ${timestamp}: ${message}</span>`
  375. log.appendChild(entry)
  376. log.scrollTop = log.scrollHeight
  377. }
  378. // 更新状态显示
  379. function updateStatus(message, type = "info") {
  380. const statusText = document.getElementById("statusText")
  381. statusText.innerHTML = message
  382. statusText.className = type
  383. }
  384. // 清空日志
  385. function clearLog() {
  386. const log = document.getElementById("testLog")
  387. log.innerHTML = '<div class="log-entry">日志已清空</div>'
  388. }
  389. // 检查UMD SDK加载状态
  390. function loadUmdSdk() {
  391. addTestLog("检查UMD SDK加载状态...")
  392. updateStatus("检查SDK加载状态...", "loading")
  393. // 检查是否已加载
  394. if (window.SttSdkCore) {
  395. addTestLog("✅ UMD SDK已加载", "success")
  396. updateStatus("UMD SDK已加载", "success")
  397. enableButtons()
  398. } else {
  399. addTestLog("❌ UMD SDK未加载,请确保script标签正确引入", "error")
  400. updateStatus("UMD SDK加载失败", "error")
  401. }
  402. }
  403. // 更新实时识别结果
  404. function updateRealtimeDisplay(textstream) {
  405. // 根据数据类型更新显示
  406. if (textstream.dataType === "transcribe") {
  407. // 原文识别结果
  408. const originalText = document.getElementById("originalText")
  409. if (textstream.words && textstream.words.length > 0) {
  410. const text = textstream.words.map((word) => word.text || "").join(" ")
  411. originalText.textContent = text
  412. }
  413. } else if (textstream.dataType === "translate") {
  414. // 翻译结果
  415. const translatedText = document.getElementById("translatedText")
  416. if (textstream.trans && textstream.trans.length > 0) {
  417. const translations = textstream.trans
  418. .map(
  419. (trans, index) =>
  420. `翻译${index + 1} (${textstream.culture || "未知"}): ${trans.text || ""}`,
  421. )
  422. .join("\n")
  423. translatedText.textContent = translations
  424. }
  425. }
  426. // 更新状态信息
  427. document.getElementById("taskId").textContent = textstream.uid || "未知"
  428. document.getElementById("transcriptionStatus").textContent =
  429. textstream.dataType === "transcribe" ? "转录中" : "翻译中"
  430. document.getElementById("startTime").textContent = new Date(
  431. textstream.time || Date.now(),
  432. ).toLocaleTimeString()
  433. }
  434. // 初始化SDK
  435. function initializeSdk() {
  436. const appId = document.getElementById("appId").value
  437. const certificate = document.getElementById("certificate").value
  438. const channel = document.getElementById("channel").value
  439. const userName = document.getElementById("userName").value
  440. if (!appId || !certificate) {
  441. addTestLog("请填写App ID和Certificate", "error")
  442. return
  443. }
  444. if (!window.SttSdkCore) {
  445. addTestLog("UMD SDK未加载,请先加载SDK", "error")
  446. return
  447. }
  448. addTestLog("开始初始化UMD SDK...")
  449. try {
  450. // 使用UMD格式的SDK
  451. const SttSdk = window.SttSdkCore.default || window.SttSdkCore.SttSdk
  452. sdk = new SttSdk()
  453. sdk
  454. .initialize({
  455. appId: appId,
  456. certificate: certificate,
  457. logLevel: "info",
  458. })
  459. .then(() => {
  460. isSdkInitialized = true
  461. addTestLog("UMD SDK初始化成功", "success")
  462. updateStatus("SDK已初始化", "success")
  463. // 创建管理器
  464. rtmManager = sdk.createRtmManager()
  465. sttManager = sdk.createSttManager(rtmManager)
  466. rtcManager = sdk.createRtcManager()
  467. // 监听RTM事件
  468. rtmManager.on("sttDataChanged", (data) => {
  469. addTestLog("收到STT数据: " + JSON.stringify(data))
  470. })
  471. // 监听RTC文本流事件
  472. rtcManager.on("textstreamReceived", (textstream) => {
  473. addTestLog("收到文本流数据: " + JSON.stringify(textstream))
  474. updateRealtimeDisplay(textstream)
  475. })
  476. addTestLog("STT、RTM和RTC管理器创建成功", "success")
  477. document.getElementById("transcribeBtn").disabled = false
  478. document.getElementById("cleanupBtn").disabled = false
  479. })
  480. .catch((error) => {
  481. addTestLog("SDK初始化失败: " + error, "error")
  482. })
  483. } catch (error) {
  484. addTestLog("SDK初始化异常: " + error, "error")
  485. }
  486. }
  487. // 测试转录功能
  488. function testTranscription() {
  489. if (!sttManager || !rtcManager) {
  490. addTestLog("STT管理器或RTC管理器未初始化", "error")
  491. return
  492. }
  493. const channel = document.getElementById("channel").value
  494. const userName = document.getElementById("userName").value
  495. addTestLog("开始测试转录功能...")
  496. // 生成随机用户ID
  497. const genRandomUserId = () => Math.floor(Math.random() * 1000000)
  498. const userId = genRandomUserId()
  499. sttManager
  500. .init({
  501. userId: userId,
  502. channel: channel,
  503. userName: userName,
  504. })
  505. .then(() => {
  506. addTestLog("STT管理器初始化成功", "success")
  507. // 加入RTC频道
  508. return rtcManager.join({
  509. channel: channel,
  510. userId: userId,
  511. })
  512. })
  513. .then(() => {
  514. addTestLog("RTC频道加入成功", "success")
  515. isRtcManagerJoined = true
  516. // 创建音视频轨道
  517. return rtcManager.createTracks()
  518. })
  519. .then(() => {
  520. addTestLog("音视频轨道创建成功", "success")
  521. // 发布音视频流
  522. return rtcManager.publish()
  523. })
  524. .then(() => {
  525. addTestLog("音视频流发布成功", "success")
  526. // 开始转录
  527. return sttManager.startTranscription({
  528. languages: [{ source: "zh-CN" }],
  529. })
  530. })
  531. .then(() => {
  532. addTestLog("转录功能启动成功", "success")
  533. // 模拟10秒后停止转录
  534. setTimeout(() => {
  535. if (sttManager) {
  536. sttManager
  537. .stopTranscription()
  538. .then(() => {
  539. addTestLog("转录功能停止成功", "success")
  540. })
  541. .catch((error) => {
  542. addTestLog("停止转录失败: " + error, "error")
  543. })
  544. }
  545. }, 10000)
  546. })
  547. .catch((error) => {
  548. addTestLog("转录功能测试失败: " + error, "error")
  549. })
  550. }
  551. // 重置实时显示
  552. function resetRealtimeDisplay() {
  553. document.getElementById("originalText").textContent = "等待识别结果..."
  554. document.getElementById("translatedText").textContent = "等待翻译结果..."
  555. document.getElementById("taskId").textContent = "未开始"
  556. document.getElementById("transcriptionStatus").textContent = "未开始"
  557. document.getElementById("startTime").textContent = "未开始"
  558. }
  559. // 清理资源
  560. function cleanup() {
  561. addTestLog("开始清理资源...")
  562. if (sttManager) {
  563. sttManager
  564. .destroy()
  565. .then(() => {
  566. addTestLog("STT管理器销毁成功", "success")
  567. sttManager = null
  568. })
  569. .catch((error) => {
  570. addTestLog("STT管理器销毁失败: " + error, "error")
  571. })
  572. }
  573. if (rtmManager) {
  574. rtmManager
  575. .destroy()
  576. .then(() => {
  577. addTestLog("RTM管理器销毁成功", "success")
  578. rtmManager = null
  579. })
  580. .catch((error) => {
  581. addTestLog("RTM管理器销毁失败: " + error, "error")
  582. })
  583. }
  584. if (rtcManager) {
  585. rtcManager
  586. .destroy()
  587. .then(() => {
  588. addTestLog("RTC管理器销毁成功", "success")
  589. rtcManager = null
  590. isRtcManagerJoined = false
  591. })
  592. .catch((error) => {
  593. addTestLog("RTC管理器销毁失败: " + error, "error")
  594. })
  595. }
  596. if (sdk) {
  597. sdk
  598. .destroy()
  599. .then(() => {
  600. addTestLog("SDK销毁成功", "success")
  601. sdk = null
  602. isSdkInitialized = false
  603. updateStatus("资源已清理", "info")
  604. document.getElementById("transcribeBtn").disabled = true
  605. document.getElementById("cleanupBtn").disabled = true
  606. resetRealtimeDisplay()
  607. })
  608. .catch((error) => {
  609. addTestLog("SDK销毁失败: " + error, "error")
  610. })
  611. }
  612. }
  613. // 启用按钮
  614. function enableButtons() {
  615. document.getElementById("initBtn").disabled = false
  616. }
  617. // 页面加载完成后检查SDK状态
  618. window.addEventListener("load", function () {
  619. addTestLog("页面加载完成,检查UMD SDK状态...")
  620. // 延迟检查,确保script标签已加载
  621. setTimeout(() => {
  622. loadUmdSdk()
  623. }, 100)
  624. })
  625. </script>
  626. </body>
  627. </html>