html_digital_item/simple.html
Song367 e2b2228d00
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
添加气泡
2025-06-20 15:00:01 +08:00

486 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>Yantu Digital human</title>
<link rel="icon" type="image/png" sizes="48x48" href="./yantu/favicon.png" />
<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);
}
.statement {
position: absolute;
bottom: 160px;
left: 80%;
transform: translate(-50%);
color: #fff;
padding: 12px;
box-sizing: border-box;
text-align: center;
background-color: rgba(27, 160, 53, 0.5);
border-radius: 12px;
visibility: hidden;
z-index: 100000;
}
.statement:empty {
display: none;
}
.subtitle {
position: absolute;
bottom: 40%;
left: 50%;
transform: translate(-50%);
color: #000;
padding: 12px;
box-sizing: border-box;
text-align: center;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 12px;
visibility: hidden;
z-index: 100000;
}
.subtitle:empty {
display: none;
}
</style>
<script src="https://cdn.bootcss.com/eruda/1.3.2/eruda.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.min.js"></script>
<script>eruda.init()</script>
<script src="./duix/duix.js"></script>
<!-- <script src="./yantu/yantoo-ava.js"></script> -->
</head>
<body>
<!-- 数字人容器 -->
<div class="container"></div>
<div class="statement"></div>
<div class="subtitle"></div>
<!-- <input class="input" style="display: block;border-color: #8f1e00;z-index: 999;" id="duihua" placeholder="输入对话" value=""> -->
<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>
<select class="input" id="answer_type" style="margin-bottom: 16px;">
<option value="jiguang" selected>极光</option>
<option value="gongzheng">公证</option>
</select>
<div style="display: none;margin-bottom: 8px; width: 100%; text-align: left; color: var(--text-200);">会话ID</div>
<input class="input" id="conversationId" style="display: none;" 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-v5",
"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]
});
let trigger_status = true
let end_talk = ""
// 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('https://srtc.yantootech.com/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"
document.querySelector('.statement').style.visibility = "visible"
document.querySelector('.subtitle').style.visibility = "visible"
})
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)
document.querySelector('.subtitle').innerText = data.content
})
duix.on('asrStop', (data) => {
console.info('asrStop', data)
document.querySelector('.statement').innerText = data.content;
});
duix.on('speakError', (data) => {
console.info('speakError', data)
})
duix.on('asrResult', async (data) => {
document.querySelector('.statement').innerText = ''
document.querySelector('.subtitle').innerText = ''
console.info('asrResult', data, trigger_status);
if (data == "小公" || data == "小共" || data == "小工"){
duix.break()
trigger_status = true
return
}
if (trigger_status) {
try {
trigger_status = false;
let plu = document.getElementById('answer_type')
api_data = {}
if (plu.value=="jiguang"){
api_data = {
"model": "bot-20250522162100-44785",
"llm_type": "ours",
"conversation_id": conversationL,
"audio": audio.value,
"stream": true,
"stream_options": {"include_usage": true},
"messages": [
{
"role": "system",
"content": "你是一个知识渊博的马克思主义研究者,能够深入且清晰地阐述马克思主义相关的理论、思想等内容,以通俗易懂的语言向用户讲解,还能结合实际案例来加深用户对马克思主义的理解。"
},
{
"role": "user",
"content": data
}
]
}
} else{
api_data = {
query: data,
response_mode: 'streaming',
user: 'SYS002',
conversation_id: conversationL,
audio: audio.value
}
}
const response = await fetch('https://srtc.yantootech.com/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(api_data)
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let pre_talk = '';
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
console.log("执行输入answer")
pre_talk = responseData.answer
duix.speak({
content: responseData.answer,
audio: responseData.audio_data
})
}
// Handle end of stream
if (responseData.isEnd) {
console.log("pretalk : ", pre_talk, "---------", trigger_status)
end_talk = pre_talk
// trigger_status = true
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["content"], "----------------", end_talk, "-----------------", trigger_status)
if(end_talk == data["content"]){
trigger_status = true
}
})
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>