본문 바로가기

API/NAVER CLOVA

CLOVA Chatbot

CLOVA Chatbot

  • 챗봇 제작 API 서비스
  • 사용자의 질문 의도를 이해하여 고객 대응 등 다양한 서비스에 활용할 수 있는  Chatbot 제작 지원

Web, App에서의 챗봇 구현 방법 : Custom 연동 방법

  1.  CLOVA Chatbot 빌더를 이용해서 대화 작성
  2.  대화 모델 빌드하고 배포 (10~20분 정도 소요)
  3.  CLOVA Chatbot Custom 연동을 설정
  4.  API Gateway 호출 URL 생성하고 Secret Key 발급 ( API 코드에서 사용 )
  5. API Gateway 호출 URL 통해서 애플리케이션에서 호출 ( 스프링 프로젝트와 연동)

 

CLOVA Chatbot 구현 과정

  1. 도메인 생성 (도메인 이름 / 도메인 코드 / 자연어처리 : 한국어 / 서비스타입 : Standard / 대화로그 임시 저장 : 저장하지 않음)
  2. 빌더 실행하기
  3. 대화 생성
  4. 학습 질문 입력
  5. 챗봇 답변 입력
  6. 챗봇 빌드
  7. 챗봇 테스트
  8. 서비스 배포 ( APIGW 연동 설정 )
  9. 스프링에서 작업

[ chatbot 예제 1 ]

(1) 폼에서 질문 메시지 입력 받고 결과 출력

(2) 채팅창

 

APIController

더보기
@Autowired
private ChatbotService chatService;

// 챗봇 : 질문 메시지 전송하고 결과 받아서 출력
// static : 객체를 생성해서 호출하는 것이 아닌, 클래스 이름으로 호출
/*@RequestMapping("/chatbot")
public void chatbot() {
    String result = chatService.main("맡은 역할은");
    System.out.println(result);
}*/

@RequestMapping("/chatbotForm")
public String chatbotForm() {
    return "chatForm";
}

// 채팅창
@RequestMapping("/chatbotForm2")
public String chatbotForm2() {
    return "chatForm2";
}

 

APIRestController

더보기
@Autowired
private ChatbotService chatService;

@RequestMapping("/chatbotCall")
public String  chatbotCall(@RequestParam("message") String message ) {
    String result = chatService.main(message);
    return result;
}

 

ChatbotService

더보기
package com.ai.ex.service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.stereotype.Service;

import com.ai.ex.model.ObjectVO;

@Service
public class ChatbotService {
	public String main(String voiceMessage) {
	//public static String main(String voiceMessage) {	

		String apiURL = "";
		String secretKey = "";		
		
        String chatbotMessage = ""; // 응답 메시지        

        try {
            //String apiURL = "https://ex9av8bv0e.apigw.ntruss.com/custom_chatbot/prod/";

            URL url = new URL(apiURL);

            String message = getReqMessage(voiceMessage);
            System.out.println("##" + message);

            String encodeBase64String = makeSignature(message, secretKey);

            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type", "application/json;UTF-8");
            con.setRequestProperty("X-NCP-CHATBOT_SIGNATURE", encodeBase64String);

            // post request
            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.write(message.getBytes("UTF-8"));
            wr.flush();
            wr.close();
            int responseCode = con.getResponseCode();

            BufferedReader br;

            if(responseCode==200) { // Normal call
                System.out.println(con.getResponseMessage());

                BufferedReader in = new BufferedReader(
                        new InputStreamReader(
                                con.getInputStream()));
                String decodedString;
                while ((decodedString = in.readLine()) != null) {
                    chatbotMessage = decodedString;
                }
                //chatbotMessage = decodedString;
                in.close();
                
                // 응답 메시지 출력
                System.out.println(chatbotMessage);
                chatbotMessage = jsonToString(chatbotMessage);

            } else {  // Error occurred
                chatbotMessage = con.getResponseMessage();
            }
        } catch (Exception e) {
            System.out.println(e);
        }

        return chatbotMessage; // 응답 메시지 반환
    }

    public static String makeSignature(String message, String secretKey) {

        String encodeBase64String = "";

        try {
            byte[] secrete_key_bytes = secretKey.getBytes("UTF-8");

            SecretKeySpec signingKey = new SecretKeySpec(secrete_key_bytes, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(signingKey);

            byte[] rawHmac = mac.doFinal(message.getBytes("UTF-8"));
           // encodeBase64String = Base64.encodeToString(rawHmac, Base64.NO_WRAP);
            encodeBase64String = Base64.getEncoder().encodeToString(rawHmac);
            return encodeBase64String;

        } catch (Exception e){
            System.out.println(e);
        }

        return encodeBase64String;

    }

    public static String getReqMessage(String voiceMessage) {

        String requestBody = "";

        try {

            JSONObject obj = new JSONObject();

            long timestamp = new Date().getTime();

            System.out.println("##"+timestamp);

            obj.put("version", "v2");
            obj.put("userId", "U47b00b58c90f8e47428af8b7bddc1231heo2");
//=> userId is a unique code for each chat user, not a fixed value, recommend use UUID. use different id for each user could help you to split chat history for users.

            obj.put("timestamp", timestamp);

            JSONObject bubbles_obj = new JSONObject();

            bubbles_obj.put("type", "text");

            JSONObject data_obj = new JSONObject();
            data_obj.put("description", voiceMessage);

            bubbles_obj.put("type", "text");
            bubbles_obj.put("data", data_obj);

            JSONArray bubbles_array = new JSONArray();
            bubbles_array.put(bubbles_obj);

            obj.put("bubbles", bubbles_array);
			/*obj.put("event", "send");*/

            // 웰컴 메시지 출력
            if(voiceMessage == "") {
            	obj.put("event", "open"); // 웰컴 메시지
            } else {
            	obj.put("event", "send");
            }
            
            requestBody = obj.toString();

        } catch (Exception e){
            System.out.println("## Exception : " + e);
        }

        return requestBody;

    }
    
 // 서버로부터 받은 결과 JSON 데이터 추출해서 반환
    public String jsonToString(String jsonResultStr) {
    	String result = "";
    	
    	JSONObject jsonObj = new JSONObject(jsonResultStr);
		JSONArray bubblesArray = (JSONArray) jsonObj.get("bubbles");		
		
		JSONObject obj0 = (JSONObject) bubblesArray.get(0);
		
		JSONObject dataObj = (JSONObject) obj0.get("data");
    	result = (String) dataObj.get("description");
    	
    	return result;
    }
}

 

chatbot.js

더보기
/**
 * chatbot.js
 */
 
 $(function(){
	
	$('#chatForm').on('submit', function(event){	
		event.preventDefault();

		$.ajax({
			url:"chatbotCall",
			type:"post",
			data:{message: $('#message').val()},
			success:function(result){
				$('#chatBox').text(result);   // 저장된 '음성 파일명' 출력
			},
			error:function(e){
				alert("오류가 발생했습니다." + e)
			}
		});
		
		/* 입력란 비우기 */
		$('#message').val('');
	});		
});

 

chatbot2.js

더보기
/**
 * chatbot2.js
 */
 
 $(function(){
	
	// 웰컴 메시지를 받기 위해서 message 입력받기 전에
	// 빈 값으로 서버에 전송하고
	// 웰컴 메시지를 받기 위해 $.axaj()를 별도의 함수로 분리해서 호출
	
	callAjax(); // 빈 값으로 서버 전송 -> open 이벤트 호출 -> 웰컴 메시지 출력하기 위해 함수 호출
	
	$('#chatForm').on('submit', function(event){	
		event.preventDefault();
		 
		 // 입력란에 메시지 입력하지 않은 채로 [전송] 버튼 클릭 시 경고창 출력 & 웰컴메시지 출력되지 않도록 함
		 if($('#message').val()=="") {
			alert("질문을 입력하세요");
			return false;
		}
		 
		 /* chatBox에 보낸 메시지 추가*/
		 if($('#message').val() != ""){
			$('#chatBox').append('<div class="msgBox send"><span id="in"><span>' + 
												$('#message').val() + '</span></span></div><br>');
		}
		
		callAjax(); // 기존에 ajax가 있던 자리에 따로 분리해준 callAjax() 함수 호출
		
		/* 입력란 비우기 */
		$('#message').val('');
	});	 // submit 끝
	
	// $.ajax()를 별도의 함수로 분리
	function callAjax() {
		$.ajax({
			url:"chatbotCall",
			type:"post",
			data:{message: $('#message').val()},
			success:function(result){
				/* chatBox에 받은 메시지 추가 */
				$('#chatBox').append('<div class="msgBox receive"><span id="in"><span>챗봇</span><br><span>' + 
														   result +'</span></span></div><br><br>'); 								   
				// 스크롤해서 올리기										   
				$("#chatBox").scrollTop($("#chatBox").prop("scrollHeight"));
			},
			error:function(e){
				alert("오류가 발생했습니다." + e)
			}
		});
	}	
});

 

chatForm.jsp

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>chatbot</title>
		<script src="<c:url value='/js/jquery-3.6.0.min.js'/>"></script>
		<script src="<c:url value='/js/chatbot.js'/>"></script>
	</head>
	<body>
		<h3>chatbot</h3>
		<form id="chatForm" enctype="multipart/form-data">
			<input type="text" id="message" name="message" size="30" placeholder="질문을 입력하세요">
			<input type="submit" value="전송">
		</form>
		<br><br>
		
		<!-- 응답 메시지 출력 -->
		<div id="chatBox"></div>
		
		<br><br>
		<a href="/">index 페이지로 이동</a>
	</body>
</html>

 

chatForm2.jsp

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>chatbot2</title>
		<script src="<c:url value='/js/jquery-3.6.0.min.js'/>"></script>
		<script src="<c:url value='/js/chatbot2.js'/>"></script>
		<link rel="stylesheet" type="text/css" href="<c:url value='/css/chatbot.css'/>">
	</head>
	<body>
		<div id="wrap">
			<!-- Header -->
				<div id="chatHeader">
					<span>chatbot</span>
					<button id="btnClose">X</button>
				</div>
			
			<!-- 채팅 내용 출력 -->
				<!-- 응답 메시지 출력 -->
				<div id="chatBox"></div>
				
				<form id="chatForm" enctype="multipart/form-data">
					<input type="text" id="message" name="message" size="30" placeholder="질문을 입력하세요">
					<input type="submit" value="전송">
				</form>
				<br><br>
			
			<br><br>
			<a href="/">index 페이지로 이동</a>
		</div>
	</body>
</html>

 

chatbot.css

더보기
@charset "UTF-8";

#wrap { margin:0 auto; width: 500px; 	height: 800px; } 

#chatHeader {padding: 10px 15px; border-bottom: 1px solid #95a6b4;}
#btnClose {border: none; background: none; float: right;}
 
#chatBox {height: 600px; width: 500px; overflow-y:scroll; padding:10px 15px; background:#9bbbd4;} 	

#message {width: 440px;}

#btnSubmit {float: right; background:#eeeeee; height: 28px; padding-right:0;}

.msgBox  span {padding:3px 5px; word-break:break-all; display:block; 
							 max-width:300px; margin-bottom: 10px; border-radius: 10px;}
							 
.msgBox.send  span {background:#fef01b; float:right; }

.msgBox #in {width:480px; background:#9bbbd4;}
.msgBox.receive  span {background:#ffffff; float:left; }

 

index.jsp

더보기
<a href="chatbotForm">챗봇</a><br><br>
<a href="chatbotForm2">챗봇2 : 채팅창</a><br><br>

[ chatbot 예제 2 : 예제 1에 질문 및 답변 음성 인식 기능 추가 ]

  • 질문을 녹음해서 mp3 파일로 저장 -> mp3 파일을 텍스트로 변환 : STT 서비스 사용
  • 변환된 텍스트를 질문으로 챗봇 서버로 전송해서 답변 받아서 텍스트 및 음성으로 출력 : TTS 서비스 사용

공통 메시지 추가 ( 답변 입력 및 저장 / 대화 모델 빌드 )

 

APIController

더보기
// 채팅창 + 음성 질문
@RequestMapping("/chatbotForm3")
public String chatbotForm3() {
    return "chatForm3";
}

 

APIRestController

더보기
@RequestMapping("/chatbotTTS")
public String  chatbotTTS(@RequestParam("message") String message ) {
    String result = ttsService.chatbotTextToSpeech(message);
    return result;  // voiceFileName;  // 저장된 음성 파일명 반환
}

 

STTService

더보기
package com.ai.ex.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;

import org.json.JSONObject;
import org.springframework.stereotype.Service;

@Service 
public class STTService {
	public String clovaSpeechToText(String filePathName) {
		String clientId = "";             // Application Client ID";
        String clientSecret = "";     // Application Client Secret";
        
        String result = "";
        
        try {
            String imgFile = filePathName;
            File voiceFile = new File(imgFile);

            String language = "Kor";        // 언어 코드 ( Kor, Jpn, Eng, Chn )
            String apiURL = "https://naveropenapi.apigw.ntruss.com/recog/v1/stt?lang=" + language;
            URL url = new URL(apiURL);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            conn.setUseCaches(false);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("Content-Type", "application/octet-stream");
            conn.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            conn.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);

            OutputStream outputStream = conn.getOutputStream();
            FileInputStream inputStream = new FileInputStream(voiceFile);
            byte[] buffer = new byte[4096];
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            inputStream.close();
            BufferedReader br = null;
            int responseCode = conn.getResponseCode();
            if(responseCode == 200) { // 정상 호출
                br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            } else {  // 오류 발생
                System.out.println("error!!!!!!! responseCode= " + responseCode);
                br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            }
            String inputLine;

            if(br != null) {
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
                result = jsonToString(response.toString()); // JSON 문자열에서 텍스트 추출
                resultToFileSave(result); //파일로 저장
                
            } else {
                System.out.println("error !!!");
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        
        return result;
	}
	
	public String clovaSpeechToText2(String filePathName, String language) {
		String clientId = "6to327c88d";             // Application Client ID";
        String clientSecret = "HqfsYXHJrk5mWcv3hgJQq3qk94YebLJ0knjw5M1k";     // Application Client Secret";
        
        String result = "";
        
        try {
            String imgFile = filePathName;
            File voiceFile = new File(imgFile);

            //String language = "Kor";        // 언어 코드 ( Kor, Jpn, Eng, Chn )
            String apiURL = "https://naveropenapi.apigw.ntruss.com/recog/v1/stt?lang=" + language;
            URL url = new URL(apiURL);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            conn.setUseCaches(false);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("Content-Type", "application/octet-stream");
            conn.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            conn.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);

            OutputStream outputStream = conn.getOutputStream();
            FileInputStream inputStream = new FileInputStream(voiceFile);
            byte[] buffer = new byte[4096];
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            inputStream.close();
            BufferedReader br = null;
            int responseCode = conn.getResponseCode();
            if(responseCode == 200) { // 정상 호출
                br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            } else {  // 오류 발생
                System.out.println("error!!!!!!! responseCode= " + responseCode);
                br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            }
            String inputLine;

            if(br != null) {
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
                result = jsonToString(response.toString()); // JSON 문자열에서 텍스트 추출
                resultToFileSave(result); //파일로 저장
                
            } else {
                System.out.println("error !!!");
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        
        return result;
	}
	
	// API 서버로부터 받은 JSON 형태의 결과 데이터를 전달받아서 text 추출
	public String jsonToString(String jsonResultStr) {
		String resultText = "";
		
		try {
			//org.json.JSONObject; 사용한 경우
			JSONObject jsonObj = new JSONObject(jsonResultStr);
			resultText = (String) jsonObj.getString("text");
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}			
		
		return resultText;
	}
	
	// 음성 파일에서 추출한 텍스트를 txt 파일로 저장
	public void resultToFileSave(String result) {
		try {
			String fileName = Long.valueOf(new Date().getTime()).toString();
			String filePathName = "C:/upload/" + "stt_" + fileName + ".txt";
			
			FileWriter fw = new FileWriter(filePathName);
			fw.write(result);
			fw.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

TTSService

더보기
package com.ai.ex.service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;

import org.springframework.stereotype.Service;

@Service
public class TTSService {
	public void clovaTextToSpeech() {
		String clientId = "";//애플리케이션 클라이언트 아이디값";
        String clientSecret = "";//애플리케이션 클라이언트 시크릿값";
        try {
        	
            String text = URLEncoder.encode("만나서 반갑습니다.", "UTF-8"); // 13자
            String apiURL = "https://naveropenapi.apigw.ntruss.com/tts-premium/v1/tts";
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            con.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);
            // post request
            String postParams = "speaker=meimei&volume=0&speed=0&pitch=0&format=mp3&text=" + text;
            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();
            int responseCode = con.getResponseCode();
            BufferedReader br;
            if(responseCode==200) { // 정상 호출
                InputStream is = con.getInputStream();
                int read = 0;
                byte[] bytes = new byte[1024];
                // 랜덤한 이름으로 mp3 파일 생성
                String tempname = Long.valueOf(new Date().getTime()).toString();
                //File f = new File(tempname + ".mp3");
                File f = new File("C:/upload/"  +  tempname + ".mp3");
                f.createNewFile();
                OutputStream outputStream = new FileOutputStream(f);
                while ((read =is.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
                is.close();
            } else {  // 오류 발생
                br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
            }
        } catch (Exception e) {
            System.out.println(e);
        }
	}
	
	// 파일 경로 및 언어 전달 받음
	// 저장된 파일 명 반환
	public String clovaTextToSpeech2(String filePathName, String language) {
		String clientId = "";//애플리케이션 클라이언트 아이디값";
        String clientSecret = "";//애플리케이션 클라이언트 시크릿값";
        
        String voiceFileName = "";
        
        try {
        	
        	// 전달 받은 파일에서 텍스트를 추출하기 위한 함수 fileRead() 사용
        	// 함수에게 전달하고 텍스트 받음
        	String fileContents = fileRead(filePathName);
        	
            String text = URLEncoder.encode(fileContents, "UTF-8"); // 
            String apiURL = "https://naveropenapi.apigw.ntruss.com/tts-premium/v1/tts";
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            con.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);
            // post request
            String postParams = "speaker="  +  language  + "&volume=0&speed=0&pitch=0&format=mp3&text=" + text;
            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();
            int responseCode = con.getResponseCode();
            BufferedReader br;
            if(responseCode==200) { // 정상 호출
                InputStream is = con.getInputStream();
                int read = 0;
                byte[] bytes = new byte[1024];
                // 랜덤한 이름으로 mp3 파일 생성
                String tempname = Long.valueOf(new Date().getTime()).toString();
                //File f = new File(tempname + ".mp3");
                
                voiceFileName = "tts_" + tempname + ".mp3";    
                File f = new File("C:/upload/"  +  voiceFileName);                
                f.createNewFile();
                
                OutputStream outputStream = new FileOutputStream(f);
                while ((read =is.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
                is.close();
            } else {  // 오류 발생
                br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        
        return voiceFileName;  // 저장된 음성 파일명 반환
	}
	
	// 챗봇으로 부터 받은 텍스트 답변을 음성으로 변환
	public String chatbotTextToSpeech(String message) {
		String clientId = "";//애플리케이션 클라이언트 아이디값";
        String clientSecret = "";//애플리케이션 클라이언트 시크릿값";
        
        String voiceFileName = "";
        
        try {        	
        	
            String text = URLEncoder.encode(message, "UTF-8"); // 
            String apiURL = "https://naveropenapi.apigw.ntruss.com/tts-premium/v1/tts";
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("X-NCP-APIGW-API-KEY-ID", clientId);
            con.setRequestProperty("X-NCP-APIGW-API-KEY", clientSecret);
            // post request
            String postParams = "speaker=nara&volume=0&speed=0&pitch=0&format=mp3&text=" + text;
            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();
            int responseCode = con.getResponseCode();
            BufferedReader br;
            if(responseCode==200) { // 정상 호출
                InputStream is = con.getInputStream();
                int read = 0;
                byte[] bytes = new byte[1024];
                // 랜덤한 이름으로 mp3 파일 생성
                String tempname = Long.valueOf(new Date().getTime()).toString();
                //File f = new File(tempname + ".mp3");
                
                voiceFileName = "tts_" + tempname + ".mp3";    
                File f = new File("C:/upload/"  +  voiceFileName);                
                f.createNewFile();
                
                OutputStream outputStream = new FileOutputStream(f);
                while ((read =is.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
                is.close();
            } else {  // 오류 발생
                br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
                System.out.println(response.toString());
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        
        return voiceFileName;  // 저장된 음성 파일명 반환
	}
	
	// 파일 경로를 전달받아서 파일 내 텍스트 추출해서 반환 함수
	public String fileRead(String filePathName) {
		String result = "";
		
		try {
			File file = new File(filePathName);
			FileReader fr = new FileReader(file);
			
			BufferedReader br = new BufferedReader(fr);
			String line = "";
			while((line = br.readLine()) != null){
				result += line;
			}
			br.close();			
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(result); // 출력해서 확인
		return result;
	}
}

 

chatbot3.js

더보기
/**
 * chatbot3.js
 */
 
 $(function(){
	// 웰컴 메시지를 받기 위해서 message 입력받기 전에
	// 빈 값으로 서버에 전송하고 웰컴 메시지를 받기 위해
	// $.ajax()를 별도의 함수로 분리해서 호출
	callAjax(); //메시지 입력하지 않고 호출해서 빈값 전송 -> open event -> 웰컴 메시지 출력
	
	/////////////////////////////////////////////////////////
	// 음성으로 질문하기
	
	//(1) 녹음 기능
	const record = document.getElementById("record");
    const stop = document.getElementById("stop");
    const soundClips = document.getElementById("sound-clips");

    const audioCtx = new(window.AudioContext || window.webkitAudioContext)(); // 오디오 컨텍스트 정의

    if (navigator.mediaDevices) {
        var constraints = {
            audio: true
        }
         let chunks = [];

        navigator.mediaDevices.getUserMedia(constraints)
            .then(stream => {
                const  mediaRecorder = new MediaRecorder(stream);
          
                record.onclick = () => {
                    mediaRecorder.start();
                    record.style.background = "red";
                    record.style.color = "black";
                }

                stop.onclick = () => {//정지 버튼 클릭 시
                    mediaRecorder.stop();//녹음 정지                       
                    record.style.background = "";
                    record.style.color = "";
                }
                
                mediaRecorder.onstop = e => {                        
                    
                    const clipName = "voiceMsg";
					//태그 3개 생성
                    const clipContainer = document.createElement('article');                     
                    const audio = document.createElement('audio');
                    const a = document.createElement('a');
					                       
                    clipContainer.appendChild(a);
                    soundClips.appendChild(clipContainer);                        
					
                    //chunks에 저장된 녹음 데이터를 audio 양식으로 설정
                    //audio.controls = true;
                    const blob = new Blob(chunks, {
                        'type': 'audio/mp3 codecs=opus'
                    }) ;
                    chunks = [];
                    const audioURL = URL.createObjectURL(blob);
                   // audio.src = audioURL;                       
                   //blob:http://localhost:8011/6377d19d-2ca8-49b1-a37f-068d602ceb60    
                    a.href=audioURL;                    
                    a.download = clipName;                      
                   //a.innerHTML = "DOWN"
					a.click(); // 다운로드 폴더에 저장하도록 클릭 이벤트 발생			
					
                    fileUpload(blob, clipName);
                   
                }//mediaRecorder.onstop

                //녹음 시작시킨 상태가 되면 chunks에 녹음 데이터를 저장하라 
                mediaRecorder.ondataavailable = e => {
                    chunks.push(e.data)
                }
                
                
            })
            .catch(err => {
                console.log('The following error occurred: ' + err)
            })
    }        
	
	
	// (2) 서버에 파일 업로드
    function fileUpload(blob, clipName){	    
	
		var formData = new FormData();
		formData.append('uploadFile', blob, clipName+".mp3");
					  
    	//녹음된 mp3파일 전송하고 반환된 텍스트(result)를 챗봇 서버에 전달
    	$.ajax({    		
			type:"post",	
			enctype: 'multipart/form-data',
			url: "clovaSTT", //통신할 url		
			data: formData, //전송할 데이타	: 파일명 :voiceMsg.mp3
			processData: false,
    		contentType: false,
			success: function(result) {
				$('#chatBox').append('<div class="msgBox send"><span id="in"><span>' + 
											  result + '</span></span></div><br>'); 
			
				// 챗봇에게 전달
			    $('#message').val(result);
				callAjax(); 
				$('#message').val('');	
			},
			error: function(e) {
				alert("에러가 발생했습니다 : " + e);
			}
		});
	
    }		
	
	
	/////////////////////////////////////////////////////////
	
	
	// 챗봇에게 질문하고 응답받기 - 텍스트 응답
	// message 입력하고 전송 버튼 눌렀을 때
	$('#chatForm').on('submit', function(event){
		event.preventDefault();
		
		// 입력란에 메시지 입력하지 않은 채로 [전송] 버튼 누른 경우 (웰컴 메시지 출력되지 않도록 함 & 클릭 시 경고창 출력)
		if ($('#message').val() == ""){
			alert("질문을 입력하세요");
			return false;
		}		
		
		/* chatBox에 보낸 메시지 추가 */
		if($('#message').val() != ""){
			$('#chatBox').append('<div class="msgBox send"><span id="in"><span>' + 
												$('#message').val() + '</span></span></div><br>');
		}
		
		callAjax(); // 입력된 값 전송 (기존에 ajax가 있던 자리에 따로 분리해문 callAjax() 함수 호출)
		
		/* 입력란 비우기*/
		$('#message').val('');
	});	// submit 끝
	
	// $.ajax()를 별도의 함수로 분리
	function callAjax(){
		$.ajax({
			url:"chatbotCall",
			type:"post",
			data:{message: $('#message').val()},		
			success:function(result){				
				/* chatBox에 받은 메시지 추가 */
				$('#chatBox').append('<div class="msgBox receive"><span id="in"><span>챗봇</span><br><span>' + 
														   result +'</span></span></div><br><br>'); 								   
				// 스크롤해서 올리기										   
				$("#chatBox").scrollTop($("#chatBox").prop("scrollHeight"));		
				
				// 챗봇으로 부터 받은 텍스트 답변을 음성으로 변환하기 위해 TTS 호출
				callAjaxTTS(result);		
			},
			error:function(){
				alert("오류가 발생했습니다.")
			}
		});
	}
	
	
	function callAjaxTTS(result){
		$.ajax({
            type:"post",            
            url:"chatbotTTS",
            data:{message : result},
            dataType :'text',
            success:function (result){ //음성 파일 이름 받음
				/* chatBox에 받은 음성 메시지 플레이 */
				$('audio').prop("src", '/voice/'+ result)[0].play();
				$('audio').hide();
            },
            error:function(data){
               alert("에러 발생");				
            }
       });
	}
});

 

chatForm3.jsp

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>챗봇</title>
		<script src="<c:url value='/js/jquery-3.6.0.min.js'/>"></script>
		<script src="<c:url value='/js/chatbot3.js'/>"></script>		
		<link rel="stylesheet" type="text/css" href="<c:url value='/css/chatbot.css'/>">
	</head>
	<body>			
		<div id="wrap">
			<!-- Header -->
			<div id="chatHeader">
				<span>챗봇</span>
				<button id="btnClose">X</button>
			</div>
		
		<!-- 채팅 내용 출력 -->
			
			<!-- 응답 메시지 출력  -->
			<div id="chatBox"></div><br>
			
			<div>
				<!-- 질문 메시지 입력 폼 -->
				<form id="chatForm">
					<input type="text" id="message" name="message" size="30" placeholder="질문을 입력하세요">	
					<input type="submit" value="전송">		
				</form>		
			</div><br>
			
			<div>
			<!-- 음성 녹음 -->
			음성 메시지 : <button id="record">녹음</button> 
							<button id="stop">정지</button>
							<div id="sound-clips"></div><br>
			
			</div>
			
			<div>
				<audio preload="auto" controls></audio>
			</div>			
			
			<br><br>
			<a href="/">index 페이지로 이동</a>
		</div>
	</body>
</html>

 

index.jsp

더보기
<a href="chatbotForm3">챗봇3 : 채팅창 + 음성으로 질문</a><br><br>

 

필요에 따라 STT / TTS 코드 추가 ( https://olli2.tistory.com/234 )

 

음성 인식 : CLOVA Speech Recognition (CSR) / CLOVA Voice - Premium

CLOVA Speech Recognition (CSR) : 음성 인식 사람의 목소리를 텍스트로 변환 | 음성을 텍스트로 변환 : STT(Speech-To-Text) 언어 선택 가능 Application에서 CLOVA Speech Recognition (CSR) 서비스 추가하여 사..

olli2.tistory.com