first commit

This commit is contained in:
Song367 2025-06-17 20:43:31 +08:00
commit 3ebdf2931b
2 changed files with 20511 additions and 0 deletions

20132
duix/duix.js Normal file

File diff suppressed because it is too large Load Diff

379
simple.html Normal file
View 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>