first commit
This commit is contained in:
		
						commit
						3ebdf2931b
					
				
							
								
								
									
										20132
									
								
								duix/duix.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20132
									
								
								duix/duix.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										379
									
								
								simple.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								simple.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,379 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="zh"> | ||||
| 
 | ||||
| <head> | ||||
|   <meta charset="UTF-8" /> | ||||
|   <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||
|   <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> | ||||
|   <meta http-equiv="Pragma" content="no-cache" /> | ||||
|   <meta http-equiv="expires" content="0" /> | ||||
|   <meta name="viewport" content="width=device-width,initial-scale=1.0,maximu-scale=1.0,user-scalable=no" /> | ||||
|   <title>Duix Sdk Simple Example</title> | ||||
|   <style> | ||||
|     :root { | ||||
|       --primary-100: #FF7F50; | ||||
|       --primary-200: #dd6236; | ||||
|       --primary-300: #8f1e00; | ||||
|       --accent-100: #8B4513; | ||||
|       --accent-200: #ffd299; | ||||
|       --text-100: #000000; | ||||
|       --text-200: #2c2c2c; | ||||
|       --bg-100: #F7EEDD; | ||||
|       --bg-200: #ede4d3; | ||||
|       --bg-300: #c4bcab; | ||||
|     } | ||||
| 
 | ||||
|     html, | ||||
|     body { | ||||
|       margin: 0; | ||||
|       padding: 0; | ||||
|       font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; | ||||
|       background: var(--bg-100); | ||||
|     } | ||||
| 
 | ||||
|     .modal { | ||||
|       position: fixed; | ||||
|       left: 0; | ||||
|       top: 0; | ||||
|       width: 100vw; | ||||
|       height: 100vh; | ||||
|       overflow: auto; | ||||
|       background: rgba(247, 238, 221, 0.95); | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|     } | ||||
| 
 | ||||
|     .modal-content { | ||||
|       background-color: transparent; | ||||
|       padding: 20px; | ||||
|       width: auto; | ||||
|       border-radius: 0; | ||||
|       box-shadow: none; | ||||
|       animation: fadeIn 0.3s ease-out; | ||||
|     } | ||||
| 
 | ||||
|     @keyframes fadeIn { | ||||
|       from { opacity: 0; transform: translateY(-20px); } | ||||
|       to { opacity: 1; transform: translateY(0); } | ||||
|     } | ||||
| 
 | ||||
|     .container { | ||||
|       width: 100vw; | ||||
|       height: 100vh; | ||||
|       background: var(--bg-200); | ||||
|     } | ||||
| 
 | ||||
|     .item { | ||||
|       margin-bottom: 20px; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .item>span { | ||||
|       font-size: 24px; | ||||
|       font-weight: 600; | ||||
|       margin-bottom: 20px; | ||||
|       color: var(--text-200); | ||||
|     } | ||||
| 
 | ||||
|     .input { | ||||
|       background: var(--bg-100); | ||||
|       height: 48px; | ||||
|       border: 1px solid var(--accent-100); | ||||
|       outline: none; | ||||
|       border-radius: 8px; | ||||
|       padding: 0 16px; | ||||
|       width: 100%; | ||||
|       box-sizing: border-box; | ||||
|       font-size: 16px; | ||||
|       transition: all 0.3s ease; | ||||
|       color: var(--text-200); | ||||
|       margin-bottom: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .input:focus { | ||||
|       border-color: var(--primary-100); | ||||
|       box-shadow: 0 0 0 3px var(--accent-200); | ||||
|     } | ||||
| 
 | ||||
|     .btn { | ||||
|       border: none; | ||||
|       border-radius: 8px; | ||||
|       height: 48px; | ||||
|       background: var(--primary-100); | ||||
|       color: white; | ||||
|       cursor: pointer; | ||||
|       font-size: 16px; | ||||
|       font-weight: 600; | ||||
|       transition: all 0.3s ease; | ||||
|       padding: 0 24px; | ||||
|     } | ||||
| 
 | ||||
|     .btn:hover { | ||||
|       transform: translateY(-2px); | ||||
|       box-shadow: 0 6px 8px rgba(0,0,0,0.15); | ||||
|       background: var(--primary-200); | ||||
|     } | ||||
| 
 | ||||
|     .btn-config { | ||||
|       position: absolute; | ||||
|       top: 20px; | ||||
|       right: 20px; | ||||
|       background: var(--accent-100); | ||||
|       color: white; | ||||
|       border: none; | ||||
|       border-radius: 50%; | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|       font-size: 20px; | ||||
|       cursor: pointer; | ||||
|       transition: all 0.3s ease; | ||||
|       transform: rotate(0deg); | ||||
|     } | ||||
| 
 | ||||
|     .btn-config:hover { | ||||
|       transform: rotate(90deg); | ||||
|       background: var(--primary-200); | ||||
|     } | ||||
| 
 | ||||
|     .btn:active { | ||||
|       transform: translateY(0); | ||||
|     } | ||||
|   </style> | ||||
|   <script src="https://cdn.bootcss.com/eruda/1.3.2/eruda.min.js"></script> | ||||
|   <script>eruda.init()</script> | ||||
|   <script src="./duix/duix.js"></script> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
|   <!-- 数字人容器 --> | ||||
|   <div class="container"></div> | ||||
| 
 | ||||
|   <div id="modal" class="modal"> | ||||
|     <div class="modal-content" style="text-align: center; padding: 20px; position: relative;"> | ||||
|       <button id="configBtn" class="btn-config" onclick="toggleConfig()">⚙️</button> | ||||
|       <div id="configSection" style="display: none;"> | ||||
|         <!-- <div style="margin-bottom: 8px; width: 100%; text-align: left; color: var(--text-200);">签名密钥</div> --> | ||||
|         <input class="input" style="display: none;" id="sign" placeholder="请输入您的签名密钥" value="" /> | ||||
|         <input class="input" style="display: none;" id="audio" placeholder="音色" value="" /> | ||||
|         <div style="margin-bottom: 8px; width: 100%; text-align: left; color: var(--text-200);">性别</div> | ||||
|         <select class="input" id="gender" style="margin-bottom: 16px;"> | ||||
|           <option value="male" selected>男</option> | ||||
|           <option value="female" >女</option> | ||||
|         </select> | ||||
|         <div style="margin-bottom: 8px; width: 100%; text-align: left; color: var(--text-200);">会话ID</div> | ||||
|         <input class="input" id="conversationId" placeholder="请输入会话ID" value="1920410565458886658" title="请输入会话ID" /> | ||||
|       </div> | ||||
|       <button id="start" onclick="init()" class="btn" style="width: 200px; margin: 20px auto 0;"> | ||||
|         <span>开始智能会话</span> | ||||
|       </button> | ||||
|     </div> | ||||
|   </div> | ||||
|   <script> | ||||
|     const duix = new DUIX() | ||||
| 
 | ||||
|     const sex = { | ||||
|       "male": "1920410565458886658", | ||||
|       "female": "1933000305591988225" | ||||
|     } | ||||
|     let conversationL = "" | ||||
|     const sex_audio = { | ||||
|       "male": "gongzheng-v2", | ||||
|       "female": "presenter_female" | ||||
|     } | ||||
|     const audio = document.getElementById('audio') | ||||
|     // Add event listener for gender selection | ||||
|     document.getElementById('gender').addEventListener('change', function(e) { | ||||
|       const selectedGender = e.target.value; | ||||
|       const conversationIdInput = document.getElementById('conversationId'); | ||||
|        | ||||
|       conversationIdInput.value = sex[selectedGender]; | ||||
|       audio.value = sex_audio[selectedGender] | ||||
|     }); | ||||
| 
 | ||||
|     // Set initial conversation ID based on default gender | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|       const genderSelect = document.getElementById('gender'); | ||||
|       const conversationIdInput = document.getElementById('conversationId'); | ||||
|       conversationIdInput.value = sex[genderSelect.value]; | ||||
|       audio.value = sex_audio[genderSelect.value] | ||||
|     }); | ||||
| 
 | ||||
|     async function getToken() { | ||||
|       try { | ||||
|         const response = await fetch('http://192.168.2.183:8080/token', { | ||||
|           method: 'POST', | ||||
|           headers: { | ||||
|             'Content-Type': 'application/json', | ||||
|           } | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         return data.token; | ||||
|       } catch (error) { | ||||
|         console.error('Error getting token:', error); | ||||
|         throw error; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function toggleConfig() { | ||||
|       const configSection = document.getElementById('configSection'); | ||||
|       if (configSection.style.display === 'none') { | ||||
|         configSection.style.display = 'block'; | ||||
|       } else { | ||||
|         configSection.style.display = 'none'; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     async function init() { | ||||
|       let sign = document.querySelector('#sign').value; | ||||
|       const conversationId = document.querySelector('#conversationId').value; | ||||
| 
 | ||||
|       if (!sign) { | ||||
|         try { | ||||
|           sign = await getToken(); | ||||
|           document.querySelector('#sign').value = sign; | ||||
|         } catch (error) { | ||||
|           alert('获取token失败,请重试'); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (!conversationId) { | ||||
|         return alert('会话ID不能为空'); | ||||
|       } | ||||
| 
 | ||||
|       duix.on('error', data => { | ||||
|         console.error(data) | ||||
|       }) | ||||
|       duix.on('intialSucccess', () => { | ||||
|         console.info('intialSucccess') | ||||
|         // 此时初始化成功,可调用start | ||||
|         duix.start({ conversationId, openAsr: true, useActSection: true }).then(res => { | ||||
|           console.info('start', res) | ||||
|         }) | ||||
|       }) | ||||
|       duix.on('bye', (data) => { | ||||
|         console.info('bye', data) | ||||
|       }) | ||||
| 
 | ||||
|       duix.on('progress', progress => { | ||||
|         console.info('progress', progress) | ||||
|       }) | ||||
|       duix.on('show', () => { | ||||
|         console.info('show') | ||||
|         // 此时可确认视频已 | ||||
|         document.querySelector('#modal').style.display = "none" | ||||
|       }) | ||||
|       duix.on('openAsrSuccess', () => { | ||||
|         console.info('openAsrSuccess') | ||||
|       }) | ||||
|       duix.on('asrClose', () => { | ||||
|         console.info('asrClose') | ||||
|       }) | ||||
|       // duix.on('speakStart', (data) => { | ||||
|       //   console.info('speakStart', data) | ||||
|       // }) | ||||
|       // duix.on('speakEnd', (data) => { | ||||
|       //   console.info('speakEnd', data) | ||||
|       // }) | ||||
|       duix.on('speakSection', (data) => { | ||||
|         console.info('speakSection', data) | ||||
|       }) | ||||
|       duix.on('speakError', (data) => { | ||||
|         console.info('speakError', data) | ||||
|       }) | ||||
|       duix.on('asrResult', async (data) => { | ||||
|         console.info('asrResult', data); | ||||
|         duix.break() | ||||
|         // if (data == "你好") { | ||||
|           try { | ||||
|             const response = await fetch('http://192.168.2.183:8080/chat', { | ||||
|               method: 'POST', | ||||
|               headers: { | ||||
|                 'Content-Type': 'application/json', | ||||
|               }, | ||||
|               body: JSON.stringify({ | ||||
|                 query: data, | ||||
|                 response_mode: 'streaming', | ||||
|                 user: 'SYS002', | ||||
|                 conversation_id: conversationL, | ||||
|                 audio: audio.value | ||||
|               }) | ||||
|             }); | ||||
| 
 | ||||
|             const reader = response.body.getReader(); | ||||
|             const decoder = new TextDecoder(); | ||||
|             let fullAnswer = ''; | ||||
|             let triggered = false; | ||||
| 
 | ||||
|             while (true) { | ||||
|               const { value, done } = await reader.read(); | ||||
|               if (done) break; | ||||
| 
 | ||||
|               const chunk = decoder.decode(value); | ||||
|               const lines = chunk.split('\n'); | ||||
| 
 | ||||
|               for (const line of lines) { | ||||
|                 if (line.startsWith('data:')) { | ||||
|                   const responseData = JSON.parse(line.slice(5).trim()); | ||||
| 
 | ||||
| 
 | ||||
|                   if (responseData.audio_data) { | ||||
|                     conversationL = responseData.conversation_id | ||||
|                     duix.speak({ | ||||
|                       content: responseData.answer, | ||||
|                       audio: responseData.audio_data | ||||
|                     }) | ||||
|                      | ||||
|                   } | ||||
| 
 | ||||
| 
 | ||||
|                   // Handle end of stream | ||||
|                   if (responseData.isEnd) { | ||||
|                     break; | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } catch (error) { | ||||
|             console.error('Error in chat API:', error); | ||||
|           } | ||||
|         // } | ||||
| 
 | ||||
|         // test = [ | ||||
|         //   'https://p3-bot-sign.byteimg.com/tos-cn-i-v4nquku3lp/0f1be92489b849f3b7568e9b17334e42.wav~tplv-v4nquku3lp-image.image?rk3s=68e6b6b5&x-expires=1752754758&x-signature=rXa5LFcZttKGZpHMVIP6SgZTsRI%3D','https://p6-bot-sign.byteimg.com/tos-cn-i-v4nquku3lp/9898244b02be4765a964cf4b3d4afcd0.wav~tplv-v4nquku3lp-image.image?rk3s=68e6b6b5&x-expires=1752754726&x-signature=%2BbIrCv%2B5yAUxZvNqBURCnSRVqWo%3D','https://p9-bot-sign.byteimg.com/tos-cn-i-v4nquku3lp/4bffded0446648a2aef1d2d7e59ddd0c.wav~tplv-v4nquku3lp-image.image?rk3s=68e6b6b5&x-expires=1752754642&x-signature=E5Dr2R%2Fhd%2Ft7K593ka393OlCPNg%3D'] | ||||
|         // for (let index = 0; index < test.length; index++) { | ||||
|         //   const element = test[index]; | ||||
|         //   duix.speak({content: "我会尽量帮助您", audio: element}) | ||||
|            | ||||
|         // } | ||||
|       }); | ||||
| 
 | ||||
|       duix.on('report', data => { | ||||
|         // console.info('report', data) | ||||
|       }) | ||||
|       duix.on('speakEnd', async(data) => { | ||||
|         console.info('公证speakEnd: ', data) | ||||
| 
 | ||||
|       }) | ||||
|       duix.init({ | ||||
|         sign, | ||||
|         containerLable: '.container' | ||||
|       }).then(data => { | ||||
|         console.info('init', data) | ||||
|       }) | ||||
|     } | ||||
| 
 | ||||
|     window.addEventListener('beforeunload', function(event) { | ||||
|       if (duix) { | ||||
|         duix.destroy() | ||||
|         duix.stop() | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|   </script> | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Song367
						Song367