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?

🎓 講義音声からAIナレッジBotを自作してみた①

Last updated at Posted at 2025-05-26

🎓 講義音声からAIナレッジBotを自作してみた話

大学で受けた講義、自分で録音した勉強会の音声…。
それらを「文字起こし → ナレッジ化 → 自然言語で質問できるBot」に変えたくて、
Whisper × LangChain × FAISS × Streamlit を使って、RAG(Retrieval-Augmented Generation)構成のローカルBotを作りました。

本記事では、その全手順をまとめます。


🧭 ゴール

  • .mp3 の講義音声を文字起こし
  • 自動でテキスト整理(フォルダ構成付き)
  • テキストをベクトルDBに変換(FAISS)
  • LLMと組み合わせて Q&A Bot 化
  • 最終的に Web UI(Streamlit)で操作可能に

🛠 使用技術

技術 役割
Python 全体の実装
Whisper 音声文字起こし(openai/whisper)
LangChain ナレッジ処理・検索
FAISS ベクトルDB(Meta製)
HuggingFace Embedding 日本語対応の文ベクトル化
Streamlit Web UI作成
Ubuntu + CUDA + NVIDIA RTX4060 ローカルGPUで高速処理

📁 プロジェクト構成

ai_lecture_bot/
├── transcribe_and_organize.py      # Whisper実行+整理
├── ingest.py                       # テキスト → ベクトルDB
├── query_bot.py                    # CLI型Bot
├── app.py                          # Streamlit UI
├── data/
│   ├── lecture_01/
│   │   ├── lecture_01.txt, .mp3...
│   └── ...
└── db/                             # FAISS保存先

① 音声 → テキスト化(Whisper)

Whisperを使って .mp3 ファイルを文字起こしし、さらに自動で講義ごとのディレクトリに整理するスクリプトです。GPUを最大活用するため、multiprocessing を使って並列実行しています。

# transcribe_and_organize.py
# mp3ファイルをWhisperで文字起こしし、lecture_xxフォルダに整理するスクリプト

import subprocess
import os
import shutil
from multiprocessing import Pool

def transcribe_and_organize(index):
    # 対象のファイル名(例:lecture_01)
    filename = f"lecture_{index:02}"
    mp3_file = f"{filename}.mp3"
    print(f"🚀 GPUで文字起こし中: {mp3_file}")

    # Whisperを使って文字起こしを実行
    subprocess.run([
        "whisper",
        mp3_file,
        "--language", "Japanese",
        "--model", "medium",
        "--device", "cuda"  # GPUを使用
    ])

    # 出力ファイルを lecture_xx/ ディレクトリに整理
    output_dir = os.path.join("data", filename)
    os.makedirs(output_dir, exist_ok=True)

    # mp3 + Whisperの出力ファイルをすべて移動
    for ext in [".mp3", ".txt", ".json", ".srt", ".vtt"]:
        src = f"{filename}{ext}"
        dst = os.path.join(output_dir, src)
        if os.path.exists(src):
            shutil.move(src, dst)

if __name__ == "__main__":
    num_files = 62          # 処理対象のmp3ファイル数(lecture_01〜lecture_62)
    max_processes = 2       # 並列実行数(GPU性能に応じて調整)
    with Pool(processes=max_processes) as pool:
        pool.map(transcribe_and_organize, range(1, num_files + 1))

🔍 出力例

data/
├── lecture_01/
│   ├── lecture_01.mp3
│   ├── lecture_01.txt
│   ├── lecture_01.json
│   ├── lecture_01.srt
│   └── lecture_01.vtt
├── lecture_02/
│   └── ...

💡 補足

GPUの使用状況は別ターミナルで watch -n 1 nvidia-smi を実行すると確認できます。

medium モデルは1プロセスあたり約3〜4GBのVRAMを使うため、RTX 4060(8GB)なら2並列がベストバランスです。

② テキスト → ベクトルDB化(LangChain + FAISS)

次に、文字起こしされた .txt ファイルをベクトルDBに変換します。チャンク分割したテキストを日本語対応の埋め込みモデルでベクトル化し、FAISSに保存します。

# ingest.py
# 整理された講義テキストをチャンク分割してベクトルDB(FAISS)に保存するスクリプト

from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings

# data/ 以下の lecture_xx/*.txt をすべて読み込む
loader = DirectoryLoader("data", glob="**/*.txt")
docs = loader.load()

# テキストを約500文字ごとに分割(チャンク)
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
split_docs = splitter.split_documents(docs)

# 日本語対応の埋め込みモデルを使用(E5-small)
embedding = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-small")

# 分割テキストをベクトル化し、FAISSに保存
db = FAISS.from_documents(split_docs, embedding)
db.save_local("db")  # 保存先は ./db ディレクトリ

③ 対話Bot構築(LangChain + Ollama)

構築したベクトルDBをもとに、自然言語で質問できるBotを作成します。ローカルLLM(Ollama)とLangChainの RetrievalQA を組み合わせます。

# query_bot.py
# ローカルベクトルDBを使ってユーザーの質問に回答する対話Bot(CLI形式)

from langchain.chains import RetrievalQA
from langchain.llms import Ollama
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings

# ベクトルDBの埋め込みと検索設定
embedding = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-small")
db = FAISS.load_local("db", embedding)

# OllamaのローカルLLM(例:mistral)を使って回答生成
qa = RetrievalQA.from_chain_type(
    llm=Ollama(model="mistral"),
    retriever=db.as_retriever()
)

# ユーザーが質問を入力するループ
while True:
    query = input("💬 質問を入力してください: ")
    print("🧠 回答:", qa.run(query))

④ Web UIで対話(Streamlit)

最後に、StreamlitでUIを構築し、ブラウザ上で対話できるようにします。

# app.py
# StreamlitでWeb UIを構築し、質問→回答までをブラウザで実行できるようにするスクリプト

import streamlit as st
from query_bot import qa  # 上で定義した RetrievalQA を読み込む

# タイトル表示
st.title("🎓 講義AIナレッジBot")

# ユーザーの入力欄
query = st.text_input("質問をどうぞ(例:『DNAとは何か?』など)")

# 質問が入力されたら回答を生成
if query:
    with st.spinner("考え中..."):
        answer = qa.run(query)
        st.success(answer)

今後のステップ

ステップ0:ベーシックな手動フローの完成

  • transcribe_and_organize.py で文字起こし+整理
  • ingest.py でベクトルDB化
  • query_bot.pyapp.py で対話まで動作
    • まずは Docker やエージェントを使わず、ターミナルで順に実行できれば OK
      python transcribe_and_organize.py
      python ingest.py
      streamlit run app.py
      
  • 成功条件
    • 各ステップで想定どおりのファイル・DB が更新されている
    • UI から質問 → 回答まで問題なく返ってくる

ステップ1:環境の固定化+自動化

  • 各サービスに Dockerfile を追加してコンテナ化
  • docker-compose.yml で複数コンテナを一括起動
  • agent/watch_and_run.py でフォルダ監視を組み込み、自動実行

ステップ2:CI/CD/Observability の導入

  • GitHub Actions でビルド → テスト → リリースを自動化
  • OpenTelemetry + Grafana で処理時間・エラーを可視化
  • Slack 通知 などのアラート設定を追加

拡張アイデア

  • lecture_data.csv を活用して meta.json を生成し、講義タイトル・日付などのフィルターを可能に
  • ノートや回答ログの保存、Notion連携

まとめ

音声を知識化し、ベクトルDBで検索、ローカルLLMで回答、そしてUIまで一貫して構築できるこの構成は、まさに「未来の自分用知識アーカイブBot」。

同じように学習や仕事に活用したい人の参考になれば幸いです。
コメント・質問大歓迎です!🙌

🧷 GitHub

準備中(またはURLをここに記載)

🙏 Thanks

AIエージェント駆動型の開発に興味があるのでこれからも学習を続けて行こうと思っています!!

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?