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