# AI 상품 추천: 데이터 호출형

## **1. 시스템 구조도**

<figure><img src="https://files.helpdocs.io/p92xn84cjv/articles/n4klfe09xw/1711528840377/image.png" alt=""><figcaption></figcaption></figure>

***

## **2. 개요**

* 스크립트 LOAD 완료된 후 원하는 시점에 추천 상품 목록을 가져와서 사용할 수 있습니다.
* DIV형과는 다르게 디자인을 자유롭게 구성 가능합니다.
* 데이터 호출형 - 동기식 방식에 대한 사항은 별도 문의 요청이 필요합니다.

***

## **3. 연동 방식**

* 고객사에서 그루비에서 추천 상품 요청 시 데이터를 바로 전달합니다.

```
groobee.getGroobeeRecommendAsync("캠페인키", 타임아웃) 
                    .then( data =>  { console.log(data); } );    
```

* 비동기식이라 요청이 느려졌을 경우 html에 추천 리스트를 표현하지 못하는 경우가 존재합니다.

{% hint style="warning" %}
이 문제를 방지하려면 아래 사항을 확인해 주세요.

1. 스크립트 로드 완료 후 호출\
   추천 API는 그루비 스크립트가 완전히 로드된 이후에 호출해야 합니다.\
   스크립트 로드 전에 호출할 경우 추천 결과가 정상적으로 렌더링되지 않을 수 있습니다.
2. 타임아웃 설정 조정\
   네트워크 환경에 따라 응답이 지연될 수 있습니다.\
   응답 실패가 자주 발생하는 경우, 타임아웃 값을 늘려 충분한 응답 대기 시간을 확보하는 것을 권장합니다.
3. 추천 실패 시 재시도 로직 구현 (고객사 직접 구현)\
   타임아웃 또는 네트워크 오류로 추천 요청이 실패한 경우, 그루비는 자동 재시도를 제공하지 않습니다.\
   실패 시 재시도 로직은 고객사 측에서 직접 구현해 주시기 바랍니다.\
   예) 일정 횟수만큼 재요청하거나, 실패 시 기본 상품 리스트로 대체 노출
   {% endhint %}

***

## **4. 추천 상품 조회(getGroobeeRecommendAsync)**

* 고객사에서 추천 상품 요청 시 전달해주는 함수입니다.
* **정의**
  * 역할: 추천 상품 조회
  * 함수명: groobee.getGroobeeRecommendAsync
  * 파라미터

| campaignKey | 캠페인키               | string |
| ----------- | ------------------ | ------ |
| timeSet     | 타임아웃 시간(기본 1000ms) | int    |
| {}          | 임시(생략 가능)          | object |

**작성 예**

```
groobee.getGroobeeRecommendAsync("RE6b33946d7add471dbd33f35347b5c06f", 500).then(              
                data =>  { console.log(data); }
                );          
```

**결과 값**

```
{ 
              "campaignKey": "RE0878d834239d4160b8d9fbac6e69617c",
              "algorithmCd": "ST09",
              "goodsList": [
                  {
                      "serviceKey": "21af7eb7cd8643a0ac599fd2ea1c9611",
                                "goodsNm": "자갸드 원피스",
                                "goodsCd": "49",
                                "goodsImg": "//shop3.grooshop.com/web/product/medium/202008/179f46dfad80fd80432fc283f8735e91.jpg",
                                "goodsCateNm": "",
                                "goodsCate": "",
                                "goodsPrc": 52800,
                                "goodsSalePrc": 47520,
                                "regDtm": [2020,5,21,22,16,13,232000000],
                                "moddDtm": [2020,5,21,22,16,13,232000000],
                  },
                  ...
              ]
          }
```

***

## **5. DI(노출)**

* 실제 고객사에서 노출시킨 상품 / 기획전 정보를 그루비로 보내줍니다.
* 그루비로 노출시킨 상품 / 기획전 정보를 보내주면 통계에 집계되어 어드민에서 확인 가능합니다.
* **정의**
  * 역할: 전시되는 상품을 그루비에서 노출 처리
  * 함수명: groobee.send
  * 파라미터

| type       | 노출 코드("DI" 고정 값) | string |
| ---------- | ---------------- | ------ |
| groobeeObj | 노출 관련 object     | Object |

```
groobeeObj = {
   algorithmCd : "알고리즘코드",
   campaignKey : "추천캠페인키",
   campaignTypeCd : "RE", //고정
   goods: [
      {goodsCd: "노출된 상품코드1"},
      {goodsCd: "노출된 상품코드2"}
      ]
}
```

* **정의**
  * 역할: 전시되는 기획전을 그루비에서 노출 처리
  * 함수명: groobee.send
  * 파라미터

| type       | 노출 코드("DI" 고정 값) | string |
| ---------- | ---------------- | ------ |
| groobeeObj | 노출 관련 object     | Object |

```
groobeeObj = {
algorithmCd : "알고리즘코드",
campaignKey : "추천캠페인키",
campaignTypeCd : "RE", //고정
goods: [
ㅤㅤ{plan: ["노출된 기획전코드1", “노출된 기획전코드2”]}
ㅤ ]
}
```

***

<br>

## **6. CL(클릭)**

* 고객이 클릭한 상품 / 기획전 정보를 그루비로 보내줍니다.
* 고객이 클릭한 상품 / 기획전 정보를 그루비로 보내주면 통계에 집계되어 어드민에서 확인 가능합니다.
* **정의**
  * 역할: 고객이 클릭한 상품을 그루비에서 클릭 처리
  * 함수명: groobee.send
  * 파라미터

| type       | 노출 코드("CL" 고정 값) | string |
| ---------- | ---------------- | ------ |
| groobeeObj | 노출 관련 object     | Object |

```
groobeeObj = {
   algorithmCd : "알고리즘코드",
   campaignKey : "추천캠페인키",
   campaignTypeCd : "RE", //고정
   goods: [
        {goodsCd: "고객이 클릭한 상품코드1"}
        ]
}
```

* **정의**
  * 역할: 고객이 클릭한 기획전을 그루비에서 클릭 처리
  * 함수명: groobee.send
  * 파라미터

| type       | 노출 코드("CL" 고정 값) | string |
| ---------- | ---------------- | ------ |
| groobeeObj | 노출 관련 object     | Object |

```
groobeeObj = {
ㅤalgorithmCd: "알고리즘코드",
ㅤcampaignKey: "추천캠페인키",
ㅤcampaignTypeCd: "RE",
ㅤgoods: [
ㅤㅤ{plan: ["고객이 클릭한 기획전 코드1"]}
ㅤ ]
}
```

***

<br>

## **7. 작성 예시**

코드 작성 예시를 보여줍니다.

{% code lineNumbers="true" %}

```javascript
//작성 예시일 뿐 고객사의 코드에 맞게 수정해 주시면 됩니다.
      //아래 코드가 정답이 아닙니다. 참고만 부탁드립니다.
      function groobeeRecommendCall () {
        
        //함수가 존재하는지 체크
        if (groobee && groobee.getGroobeeRecommendAsync) {
          //groobee.getGroobeeRecommendAsync 함수를 정상적으로 호출이 될 경우
          groobee.getGroobeeRecommendAsync('RE6b33946d7add471dbd33f35347b5c06f')
            .then(data => {
              고객사처리함수(data);
            })
        }  else {
          //groobee.getGroobeeRecommendAsync 함수가 정상적으로 호출이 되지 않을 경우
          let tryCnt = 0;
          
          let _timer = setInterval(()=> {
            
            // 3회 넘어갈시 중지
            if(tryCnt==3){
                clearInterval(_timer);
                $('#지정된ID').hide();
                return;
            }
            tryCnt++;
            
            // function 존재시에만 실행
            if(groobee.getGroobeeRecommendAsync && typeof groobee.getGroobeeRecommendAsync == 'function') {
                groobee.getGroobeeRecommendAsync('RE6b33946d7add471dbd33f35347b5c06f')
                  .then(data =< {
                    고객사처리함수(data);
                  })
                clearInterval(_timer);
            }}, 500);
        }
      }
      
      function 고객사처리함수(data) {
        console.log('recommendData :::', data);
        if (data && data.goodsList) {
          //고객사 추천상품 노출 및 데이터처리
          ...code 
          /*
            추천 상품 선별 및 노출작업
            각 상품 클릭 시 이벤트 연결처리도 필요 아래 clickGroobeeProduct(함수명은 자유)
            예시일 뿐 고객사에 맞춰서 코드는 새로 작성할 것
          */
          var html = "<ul>"; 
          for (let i = 0; i < data.goodsList.length; i++) { 
            html += `<li onClick="clickGroobeeProduct(${data.algorithmCd}, ${data.campaignKey}, ${data.goodsList[i].goodsCd})">${data.goodsList[i].goodsNm}</li>`;
          }
          html += "</ul>";
          
          $('#지정된ID').append(html);
          $('#지정된ID').show();
          
          --------------groobee 노출(DI) 처리 START----------------
          groobeeDisplayInsert(data.campaignKey, data.algorithmCd, data.goodsList);
          --------------groobee 노출(DI) 처리 END------------------
        } else {
          $('#지정된ID').hide();
        }
      }
            function groobeeDisplayInsert(type, campignKey, algorithmCd, goodsList) {
        //상품목록이 존재하는지 체크
        if (!goodsList || goodsList.length == 0) return;
                //이전에 goodsCd만 가공해서 보냈다면 1번방식을 그게 아니라면 2번방식을 채택하시면 됩니다.
        1. var goods = goodsList;
        2. var goods = [];
          for (var i = 0; i < goodsList.length; i++) {
            var newObj = {goodsCd: goodsList[i].goodsCd};
            goods.push(newObj);
          } 
          
        var groobeeObj = {
          algorithmCd: algorithmCd, //알고리즘코드 (추천받을때 받은 algorithmCd)
          campaignKey: campaignKey, //캠페인키
          campaignTypeCd: 'RE',     //고정값
          goods: goods
        }
        groobee.send('DI', groobeeObj);
      }
      
      function clickGroobeeProduct(campaignKey, algorithmCd, goodsCd) {
        //추천 클릭처리
        var groobeeObj = {
          algorithmCd: algorithmCd, //알고리즘코드 (추천받을때 받은 algorithmCd)
          campaignKey: campaignKey, //캠페인키
          campaignTypeCd: 'RE',     //고정값
          goods: [
            {goodsCd: goodsCd}
          ]
        }
        groobee.send('CL', groobeeObj);
        
        //고객사 페이지 이동처리
        code....
      }        
```

{% endcode %}

\ <br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.groobee.ai/developer-guide/script-guide/ai-recommendation/data-request.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
