기초공사 (html,css,javascript)

목소리인증 - 디자인 전 코드 본문

카테고리 없음

목소리인증 - 디자인 전 코드

에스프레소라떼 2024. 1. 8. 17:46

//

<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<style type="text/css">

.panel {
	margin:0 auto;
}
/* 화자등록과 화자인증만 적용 */
.l-btn {
	overflow:visible;
	/* background:#e9d9ff; */
}

/******화자등록 / 화자인증 button *******/
/* Ripple Out */
@-webkit-keyframes hvr-ripple-out_border {
  100% {
    top: -12px;
    right: -12px;
    bottom: -12px;
    left: -12px;
    opacity: 0;
  }
 }

@keyframes hvr-ripple-out_border {
  100% {
    top: -12px;
    right: -12px;
    bottom: -12px;
    left: -12px;
    opacity: 0;
  }
 }

/*인증시작 버튼  */
.hvr-ripple-out {
  display: inline-block;
  vertical-align: middle;
  -webkit-transform: perspective(1px) translateZ(0);
  transform: perspective(1px) translateZ(0);
  padding:1em;
  
  margin:0.4em;
  box-shadow: 0 0 1px rgba(0, 0, 0, 0);
 /*   position: relative; */
  background:#fafafa;
}

/* on을 넣었다빼는것으로. */
.hvr-ripple-out.on {
	background:#5f4bef;
	color:#fff; 
	/* animation:hvr-ripple-out_border 1s infinite; */
}

</style>
		
<style type="text/css">	
/* MIC */

#micbox {
  /* width: 200px; */
  height: 200px;
  position: relative;
  
}

#circle1 {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  /* border: 1px solid green; */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  /* transition: all 0.3s ease; */
}
    
#circle2 {
  width: 200px;
  height: 200px;
  border-radius: 50%;
 /*  background-color: #3153af; */
  background-color:#2e517b;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  transition: all 0.1s ease;
}
    
#circle3 {
    width: 100px;
    height:100px;
    border-radius: 50%;
    border: 5px solid #c7e0f5;
    background-color: #fff;
	background-image: url('/VOIS/sttsv-visualizer/img/mic.svg');
    background-repeat:no-repeat;
	background-size:40%;
    background-position: center;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* transition: all 0.3s ease; */
}

/* progressbar */
.add-progress{
	display: flex; 
	flex-direction: row; 
}

.border {
    width: 100%;
    border-color: lightgray;
    border-style: solid;
    border-radius: 15px;
    background-color: lightgray;
}

.progress-bar {
  height: 18px;
  border-radius: 15px;
 /*  animation: widthsize 3s ease-out infinite;  */
}

.success{
   width: 50%;
   background: linear-gradient(to right, #78F5F5, #3057FA);
   transition: all 0.5s ease-out;
}

/* @keyframes widthsize {
  from {width: 0%}
  to {width: 100%}
} */
</style>

  <div class="easyui-layout" >
    <div class="easyui-panel" title="목소리인증" style="width: 70%;height:800px; max-width: 70%; padding: 30px 30px;">
        <div data-options="region:'north'" style="height:70px">
			<ul style="display: block; float: left; margin: 10px 10px;">
				 <!-- 고객ID --> 
				 <li style="float:left; margin-right:10px;">
					<input class="easyui-textbox" id="s_SpeakerId" value="" />
				 </li>
				 <li style="float:left;">
					<input class="easyui-textbox" value="0" id='s_Threshold' label="옵셋" disabled="true" labelAlign="right" labelWidth="50" />
				 </li>
			</ul>        
        </div>
        <div data-options="region:'center'" style="margin-top:30px; text-align:center;">
        	<div class="micbox-button">
	            <div id="micbox">
	            	<div id="circle1">
				        <div id="circle2"></div>
				        <div id="circle3"></div>
        			</div>
    			</div>
			</div>	  
        
			<a href="#" class="easyui-linkbutton short hvr-ripple-out" onclick="start_verify_short()" style="padding:20px; margin:0 10px;">인증시작</a>
			<a href="#" class="easyui-linkbutton stop" onclick="stop_verify_short()" style="padding:20px 35px; margin:0 10px;">중단</a>
			<!-- 
			<div class="bar" style="width:100%; float:left;">
				<div id = "enrollprogressbar" class="easyui-progressbar first-progressbar" data-options="value:50" style="margin-top:40px;"></div>
			</div>
			 -->
			  <div class="parse_pending border" style="margin-top: 40px;">
			      <div class="progress-bar success">
			      </div>
			  </div>
			  
        </div>
    </div>
  </div><!--easyui-layout  -->
			
			
<script type="text/javascript">
	// 페이지 로딩 완료 후 호출 메소드
	function loadBody() {
		initGrid();
	}
	// 컨트롤초기화
	function initGrid() {
		$btTextbox.create("#s_SpeakerId", $btTextbox.options({
			label : '고객ID',
			labelWidth : 50,
			width : 150,
			prompt: "고객ID 입력"
		}));
		
		$btTextbox.create("#s_Name", $btTextbox.options({
			label : '고객명',
			labelWidth : 50,
			width : 200,
			prompt: "고객명 입력"
		}));
		
		$btTextbox.create("#s_TellNum", $btTextbox.options({
			label : '착신번호',
			labelWidth : 60,
			width : 200,
			prompt: "착신번호 입력",
			
			//전화번호 입력시 자동하이픈 삽입
			inputEvents:$.extend({},$.fn.textbox.defaults.inputEvents,{
				keyup:function(e){
					$(this).val( $(this).val().replace(/[^0-9]/g, "").replace(/(^02|^0505|^1[0-9]{3}|^0[0-9]{2})([0-9]+)?([0-9]{4})$/,"$1-$2-$3").replace("--", "-") );  
				}
			}) 
			
		}));
		        
	}

	// 인증시작 : short term 
	function start_verify_short()
	{
		if($('#s_SpeakerId').textbox('getValue') == ""){
			alert("고객ID를 입력해주세요");
			return;
		};
	
		
		// 통화번호 부여
		dataRow = $btData.getRows("SC3000S3000", "selectTelSeq", "__", {});
		dataTeLSeq = dataRow[0].seq; 

    	start_Recording(true); // true = 최초실행
	    start_timer = setInterval(() => {
	        send_Recording();
	    }, interval_verify);	
    		
		$('.hvr-ripple-out').addClass('on');
		
}
	
	
</script>


<!-- 화자등록, 화자인증 -->
<script type="text/javascript">
var interval_verify = 1200; //1000 -> 1200 (음성파일이 1초미만이라 살짝 늘려 수정함)
var start_timer;
var send_timer;
var dataTeLSeq = 0; //통화번호 (저장전부안함으로수정)


function stop_verify_short(){
	stop_verify();
	
	$('.hvr-ripple-out').removeClass('on');
}

//등록취소
function stop_verify(){
    clearInterval(start_timer);         //타이머해제하고
    clearInterval(send_timer);

   if (rec == null) {
		return;
	}
    
    rec.stop();						// short term 레코드 초기화(누적은 진행됨) 
    javascriptNode.disconnect(); // 볼륨 측정을 중단합니다.
          
    console.log("Recording stopped");
    
}


function send_Recording(){
    clearInterval(start_timer);         //타이머해제하고
    clearInterval(send_timer);
	
	var jParams = { telSeq : dataTeLSeq };

	if(jParams)
    {
		$btData.delete("SC3000S3000", "deleteVAbyTelSeq", "__", jParams );
		$btData.delete("SC3000S3000", "deleteUVbyTelSeq", "__", jParams );
	}
	
    rec.exportWAV(createDownloadLink);
}

// 화장인증
function createDownloadLink(blob) {
    //업로드 및 다운로드 중에 사용할 .wav 파일 이름(확장자 제외)
	var x = new Date();
		let offset = x.getTimezoneOffset() * 60000; //ms단위라 60000곱해줌
		let dateOffset = new Date(x.getTime() - offset);
	var filename = dateOffset.toISOString();
          
    var fd=new FormData();		  
          fd.append("group"  	, "VIP");
          fd.append("speaker"	, $("#s_SpeakerId").val());
          fd.append("telno"		, $("#s_TellNum").val());
          fd.append("speakernm"	, $("#s_Name").val());// 이름 
          fd.append("voiceseq"	, "");
          fd.append("telseq"	, dataTeLSeq); // 통화번호
          fd.append("voice"		, blob, filename+".wav");  //(이름, 값, 파일이름)
          
    var xhr = new XMLHttpRequest();

        //verify
       	fd.append("threshold", $("#s_Threshold").val()); 
        console.log("threshold : " + $("#s_Threshold").val());
        xhr.open("POST",url_verify);
       
	    xhr.addEventListener("readystatechange", function() {
            if(this.readyState === 4){
                return_data = JSON.parse(this.responseText);
	                console.log(this.responseText);
	                if(return_data.score){
	                	show_verify_percent(0);
	                	
	                	console.log("return_data.score="+return_data.score);
	                	if(return_data.score > 0) {
	                		let thisscore = return_data.score *4; //본인이어도 -15~25 정도로만 점수가 나오므로 *4 해줌..
	                		show_verify_percent(thisscore);
	                	}
	                }else{
	                	if(return_data.status == "FAIL"){
	                		alert("return_data.status == FAIL,"+return_data.errorMessage);
	                    	stop_verify();
	                	}
	                }
	     	}
	    });
	    
	    xhr.send(fd);
	    
		stop_verify();
    	start_Recording(false); // 두번째 실행 
        send_timer = setInterval(() => {
	        send_Recording();
        }, interval_verify);
};

//progressbar
function show_verify_percent(score)
{   
	let setscore = Math.ceil(score); //올림
	if(setscore > 100) setscore = 100;
    //$('#enrollprogressbar').progressbar('setValue', setscore);
    $('.success').css("width", setscore + "%");
}

</script>


<script src="/VOIS/js/recorder.js"></script>
<script>

// 홈페이지를 이용하여 서비스를 호출한다 
var url_enroll = "/VOIS/ossm/enroll.do";            //등록 주소
var url_verify = "/VOIS/ossm/verifyOneSec.do";            //인증 주소
var url_disenroll = "/VOIS/ossm/disenroll.do";      //등록 삭제 주소
var url_recording = "/VOIS/ossm/recording.do";      //상담 파일 업로드	

var gumStream; 						//stream from getUserMedia()
var rec; 							//Recorder.js object
var input; 							//MediaStreamAudioSourceNode we'll be recording

function start_Recording(bStart)
{
	console.log("1--------------------------<Recording started>");

    var constraints = { audio:{echoCancellation: false, noiseSuppression: false, autoGainControl: false, mozNoiseSuppression: false, mozAutoGainControl: false}, video:false }
	
    // navigator.mediaDevices.getUserMedia(constraints)는 사용자의 오디오 미디어 가져옴
    // constraints 객체를 통해 오디오 설정을 지정
	navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
		console.log("getUserMedia() success, stream created, initializing Recorder.js ...");
	
		//미디어 스트림을 성공적으로 가져오면 AudioContext를 생성
		audioContext = new AudioContext({sampleRate: 16000});
		gumStream = stream;
        
		// 오디오 스트림 소스를 생성
		input = audioContext.createMediaStreamSource(stream);
		
		/* Create an analyser node */
        analyser = audioContext.createAnalyser();
        input.connect(analyser);
        
        /* Create a script processor node */
        javascriptNode = audioContext.createScriptProcessor(2048, 1, 1);
        
        /* Connect the script processor node */
        analyser.connect(javascriptNode);
        javascriptNode.connect(audioContext.destination);
		
		//Recorder 객체를 생성하고 녹음을 시작
        rec = new Recorder(input,{numChannels:1});
        rec.record();
        
        /* Respond to the audio process event. */
        javascriptNode.onaudioprocess = function() {
            var array = new Uint8Array(analyser.frequencyBinCount);
            analyser.getByteFrequencyData(array);
            
            var values = 0;

            var length = array.length;
            for (var i = 0; i < length; i++) {
                values += array[i];
            }

            var average = values / length;
            
            /* Normalize the volume */
            var volume = Math.floor((average / 128) * 100);  // 정규화 계수를 255에서 128로 변경  //동일한 입력 볼륨에 대해 더 높은 출력 볼륨이 측정
            //console.log(volume);
            
            drawMic(volume);  
        }
        
	}).catch(function(err) {
		$(".stop").trigger("click");
		alert("마이크를 연결 해주세요");
		console.log("getUserMedia() fails");
	});
}    

	//button animation
	/* $('.short').click(function(){
		$(this).addClass('active');
	});
	$('.stop').click(function(){
		$('.short').removeClass('active');
	}); */
	
	/* $('#circle3').click(function() {
        var AudioData = Math.floor(Math.random() * 101);
        drawMic(AudioData);        
    }); */
	
	drawMic(30);
	
    /* visualizer */
    function drawMic(inputData)
    {
    	if(inputData < 0){
    		inputData = 0; 
    	} 
    	
	 	var inCircle_W_H = 100 /2 ;      //circle3의 정사이즈 너비,높이값 / 2
        var percentage;

        if (inputData === 0) {
            percentage = inCircle_W_H;   //circle3 너비,높이값인 100

        } else if (inputData >= 100) {
            percentage = 99;
        }
        else {
            percentage = inCircle_W_H + (inputData * ((100-inCircle_W_H)/100));     //circle3 너비,높이값인 65 + (inputdata) *  ((100-65)/100)        
        }

        
        $("#circle2").css('width', percentage + '%');
        $("#circle2").css('height', percentage + '%');
        
        //console.log("inputData:" + inputData + "  percent:" + percentage + "%");  
    }
</script>

여기에서 on클래스를 추가삭제는 알았는데 

function stop_verify( )

함수에 넣으니 

on의속(바탕색)성이 자꾸 사라져서 디버깅을 보니 stop_verify();가 곳곳에 있다보니 나왔다 사라지고 했다.

 

그래서 따로 함수를 만들어서 function stop_verify_short()를 만들어서 stop_verify(); 을 호출하고,

 

중단버튼을 클릭 할때만 $('.hvr-ripple-out').removeClass('on')이것이 적용하도록 했다.

 

안선임이 도와줌;;

function stop_verify_short(){

stop_verify();

 

$('.hvr-ripple-out').removeClass('on');

}