# genser 활용 제안

<figure><img src="/files/xAnRiurm9bygSKhtoEKE" alt=""><figcaption></figcaption></figure>

사용자에게 AI 검색 UX를 어떤 방식으로 제공하느냐에 따라 검색 서비스의 실제 활용도와 만족도가 달라집니다. 서비스의 아이덴티티와 페이지 구조를 고려하여, 가장 몰입감 있는 최적의 검색 패턴을 적용해 보세요.

## 탭 전환형 (Explicit Toggle)

<figure><img src="/files/Mirx2F90loHX2NpK6qHZ" alt=""><figcaption></figcaption></figure>

* 로그인 회원에게만 AI 검색을 제공하고 싶을 때 사용하면 좋습니다.&#x20;
* 일반 검색과 AI 검색을 구분하여 사용하도록 유도할 수 있습니다.&#x20;
* AI 검색에 대한 고객의 인지를 점층적으로 높이고, 검색 목적 별로 고객에게 선택권을 줄 수 있습니다.&#x20;

{% hint style="info" %}
**Tip**

탭 전환 시 Placeholder(입력 안내 문구)를 함께 변경하여, 사용자가 어떤 검색어를 입력해야 할지 가이드를 주는 것이 중요합니다.
{% endhint %}

<details>

<summary>React 코드 예시</summary>

```javascript
const TabSearchPattern = () => {
  const [mode, setMode] = useState('AI'); // 'AI' | 'GENERAL'
  const [query, setQuery] = useState('');
  const [products, setProducts] = useState([]);
  const [requestId, setRequestId] = useState(null); // 검색 요청 ID 저장

  // 노출(DI) 로그 전송
  // 상품 목록(products)이 업데이트되고 화면 렌더링이 완료된 시점에 호출합니다.
  useEffect(() => {
    if (products.length > 0 && requestId) {
      window.genser.call('DI', {
        instance: { key: 'YOUR_INSTANCE_KEY' },
        goods: products.map(p => ({ code: p.code, name: p.name })),
        requestId: requestId
      });
      // console.log('DI 전송 완료');
    }
  }, [products, requestId]);

  // 클릭(CL) 로그 전송
  const handleProductClick = (product) => {
    if (!requestId) return;
    
    window.genser.call('CL', {
      instance: { key: 'YOUR_INSTANCE_KEY' },
      goods: [{ code: product.code, name: product.name }],
      requestId: requestId
    });
    
    // 이후 상품 상세 페이지로 이동
    console.log('CL 전송 완료, 페이지 이동:', product.name);
  };

  const handleSearch = (e) => {
    e.preventDefault();
    if (mode === 'AI') {
      // genser AI 검색 호출
      window.genser.call('searchProducts', {
        instanceKey: 'YOUR_INSTANCE_KEY',
        queryText: query
      }).success((res) => {
        if (res.type === 'SEARCH') {
          // 상태 업데이트 -> 리렌더링 발생 -> useEffect 실행 -> DI 전송
          setProducts(res.products);
          setRequestId(res.requestId);
        }
      });
    } else {
      console.log('일반 키워드 검색 실행:', query);
    }
  };

  return (
    <div>
      <div className="tabs">
        <button onClick={() => setMode('AI')} className={mode === 'AI' ? 'active' : ''}>AI 검색</button>
        <button onClick={() => setMode('GENERAL')} className={mode === 'GENERAL' ? 'active' : ''}>일반 검색</button>
      </div>
      <form onSubmit={handleSearch}>
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder={mode === 'AI' ? "결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!" : "검색어를 입력하세요"}
        />
        <button type="submit">검색</button>
      </form>
      
      {/* 결과 리스트 예시 */}
      <ul>
        {products.map(p => (
          <li key={p.code} onClick={() => handleProductClick(p)}>
            {p.name}
          </li>
        ))}
      </ul>
    </div>
  );
};

```

</details>

<details>

<summary>Vue 코드 예시</summary>

```python
<template>
  <div class="search-container">
    <div class="tabs">
      <button :class="{ active: mode === 'AI' }" @click="mode = 'AI'">✨ AI 검색</button>
      <button :class="{ active: mode === 'GENERAL' }" @click="mode = 'GENERAL'">일반 검색</button>
    </div>
    <div class="input-wrapper">
      <input 
        v-model="query" 
        @keyup.enter="handleSearch"
        :placeholder="placeholderText" 
      />
      <button @click="handleSearch">검색</button>
    </div>
    
    <!-- 결과 리스트 -->
    <ul>
      <li 
        v-for="p in products" 
        :key="p.code" 
        @click="handleProductClick(p)"
      >
        {{ p.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, computed, nextTick } from 'vue';

const mode = ref('AI');
const query = ref('');
const products = ref([]);
const requestId = ref(null);

const placeholderText = computed(() => 
  mode.value === 'AI' ? "결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!" : "검색어를 입력하세요"
);

const handleSearch = () => {
  if (mode.value === 'AI') {
    // 검색 API 호출
    window.genser.call('searchProducts', {
      instanceKey: 'YOUR_INSTANCE_KEY',
      queryText: query.value
    }).success((res) => {
      products.value = res.products;
      requestId.value = res.requestId;
      
      // DI 로그 전송 
      nextTick(() => {
        window.genser.call('DI', {
          instance: { key: 'YOUR_INSTANCE_KEY' },
          goods: res.products.map(p => ({ code: p.code, name: p.name })),
          requestId: res.requestId
        });
      });
    });
  } else {
    console.log('일반 검색 실행');
  }
};

// 클릭(CL) 로그 전송
const handleProductClick = (product) => {
  if (!requestId.value) return;
  
  window.genser.call('CL', {
    instance: { key: 'YOUR_INSTANCE_KEY' },
    goods: [{ code: product.code, name: product.name }],
    requestId: requestId.value
  });
  
  console.log('CL 전송 및 이동', product.name);
};
</script>
```

</details>

<details>

<summary>HTML/JS 코드 예시</summary>

```js
<div class="search-wrapper">
  <div class="tab-group">
    <button onclick="setMode('AI')" id="btn-ai" class="active">✨ AI 검색</button>
    <button onclick="setMode('GENERAL')" id="btn-gen">일반 검색</button>
  </div>
  <input type="text" id="search-input" placeholder="결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!">
  <button onclick="executeSearch()">검색</button>
  
  <!-- 결과 리스트 영역 -->
  <ul id="result-list"></ul>
</div>

<script>
let currentMode = 'AI';
let currentRequestId = null; // 전역 변수나 상태로 requestId 관리

function setMode(mode) {
  // ... (기존과 동일)
}

function executeSearch() {
  const query = document.getElementById('search-input').value;
  
  if(currentMode === 'AI') {
    // AI 검색 호출
    genser.call('searchProducts', {
      instanceKey: 'YOUR_INSTANCE_KEY',
      queryText: query
    }).success(function(res) {
      currentRequestId = res.requestId; // ID 저장
      
      // 결과 렌더링
      renderList(res.products);
      
      // DI 로그 전송 (렌더링 직후)
      genser.call('DI', {
        instance: { key: 'YOUR_INSTANCE_KEY' },
        goods: res.products.map(p => ({ code: p.code, name: p.name })),
        requestId: res.requestId
      });
    });
  }
}

function renderList(products) {
  const ul = document.getElementById('result-list');
  ul.innerHTML = '';
  products.forEach(p => {
    const li = document.createElement('li');
    li.textContent = p.name;
    // 클릭 이벤트 바인딩
    li.onclick = function() {
      handleProductClick(p);
    };
    ul.appendChild(li);
  });
}

function handleProductClick(product) {
  if (!currentRequestId) return;
  
  genser.call('CL', {
    instance: { key: 'YOUR_INSTANCE_KEY' },
    goods: [{ code: product.code, name: product.name }],
    requestId: currentRequestId
  });
  
  console.log('CL 전송 및 이동', product.name);
}
</script>
```

</details>

## AI 검색 버튼 유도형 (Dropdown Nudge)

<figure><img src="/files/6Dojmr1a05ZImHKDlPHo" alt=""><figcaption></figcaption></figure>

* 기존 검색 UX를 해치지 않으면서 자연스럽게 AI 검색을 유도하는 방식입니다.&#x20;
* 사용자가 검색창을 클릭했을 때(Focus), 하단 드롭다운에 AI 검색 버튼을 노출합니다.
* AI 검색에 대한 고객 인지를 확실히 한 후 검색 페이지로 유도가 가능합니다.&#x20;

<details>

<summary>React 코드 예시</summary>

```javascript
const DropdownNudgePattern = () => {
  const [isFocused, setIsFocused] = useState(false);
  
  const goToAiSearch = () => {
    alert("AI 검색 모드로 전환!");
    // window.location.href = '/ai-search';
  };

  return (
    <div className="relative">
      <input
        type="text"
        placeholder="검색어를 입력하세요"
        onFocus={() => setIsFocused(true)}
        // Blur 시 바로 닫히면 버튼 클릭이 안 될 수 있으므로 약간의 지연을 줍니다.
        onBlur={() => setTimeout(() => setIsFocused(false), 200)}
      />
      
      {isFocused && (
        <div className="dropdown">
          {/* AI 검색 유도 버튼 */}
          <button onClick={goToAiSearch} className="ai-nudge-btn">
            <strong>✨ 내가 찾는 옷, AI에게 질문해보세요!</strong>
            <span>"이번주 하객룩 추천해줘"</span>
          </button>
          <ul><li>최근 검색어...</li></ul>
        </div>
      )}
    </div>
  );
};
```

</details>

<details>

<summary>Vue 코드 예시</summary>

```python
<template>
  <div class="search-wrap">
    <input 
      @focus="isFocused = true" 
      @blur="handleBlur"
      placeholder="검색어를 입력하세요" 
    />
    <div v-if="isFocused" class="dropdown">
      <button class="ai-nudge-btn" @click="goToAiSearch">
        <strong>✨ 내가 찾는 옷, AI에게 질문해보세요!</strong>
        <span>"이번주 하객룩 추천해줘"</span>
      </button>
      <ul class="history"><li>최근 검색어...</li></ul>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
// ... (이전과 동일)
</script>
```

</details>

<details>

<summary>HTML/JS 코드 예시</summary>

```js
<div class="search-box">
  <input type="text" id="inp-search" placeholder="검색어를 입력하세요">
  <!-- 기본적으로 숨겨져 있다가 Focus 시 노출 -->
  <div id="dropdown" class="dropdown-content hidden">
    <button class="ai-nudge-btn" onclick="goToAiSearch()">
      <strong>✨ 내가 찾는 옷, AI에게 질문해보세요!</strong>
      <span>"이번주 하객룩 추천해줘"</span>
    </button>
    <div class="history">최근 검색어...</div>
  </div>
</div>

<script>
  const input = document.getElementById('inp-search');
  const dropdown = document.getElementById('dropdown');

  input.addEventListener('focus', () => {
    dropdown.classList.remove('hidden'); // CSS .hidden { display: none; }
  });
  
  // blur 시 숨김 처리 (setTimeout으로 클릭 이벤트 허용 시간 확보)
  input.addEventListener('blur', () => {
    setTimeout(() => dropdown.classList.add('hidden'), 200);
  });

  function goToAiSearch() {
    alert("AI 검색 모드로 전환!");
    // location.href = '/ai-search';
  }
</script>
<style>
  .hidden { display: none; }
  .dropdown-content { position: absolute; /* 스타일 생략 */ }
</style>

```

</details>

## 검색 몰입형 (Immersive/Focus)

<figure><img src="/files/m6uKI3e0tP3GW0UDKxiM" alt=""><figcaption></figcaption></figure>

* ChatGPT나 Gemini와 유사한 스타일로, 검색 자체가 메인 기능인 페이지에서 사용합니다.&#x20;
* 긴 문장의 질문도 편하게 입력할 수 있도록 넓은 입력 영역을 제공합니다.
* 질의 예시를 노출하여 AI 검색 활성화를 자연스럽게 유도합니다.&#x20;

<details>

<summary>React 코드 예시</summary>

```javascript
const ImmersiveSearch = () => {
  const [query, setQuery] = useState('');
  const [products, setProducts] = useState([]);
  const [requestId, setRequestId] = useState(null);
  const textareaRef = useRef(null);

  // DI 로그 전송
  useEffect(() => {
    if (products.length > 0 && requestId) {
      window.genser.call('DI', {
        instance: { key: 'YOUR_INSTANCE_KEY' },
        goods: products.map(p => ({ code: p.code, name: p.name })),
        requestId: requestId
      });
    }
  }, [products, requestId]);
  
  // CL 로그 전송
  const handleProductClick = (product) => {
    if (!requestId) return;
    window.genser.call('CL', {
      instance: { key: 'YOUR_INSTANCE_KEY' },
      goods: [{ code: product.code, name: product.name }],
      requestId: requestId
    });
  };

  const handleInput = (e) => {
    setQuery(e.target.value);
    if (textareaRef.current) {
      textareaRef.current.style.height = 'auto';
      textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
    }
  };

  const executeSearch = () => {
    window.genser.call('searchProducts', {
      instanceKey: 'YOUR_INSTANCE_KEY',
      queryText: query
    }).success((res) => {
      if(res.type === 'SEARCH') {
        setProducts(res.products);
        setRequestId(res.requestId);
      }
    });
  };

  return (
    <div className="immersive-box">
      <textarea
        ref={textareaRef}
        value={query}
        onInput={handleInput}
        rows={1}
        placeholder="AI에게 무엇이든 물어보세요."
      />
      <button onClick={executeSearch}>Send</button>
      
      {/* 결과 리스트 */}
      <ul>
          {products.map(p => (
            <li key={p.code} onClick={() => handleProductClick(p)}>{p.name}</li>
          ))}
      </ul>
    </div>
  );
};

```

</details>

<details>

<summary>Vue 코드 예시</summary>

```python
<template>
  <div class="immersive-box">
    <textarea
      ref="textarea"
      v-model="query"
      @input="resize"
      rows="1"
      placeholder="AI에게 무엇이든 물어보세요."
    ></textarea>
    <button @click="executeSearch">Send</button>

    <!-- 결과 리스트 -->
    <ul>
      <li v-for="p in products" :key="p.code" @click="handleProductClick(p)">
        {{ p.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue';

const query = ref('');
const textarea = ref(null);
const products = ref([]);
const requestId = ref(null);

const resize = () => {
  const el = textarea.value;
  el.style.height = 'auto';
  el.style.height = el.scrollHeight + 'px';
};

const executeSearch = () => {
  window.genser.call('searchProducts', {
    instanceKey: 'YOUR_INSTANCE_KEY',
    queryText: query.value
  }).success((res) => {
    if (res.type === 'SEARCH') {
      products.value = res.products;
      requestId.value = res.requestId;

      // DI 로그 전송
      nextTick(() => {
        window.genser.call('DI', {
          instance: { key: 'YOUR_INSTANCE_KEY' },
          goods: res.products.map(p => ({ code: p.code, name: p.name })),
          requestId: res.requestId
        });
      });
    }
  });
};

// CL 로그 전송
const handleProductClick = (product) => {
  if (!requestId.value) return;
  window.genser.call('CL', {
    instance: { key: 'YOUR_INSTANCE_KEY' },
    goods: [{ code: product.code, name: product.name }],
    requestId: requestId.value
  });
};
</script>
```

</details>

<details>

<summary>HTML/JS 코드 예시</summary>

```js
<div class="immersive-box">
  <textarea id="ai-input" rows="1" placeholder="AI에게 무엇이든 물어보세요."></textarea>
  <button onclick="doSearch()">Send</button>
  <ul id="immersive-results"></ul>
</div>

<script>
  const tx = document.getElementById('ai-input');
  let currentRequestId = null;
  
  tx.addEventListener("input", function() {
    this.style.height = 'auto';
    this.style.height = (this.scrollHeight) + "px";
  });

  function doSearch() {
    const query = tx.value;
    genser.call('searchProducts', {
      instanceKey: 'YOUR_INSTANCE_KEY',
      queryText: query
    }).success(function(res) {
      if (res.type === 'SEARCH') {
        currentRequestId = res.requestId;
        renderImmersiveList(res.products);
        
        // DI 로그 전송
        genser.call('DI', {
          instance: { key: 'YOUR_INSTANCE_KEY' },
          goods: res.products.map(p => ({ code: p.code, name: p.name })),
          requestId: res.requestId
        });
      }
    });
  }

  function renderImmersiveList(products) {
    const ul = document.getElementById('immersive-results');
    ul.innerHTML = '';
    products.forEach(p => {
      const li = document.createElement('li');
      li.textContent = p.name;
      // CL 로그 전송 바인딩
      li.onclick = function() {
        if (currentRequestId) {
          genser.call('CL', {
            instance: { key: 'YOUR_INSTANCE_KEY' },
            goods: [{ code: p.code, name: p.name }],
            requestId: currentRequestId
          });
        }
      };
      ul.appendChild(li);
    });
  }
</script>
```

</details>

## 기존 검색창 연동형 (Simple Integration)

<figure><img src="/files/5mFGEx9zSdLUilWg7YVa" alt=""><figcaption></figcaption></figure>

* 별도의 UI/UX 변경 없이, 현재 사용 중인 검색창 로직에 genser 검색 엔진만 연결하는 방식입니다.
* 기존 검색창 UI를 그대로 유지함으로 UX에 대한 학습 등을 고객에게 요구하지 않고, AI 검색을 제공할 수 있습니다.&#x20;

<details>

<summary>React 코드 예시</summary>

```javascript
const SimpleSearch = () => {
  const [query, setQuery] = useState('');
  const [products, setProducts] = useState([]);
  const [requestId, setRequestId] = useState(null);

  // DI 로그 전송 (렌더링 직후)
  useEffect(() => {
    if (products.length > 0 && requestId) {
      window.genser.call('DI', {
        instance: { key: 'YOUR_INSTANCE_KEY' },
        goods: products.map(p => ({ code: p.code, name: p.name })),
        requestId: requestId
      });
    }
  }, [products, requestId]);

  // CL 로그 전송
  const handleProductClick = (product) => {
    if (!requestId) return;
    window.genser.call('CL', {
      instance: { key: 'YOUR_INSTANCE_KEY' },
      goods: [{ code: product.code, name: product.name }],
      requestId: requestId
    });
    // 이후 기존 상품 상세 페이지 이동 로직 실행
  };

  const handleSearch = (e) => {
    e.preventDefault();
    if (!query) return;

    // 기존 API 호출 대신 genser 호출
    window.genser.call('searchProducts', {
      instanceKey: 'YOUR_INSTANCE_KEY',
      queryText: query
    }).success((res) => {
      if (res.type === 'SEARCH') {
        // 기존 상태 업데이트 (변수명만 매핑)
        setProducts(res.products);
        setRequestId(res.requestId);
      }
    });
  };

  return (
    <div>
      <form onSubmit={handleSearch}>
        <input 
          type="text" 
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!"
        />
        <button type="submit">검색</button>
      </form>

      {/* 기존 결과 리스트 UI 유지 */}
      <ul>
        {products.map(p => (
          <li key={p.code} onClick={() => handleProductClick(p)}>
            {p.name}
          </li>
        ))}
      </ul>
    </div>
  );
};

```

</details>

<details>

<summary>Vue 코드 예시</summary>

```python
<template>
  <div class="search-container">
    <!-- 기존 검색 폼 -->
    <form @submit.prevent="handleSearch">
      <input v-model="query" placeholder="결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!" />
      <button type="submit">검색</button>
    </form>

    <!-- 기존 결과 리스트 UI -->
    <ul>
      <li v-for="p in products" :key="p.code" @click="handleProductClick(p)">
        {{ p.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue';

const query = ref('');
const products = ref([]);
const requestId = ref(null);

const handleSearch = () => {
  if (!query.value) return;

  // 기존 검색 로직을 genser 호출로 변경
  window.genser.call('searchProducts', {
    instanceKey: 'YOUR_INSTANCE_KEY',
    queryText: query.value
  }).success((res) => {
    if (res.type === 'SEARCH') {
      products.value = res.products;
      requestId.value = res.requestId;

      // DI 로그 전송 (DOM 업데이트 직후)
      nextTick(() => {
        window.genser.call('DI', {
          instance: { key: 'YOUR_INSTANCE_KEY' },
          goods: res.products.map(p => ({ code: p.code, name: p.name })),
          requestId: res.requestId
        });
      });
    }
  });
};

// CL 로그 전송
const handleProductClick = (product) => {
  if (!requestId.value) return;
  window.genser.call('CL', {
    instance: { key: 'YOUR_INSTANCE_KEY' },
    goods: [{ code: product.code, name: product.name }],
    requestId: requestId.value
  });
};
</script>
```

</details>

<details>

<summary>HTML/JS 코드 예시</summary>

```js
<div class="search-box">
  <input type="text" id="searchInput" placeholder="결혼식에 입고 갈 30대 여자 네이비 자켓 추천해줘!">
  <button onclick="executeSearch()">검색</button>
</div>
<ul id="resultList"></ul>

<script>
let currentRequestId = null;

function executeSearch() {
  const query = document.getElementById('searchInput').value;
  if (!query) return;

  // 기존 AJAX 호출 부분을 genser 호출로 교체
  genser.call('searchProducts', {
    instanceKey: 'YOUR_INSTANCE_KEY',
    queryText: query
  }).success(function(res) {
    if (res.type === 'SEARCH') {
      currentRequestId = res.requestId;
      renderList(res.products); // 기존 렌더링 함수 재사용

      // DI 로그 전송 (렌더링 직후)
      genser.call('DI', {
        instance: { key: 'YOUR_INSTANCE_KEY' },
        goods: res.products.map(p => ({ code: p.code, name: p.name })),
        requestId: res.requestId
      });
    }
  });
}

function renderList(products) {
  const ul = document.getElementById('resultList');
  ul.innerHTML = '';
  products.forEach(p => {
    const li = document.createElement('li');
    li.textContent = p.name;
    // CL 로그 전송 바인딩
    li.onclick = function() {
      handleProductClick(p);
    };
    ul.appendChild(li);
  });
}

function handleProductClick(product) {
  if (!currentRequestId) return;
  
  genser.call('CL', {
    instance: { key: 'YOUR_INSTANCE_KEY' },
    goods: [{ code: product.code, name: product.name }],
    requestId: currentRequestId
  });
  // 페이지 이동
}
</script>
```

</details>


---

# 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.genser.ai/integration/frontend-installation/installation-tips.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.
