2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

メモ書きからQiita記事自動作成→投稿の仕組みをAWSCDKで作ってみた

Posted at

自動Qiita投稿システムを作ってみた

今日は、勉強メモをQiitaに自動投稿するシステムを作った話をシェアします。

動機

AWSの資格勉強をしている中で、分からないところのメモを取っていました。このメモをなんとかアウトプットとして活用できないかと考え、Qiitaへの投稿を自動化しようと思い立ちました。

ワークフロー🔗

以下の流れで自動投稿システムを作りました。

  1. LINEbotにメモを送信
  2. API Gatewayで受け取りLambdaに流す
  3. LambdaでメモをBeadrockに渡し、Markdownの記事を作成
  4. Qiita APIで投稿

コード

LINEbotからメモを受け取るLambda

LINEBotにメモを送信するとAPIGatewayのエンドポイントに送信するようMessageAPIを設定します。

トークンはSecretManagerに格納しておき、LambdaでLINEからのメッセージを受け取ります。

import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";

// --- 型定義 ---
interface QiitaPostResponse {
  url: string;
  title: string;
  id: string;
  [key: string]: unknown;
}

interface Secrets {
  LINE_CHANNEL_ACCESS_TOKEN: string;
  QIITA_ACCESS_TOKEN: string;
  BEDROCK_API_KEY: string;
}

// --- Lambda Handler ---
export const handler = async (event: any) => {
  const secretsClient = new SecretsManagerClient({ region: "XXX" });
  const parsedEvent = typeof event.body === "string"
    ? JSON.parse(event.body)
    : event;

  try {
    // Secrets Manager からキーを取得
    const secretRes = await secretsClient.send(
      new GetSecretValueCommand({
        SecretId: process.env.SECRET_NAME
      })
    );

    if (!secretRes.SecretString) {
      throw new Error("Secrets not found");
    }

    const secrets: Secrets = JSON.parse(secretRes.SecretString);

    if (!parsedEvent.events || !Array.isArray(parsedEvent.events) || parsedEvent.events.length === 0) {
      return { statusCode: 200, body: "非対応イベント" };
    }

    const lineEvent = parsedEvent.events[0];
    if (!lineEvent || lineEvent.type !== "message" || !lineEvent.message?.text) {
      return { statusCode: 200, body: "非対応イベント" };
    }

    const userMessage = lineEvent.message.text;

BeadrockでMarkdown記事を作成するLambda

受け取ったメッセージをあらかじめ用意したプロンプトに織り交ぜ生成AIに投げます。
今回はNovaというモデルを採用しています。

// --- Bedrock Claude に送信 ---
    const bedrockClient = new BedrockRuntimeClient({ region: "xxx" });
    const prompt = `あなたはQiitaで記事を書くエンジニアです。
    ユーザーから与えられたメモをもとに、Qiita用のMarkdown記事を文章を作成してください。

    # 要件
    - 見出し・箇条書き・コード例・注意点を含める
    - 未検証部分は「補足: 未検証」と記載
    - 動機セクションを記載
    - まとめセクションを最後に追加
    - タイトルは内容を要約したもの

    === メモ:\n\n${userMessage}`;

 const input = {
        modelId: "XXXnovaXXX",
        contentType: "application/json",
        accept: "application/json",
        body: JSON.stringify({
          messages: [
            {
              role: "user",
              content: [{ text: prompt }],
            },
          ],
          inferenceConfig: {
            maxTokens: 1024,
            temperature: 0.7,
          },
        }),
      };

    const bedrockRes = await bedrockClient.send(new InvokeModelCommand(input));
    const responseBody = await bedrockRes.body.transformToString();
    const claudeData = JSON.parse(responseBody);
    const articleBody = claudeData.output?.message?.content?.[0]?.text || "";

Qiita APIで投稿するLambda

QiitaのAPIを介してQiitaに記事を投稿します。

// --- Qiita 下書き作成 ---
    const qiitaRes = await fetch("https://qiita.com/api/v2/items", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${secrets.QIITA_ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        body: articleBody,
        private: false,
        draft: true, 
        tags: [{ name: "自動投稿", versions: [] }],
        title: "Lambdaからの自動投稿",
      }),
    });

    if (!qiitaRes.ok) {
      const text = await qiitaRes.text();
      throw new Error(`Qiita API Error: ${qiitaRes.status} ${text}`);
    }

    const qiitaResult: QiitaPostResponse = await qiitaRes.json() as QiitaPostResponse;

実装の上で苦労した点

  • Qiita APIの制約: QiitaのAPIでは下書きに直接投稿できないため、投稿し、コピペし、投稿を削除し、下書きを新しく手動で作るという手間が生じています。
  • APIのレスポンス処理: 各APIのレスポンスのエラー処理に一番時間を取られました。CloudWatch様様です。地道にデバッグしました。

改善点として

QiitaのAPIの使用上、直接下書き保存ができないので、下書きに直接投げれるような仕組みを思案中です。

まとめ🏁

今日は、勉強メモを自動でQiitaに投稿するシステムを作った話をしました。

この記事含め、学習記録の記事はこのシステムを活用して投稿してます。

何か質問やフィードバックがあれば、ぜひコメント欄にご意見ください!💬

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?