0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChatGPTを使ってGoogle Patentから自動で最新の特許を要約して、メールを送る

Last updated at Posted at 2024-08-09

お世話になります。@tmiyamanさんの記事を参考にして、GooglePatentから最新の特許が自動で送られてくる、GASを作成しました。
参考に下リンクは以下の通り、
https://qiita.com/tmiyama/items/646595ac76dab039b6ec

GASスクリプトの全文

// API keys
const OPENAI_API_KEY = "chatgpt API";
var SERPAPI_API_KEY = "SERP API";
// 結果メールの送信先
const EMAIL_RECIPIENT = "メールアドレル";
// Key word
const keyword = '検索キーワード';
// 結果メールのタイトル
const EMAIL_SUBJECT = `Google Patents 要約 (${keyword}) `;
// 結果メールの送信者の名前
const EMAIL_SENDER = "要約bot";
// 最大特許数
const MAX_PATENT_COUNT = 5;
// 最新から検索対象日数
const DAYS = 365;

function main() {
  var results = getMostRecentPatentUrlSerpApi(keyword);
  
  if (results) {
    var output = "新着特許のお知らせ\n\n";
    var patentCount = 0;

    for (let i = 0; i < results.length; i++) {
      var title = results[i].title;
      var patentId = results[i].patent_id;
      var url = `https://patents.google.com/patent/${patentId.split('/')[1]}/en`;
      
      // 特許ページのHTMLを取得
      var htmlContent = UrlFetchApp.fetch(url).getContentText();
      
      // 出願日を取得
      var filingDate = extractFilingDate(htmlContent);
      
      // メタタグのdescriptionを抽出
      var metaDescription = extractMetaDescription(htmlContent);

      // ChatGPTで日本語200字程度に要約
      const input = `以下のメタタグdescriptionの内容を日本語で200字程度に要約してください。出願日: ${filingDate}\n\n${metaDescription}`;
      const res = callChatGPT(input);

      if (res && res.choices && res.choices.length > 0) {
        const paragraphs = res.choices.map((c) => c.message.content.trim());
        output += `Title: ${title}\n` + `URL: ${url}\n` + `出願日: ${filingDate}\n` + `${paragraphs.join("\n")}\n\n\n`;
      } else {
        output += `Title: ${title}\n` + `URL: ${url}\n` + `出願日: ${filingDate}\n` + `要約を取得できませんでした。\n\n\n`;
        Logger.log("要約の取得に失敗しました。レスポンス: " + JSON.stringify(res));
      }
      
      patentCount += 1;
      if (patentCount == MAX_PATENT_COUNT) break;
    }

    if (patentCount == 0) {
      output = "No new patents found \n ";
    } 
  } else {
    output = "No patents found (check keyword) \n ";
  }

  sendEmail(output);
}

function getMostRecentPatentUrlSerpApi(keyword) {
  var searchUrl = 'https://serpapi.com/search.json?q=' + encodeURIComponent(keyword) +
                  '&engine=google_patents' +
                  '&api_key=' + SERPAPI_API_KEY +
                  '&sort=new';  // ソートを最新順に設定
  
  var options = {
    'method': 'get',
    'muteHttpExceptions': true,
    'followRedirects': true
  };
  
  var response = UrlFetchApp.fetch(searchUrl, options);
  var content = JSON.parse(response.getContentText());
  
  if (content.organic_results && content.organic_results.length > 0) {
    return content.organic_results;
  } else {
    Logger.log("No patents found.");
    return null;
  }
}

function extractFilingDate(htmlContent) {
  // HTMLから出願日を抽出
  var filingDateStart = htmlContent.indexOf('<time itemprop="date" datetime="');
  if (filingDateStart === -1) return "出願日情報なし";

  filingDateStart = htmlContent.indexOf('datetime="', filingDateStart) + 10; // datetime=" の位置を特定
  var filingDateEnd = htmlContent.indexOf('"', filingDateStart); // " で閉じられる位置を特定
  if (filingDateEnd === -1) return "出願日情報なし";

  var filingDate = htmlContent.substring(filingDateStart, filingDateEnd).trim();

  return filingDate;
}

function extractMetaDescription(htmlContent) {
  // HTMLから<meta name="description" content="...">の内容を抽出
  var metaTagStart = htmlContent.indexOf('<meta name="description"');
  if (metaTagStart === -1) return "メタタグdescriptionが見つかりませんでした。";

  var contentStart = htmlContent.indexOf('content="', metaTagStart) + 9; // content=" の位置を特定
  var contentEnd = htmlContent.indexOf('"', contentStart); // " で閉じられる位置を特定
  if (contentEnd === -1) return "メタタグdescriptionの内容が見つかりませんでした。";

  var description = htmlContent.substring(contentStart, contentEnd).trim();

  return description;
}

function callChatGPT(input) {
    const messages = [
        {
            role: "user",
            content: input,
        },
    ];

    const url = "https://api.openai.com/v1/chat/completions";

    const options = {
        "method": "post",
        "headers": {
            "Authorization": `Bearer ${OPENAI_API_KEY}`,
            "Content-Type": "application/json",
        },
        "payload": JSON.stringify({
            model: "gpt-4o-mini",  // モデルをGpt4o-miniに設定
            messages: messages,
            max_tokens: 200,  // レスポンスのトークン数を制限
        }),
        "muteHttpExceptions": true  // 詳細なエラーメッセージを取得
    };

    try {
        const response = UrlFetchApp.fetch(url, options);
        const statusCode = response.getResponseCode();

        if (statusCode === 429) {
            // TPM制限に達した場合、30秒待機して再試行
            Logger.log("TPM制限に達しました。30秒待機して再試行します。");
            Utilities.sleep(30000);  // 30秒待機
            return callChatGPT(input);  // 再試行
        }

        const jsonResponse = JSON.parse(response.getContentText());

        // チェック: レスポンスが適切か
        if (jsonResponse && jsonResponse.choices && jsonResponse.choices.length > 0) {
            return jsonResponse;
        } else {
            Logger.log("ChatGPTレスポンスに問題があります。レスポンス: " + JSON.stringify(jsonResponse));
            return null;
        }
    } catch (e) {
        Logger.log("Error: " + e.message);
        return null;
    }
}

function sendEmail(body) {
    const options = { name: EMAIL_SENDER };
    GmailApp.sendEmail(EMAIL_RECIPIENT, EMAIL_SUBJECT, body, options);
}

以下はステップ・バイ・ステップでのスクリプトの概要です

このスクリプトは、特許情報を自動的に検索し、要約を生成し、メールで送信するプロセスを自動化します。

1. APIキーの設定

最初に、OpenAI APIキーとSERP APIキーを設定します。これにより、後でAPIリクエストを行う際に認証情報を提供します。

2. 検索条件とメール設定

次に、以下のパラメータを設定します。

  • 検索するキーワード (keyword)
  • 結果のメールを送信するアドレス (EMAIL_RECIPIENT)
  • メールの件名 (EMAIL_SUBJECT)
  • 検索結果の上限数 (MAX_PATENT_COUNT)
  • 検索対象の日数 (DAYS)

3. main 関数

この関数はスクリプトのエントリーポイントで、以下のステップを順に実行します。

  1. 特許の検索:
    getMostRecentPatentUrlSerpApi 関数を呼び出して、指定されたキーワードに基づいて最新の特許を検索します。

  2. 検索結果の処理:
    取得した特許結果をループで処理します。各特許について、タイトル、特許ID、URLを取得し、特許の詳細ページを取得します。

  3. 出願日の抽出:
    extractFilingDate 関数を使用して、特許ページから出願日を抽出します。

  4. メタタグdescriptionの抽出:
    extractMetaDescription 関数を使用して、特許ページのメタタグに含まれるdescriptionを抽出します。

  5. ChatGPTを使用した要約の生成:
    抽出したdescriptionと出願日を含めて、ChatGPTに要約を依頼します。要約の結果を保存します。

  6. メールの送信:
    すべての特許を処理した後、要約をメールで送信します。

4. getMostRecentPatentUrlSerpApi 関数

この関数は、指定されたキーワードを使用してSERP APIにリクエストを送り、最新の特許結果を取得します。取得した結果はJSON形式で解析され、特許の情報を返します。

5. extractFilingDate 関数

この関数は、特許ページのHTMLから出願日を抽出します。HTMLタグ <time itemprop="date" datetime="..."> から出願日を取得し、返します。

6. extractMetaDescription 関数

この関数は、特許ページのHTMLからメタタグ <meta name="description" content="..."> の内容を抽出します。これにより、特許の概要を取得します。

7. callChatGPT 関数

この関数は、ChatGPT APIを呼び出し、指定された入力テキストに基づいて要約を生成します。APIリクエストが失敗した場合、一定時間待機して再試行する処理も含まれています。

8. sendEmail 関数

最後に、この関数はGmailAppを使用して生成された要約を指定されたメールアドレスに送信します。送信者名も指定できます。


これらのステップに従ってコードが実行され、検索キーワードに基づく最新の特許情報を取得し、ChatGPTを使用して要約を生成し、それをメールで送信します。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?