Post

[Jobby] 환경 세팅 4

오늘 목표

3편까지는:

  • Google Cloud에서 Jobby용 GCP 프로젝트 / 서비스 계정 / JSON 키를 만들고
  • Dialogflow 에이전트 생성 후 GCP 프로젝트와 묶고
  • server/config/dev.js에 실제 값까지 채워 넣었다.

4편에서는 드디어 이 설정을 실제로 사용해서:

  • 서버에서 Dialogflow로 텍스트 질문을 보내는 함수 하나 만들고
  • Jobby용 POST /api/dialogflow/textQuery 라우트를 만들어서
  • 나중에 React 클라이언트가 이 엔드포인트를 직접 호출할 수 있는 상태까지 만든다.

이 편이 끝나면 브라우저에서 API 테스트 도구(예: Postman, Thunder Client, curl 등)로 “텍스트 질문 → 서버 → Dialogflow → 서버 → 응답 JSON” 흐름을 실제로 한 번 돌려볼 수 있다.


전체 흐름 다시 한 번 잡기

지금 Jobby의 큰 그림은 이렇다:

  1. 사용자가 웹에서 Jobby에게 텍스트로 질문을 보낸다.
  2. 프론트(React)가 이 텍스트를 백엔드(Express 서버)의 POST /api/dialogflow/textQuery로 보낸다.
  3. 서버는 이 텍스트를 Dialogflow API의 detectIntent로 넘긴다.
  4. Dialogflow가 의도/응답을 계산해서 서버에 결과를 돌려준다.
  5. 서버가 이 결과를 JSON으로 가공해서 프론트로 보내고, 프론트가 화면에 보여준다.

이번 4편은 이 중에서 3번과 4번을 담당하는 “서버 ↔ Dialogflow” 구간을 실제 코드로 만드는 단계다.


1. Dialogflow 클라이언트 코드 파일 만들기

설정 값(dev.js)과 실제 Dialogflow 호출 로직을 분리하기 위해, server/ 아래에 별도 폴더를 하나 만들어서 클라이언트 코드를 모아 둔다.

1
2
3
cd server
mkdir -p dialogflow
touch dialogflow/dialogflowClient.js

이제 server/dialogflow/dialogflowClient.js 파일에 Dialogflow 클라이언트 코드를 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// server/dialogflow/dialogflowClient.js

const dialogflow = require("@google-cloud/dialogflow");
const uuid = require("uuid");
const config = require("../config/dev");

const projectId = config.googleProjectID;
const sessionLanguageCode = config.dialogFlowSessionLanguageCode;

// 텍스트 질문을 Dialogflow에 보내고, 응답을 그대로 돌려주는 함수
async function textQuery(userText, sessionId = uuid.v4()) {
  // 세션 클라이언트 생성
  const sessionClient = new dialogflow.SessionsClient({
    projectId,
    credentials: {
      client_email: config.googleClientEmail,
      private_key: config.googlePrivateKey,
    },
  });

  const sessionPath = sessionClient.projectAgentSessionPath(projectId, sessionId);

  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        text: userText,
        languageCode: sessionLanguageCode,
      },
    },
  };

  const responses = await sessionClient.detectIntent(request);
  return responses;
}

module.exports = {
  textQuery,
};

설명:

  • config/dev.js에서 googleProjectID, googleClientEmail, googlePrivateKey, dialogFlowSessionLanguageCode를 불러온다.
  • SessionsClient를 생성할 때 credentials에 서비스 계정 정보를 넘겨서 인증한다.
  • textQuery 함수는 나중에 Express 라우트에서 불러서 사용할 것이다.

패키지 설치 안 했으면 한 번만:

1
2
cd server
npm install @google-cloud/dialogflow uuid

2. Express 라우트: POST /api/dialogflow/textQuery 추가

이제 server/index.js에 위에서 만든 textQuery 함수를 연결하는 API 엔드포인트를 추가한다.

먼저 JSON 바디를 받기 위해 express.json() 미들웨어를 한 번 설정해 둔다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// server/index.js

const express = require("express");
const app = express();
const PORT = 5000;

app.use(express.json()); // JSON 바디 파싱

app.get("/", (req, res) => {
  res.send("Jobby server is running");
});

app.get("/health", (req, res) => {
  res.send("ok");
});

app.get("/intro", (req, res) => {
  res.send("이 엔드포인트에는 나중에 자기소개 문구가 들어갈 예정입니다.");
});

// 여기서부터 Dialogflow 관련 라우트
const { textQuery } = require("./dialogflow/dialogflowClient");

// 텍스트 질문을 받아 Dialogflow에 전달하는 엔드포인트
app.post("/api/dialogflow/textQuery", async (req, res) => {
  try {
    const { text } = req.body;

    if (!text) {
      return res.status(400).json({ error: "text 필드가 필요합니다." });
    }

    const dialogflowResponse = await textQuery(text);

    res.json({
      queryText: dialogflowResponse.queryResult.queryText,
      intent: dialogflowResponse.queryResult.intent.displayName,
      fulfillmentText: dialogflowResponse.queryResult.fulfillmentText,
      raw: dialogflowResponse,
    });
  } catch (error) {
    console.error("Dialogflow textQuery error:", error);
    res.status(500).json({ error: "Dialogflow 요청 중 오류가 발생했습니다." });
  }
});

app.listen(PORT, () => {
  console.log(`Jobby server is running on port ${PORT}`);
});

설명:

  • express.json()으로 req.body에 JSON이 들어오도록 설정한다.
  • POST /api/dialogflow/textQuery에서 req.body.text를 받아
    textQuery(text)로 Dialogflow에 전달한다.
  • Dialogflow 응답에서
    • 사용자가 보낸 문장 (queryText)
    • 매칭된 의도 이름 (intent.displayName)
    • 챗봇이 돌려줄 문장 (fulfillmentText) 정도만 뽑아서 응답 JSON에 담았다.

3. 지금까지 구조 상태 정리

여기까지 작업을 하면 Jobby 서버 구조는 대략 이렇게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jobby/
├── server/
│   ├── index.js                 # Express 서버 + /, /health, /intro, /api/dialogflow/textQuery
│   ├── dialogflow/
│   │   └── dialogflowClient.js  # Dialogflow textQuery 호출 로직
│   ├── config/
│   │   └── dev.js               # GCP / Dialogflow 설정 값 (gitignore 대상)
│   ├── package.json
│   └── package-lock.json
├── client/
│   ├── index.html
│   ├── package.json
│   └── src/ ...
├── .gitignore
└── README.md (예정)

3편까지는 “서버 ↔ Dialogflow 인증 준비”가 끝났고,
4편에서는 그 설정을 실제 코드로 사용해서 textQuery API까지 만든 상태가 된다.


오늘 실제로 한 작업 (로그)

  • server/dialogflow/dialogflowClient.js 생성
    • @google-cloud/dialogflow, uuid, config/dev.js를 사용해서 textQuery(userText, sessionId) 함수 구현
    • 내부에서 SessionsClient.detectIntent 호출로 Dialogflow 응답 받아오기
  • server/index.jsexpress.json() 미들웨어 추가
  • POST /api/dialogflow/textQuery 라우트 추가
    • req.body.text를 받아 textQuery로 전달
    • Dialogflow 응답에서 queryText, intent.displayName, fulfillmentText를 뽑아 JSON으로 반환
  • 서버 구조 업데이트:
    • server/ 아래에 dialogflow/ 폴더 추가
    • Dialogflow 관련 설정/코드를 config/dev.jsdialogflowClient.js로 분리

다음 글에서 할 것

다음 편에서는:

  • 로컬에서 POST /api/dialogflow/textQuery를 직접 호출해서
    • Dialogflow 에이전트가 만든 응답이 제대로 오는지 확인하고
  • client(React)에서 간단한 입력창/버튼을 만들어
    • 사용자가 입력한 문장을 이 엔드포인트로 보내고
    • 서버/Diagramflow 응답을 화면에 뿌리는 첫 챗봇 UI를 만들어 볼 예정이다.
This post is licensed under CC BY 4.0 by the author.