GCP/Apps Script

Apps Script로 Bing Search API 결과를 OpenAI로 요약하기

whistory 2024. 4. 3. 10:35
반응형

 

 

Azure 에 Bing Search를 이용해 데이터를 검색해본다.

var bingApiKey = "Bing Search API 키";
var bingEndpoint = "https://api.bing.microsoft.com/v7.0/search";

function runBingSearch(searchQuery) {
  searchQuery = "비트코인 시황 알려줘";
  console.log(`####### 질문 : ${searchQuery}`)
  const headers = {'Ocp-Apim-Subscription-Key': bingApiKey};
 
  const mkt = 'ko-KR';
  const cc = 'KR';
  const promote = 'Webpages,News'; // 답변 승격
  const answerCount = 5;
  const count = 3;
  const setLang = 'ko';
  const freshness = 'day'; // 콘텐츠 최신성
  const url = `${bingEndpoint}?q=${URLEncode(searchQuery)}&freshness=${freshness}&count=${count}`
  
  try {
    const response = UrlFetchApp.fetch(url, {
                              method : "GET",
                              muteHttpExceptions :true,
                              headers:{
                                "Ocp-Apim-Subscription-Key": bingApiKey
                              }
    });
    const json = response.getContentText();
    const returndData = JSON.parse(json);
    const values = returndData.webPages.value;

    for ( i in values ) {
      const value = values[i];
      console.log(`### ${parseInt(i)+1}번째 검색 결과`)
      console.log(`제목 : ${value.name}`);  // 제목
      console.log(`내용미리보기 : ${value.snippet}`);  // 내용미리보기
      console.log(`url : ${value.url}`);  // url
      console.log(`작성시간 : ${value.datePublishedFreshnessText}`);  // 작성시간
    }
  } catch (error) {
    console.error('Error:', error);
    return null;
  }
}

 

제목, 미리보기, url 등은 가져오지만 전체 내용을 가져올수는 없다.

 

 

 

 

 

 python 이라면 bs4를 사용해 텍스트를 추출하면되지만, 

apps script라 다른방법을 사용했다.

 

커피를 끊어서 머리가 안돌아가서 대충 했다.

urlfetch로 페이지를 읽고, 텍스트만 추출한뒤 

본문으로 추측되는 부분을 확인하여

 

gpt에게 전달해 내용을 정리하고 요약할수 있도록 구성했다.

 

var bingApiKey = "Bing Search API 키";
var bingEndpoint = "https://api.bing.microsoft.com/v7.0/search";

function runBingSearch(searchQuery) {
  searchQuery = "비트코인 시황 알려줘";
  console.log(`####### 질문 : ${searchQuery}`)
  const headers = {'Ocp-Apim-Subscription-Key': bingApiKey};
 
  const mkt = 'ko-KR';
  const cc = 'KR';
  const promote = 'Webpages,News'; // 답변 승격
  const answerCount = 5;
  const count = 5;
  const setLang = 'ko';
  const freshness = 'day'; // 콘텐츠 최신성

  const params = {
                    'q': searchQuery,
                    'mkt': mkt,
                    'setLang': setLang,
                    'cc': cc,
                    'promote': promote,
                    'answerCount': answerCount,
                    'count': count,
                    'freshness': freshness,
  };
  const url = `${bingEndpoint}?q=${URLEncode(searchQuery)}&freshness=${freshness}&count=${count }`
  
  try {
    const response = UrlFetchApp.fetch(url, {
                              method : "GET",
                              muteHttpExceptions :true,
                              headers:{
                                "Ocp-Apim-Subscription-Key": bingApiKey
                              }
    });
    const json = response.getContentText();
    const returndData = JSON.parse(json);
    const values = returndData.webPages.value;
    
    console.log("######### 5개 결과 보기");
    for ( i in values ) {
      console.log(`### ${parseInt(i)+1}번째 검색 결과`)
      const value = values[i];
      console.log(`제목 : ${value.name}`);  // 제목
      console.log(`내용미리보기 : ${value.snippet}`);  // 내용미리보기

      const data_response = UrlFetchApp.fetch(value.url, {
                              method : "GET",
      });
      const htmlResult = data_response.getContentText();

      // HTML에서  태그 안에 있는 텍스트만 추출하는 정규식
      var bodyTextRegex = /<body[^>]*>([\\s\\S]*?)<\\/body>/i;
      var match = htmlResult.match(bodyTextRegex);
      var bodyText = "";
      //  안에 있는 텍스트가 있는 경우 추출
      if (match && match[1]) {
        bodyText = match[1];
        // 클래스와 자바스크립트가 있는 요소 제거
        bodyText = bodyText.replace(/<\\s*(?:script|style)[^>]*>[\\s\\S]*?<\\/\\s*(?:script|style)\\s*>/ig, '');
        // HTML 태그 제거
        bodyText = bodyText.replace(/<[^>]+>/g, '');
        // 공백 및 줄바꿈 정리
        bodyText = bodyText.trim().replace(/\\s+/g, ' ');
      } else {
        Logger.log("No body text found in the response.");
      }

      var snippet = value.snippet;
      var snippet_pattern = /(\\S+)\\s+(\\S+)/;

      // 제목과 일치하는 부분으로 자름
      var matches = snippet.match(snippet_pattern);
      var snippet_short = matches[0];

      const split_text = bodyText.split(snippet_short);
      const extractBody = snippet_short + split_text[1];
      
      // 이메일로 맨마지막 확인
      var emailRegex = /[a-zA-Z0-9+-\\_.]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]/;
      const email = extractBody.match(emailRegex);
      const finalText =  extractBody.split(email);
      // console.log(finalText[0])
      const summaryResult = summaryAzureOpenAi(finalText[0]);
      console.log("############ GPT로 요약한 결과 ############")
      console.log(summaryResult);
    }
  } catch (error) {
    console.error('Error:', error);
    return null;
  }
}

var AOAI = {
  env: {
    'AZURE_OPENAI_ENDPOINT' : "https://리소스이름.openai.azure.com/",
    'AZURE_OPENAI_RESOURCE' : "리소스이름",
    'AZURE_OPENAI_MODEL' : "gpt 모델",
    'AZURE_OPENAI_MODEL_NAME' : "gpt 모델 배포이름",
    'AZURE_OPENAI_KEY' : "api 키",
    'AZURE_OPENAI_MAX_TOKENS' : 1900,
    'AZURE_OPENAI_PREVIEW_API_VERSION' : '2023-06-01-preview',
    'AZURE_OPENAI_TEMPERATURE' : 0.1,
    'AZURE_OPENAI_TOP_P' : 1.0,
    'AZURE_OPENAI_STOP_SEQUENCE' : "", 
    'AZURE_OPENAI_STREAM' : false,
    'AZURE_OPENAI_SYSTEM_MESSAGE' : "입력된 내용을 요약해줘. 뒤에 문맥과 어울리지 않는 부분은 요약하지마."
  }
};
function summaryAzureOpenAi(message) {
  const url = `${AOAI.env.AZURE_OPENAI_ENDPOINT}openai/deployments/${AOAI.env.AZURE_OPENAI_MODEL}/chat/completions?api-version=${AOAI.env.AZURE_OPENAI_PREVIEW_API_VERSION}`;

  var formData = { "max_tokens":AOAI.env.AZURE_OPENAI_MAX_TOKENS,
                  "messages":[{"role": "system", "content": AOAI.env.AZURE_OPENAI_SYSTEM_MESSAGE},{"role": "user", "content": message}]
                  };

  const response = UrlFetchApp.fetch(url, {
    method : "POST",
    headers:{
      "api-key" : AOAI.env.AZURE_OPENAI_KEY,
      "Content-Type": "application/json"
    }
    , payload: JSON.stringify(formData)
  });

  const json        = response.getContentText();
  const returndData = JSON.parse(json);
  console.log(json)
  const contents    = returndData.choices[0].message.content;
  return contents;
}

 

반응형