Изначально я собирался извлечь стенограммы из видео на YouTube напрямую с помощью Assemblyai, однако Google слишком продвинут и начал предоставлять стенограммы автоматически.

сборка — отличный инструмент для извлечения стенограмм из видео, я использовал его для презентаций для инвесторов из других источников.

Старый проект (ytube_nlp) Раньше я использовал jinja2 для создания страниц расшифровки, у меня не было оглавления или группировки видео по категориям. Кроме того, на ytube_nlp нет rss-канала, поэтому я не могу знать, когда выходят новые видео.

Моя последняя итерация, media_nlp предназначен для работы с любыми носителями (в основном видео на YouTube) и извлечения стенограммы и других метаданных.

Улучшения включают в себя:

  • rss лента с astrojs
  • инкрементная генерация страниц с помощью astrojs, возможность напрямую обслуживать файлы json, если это необходимо
  • возможность группировать видео по категориям
  • улучшенные электронные письма


Объяснение технической архитектуры

Есть два основных компонента в media_nlp.

Сценарий Python для сбора стенограммы (с использованием youtube_transcript_api) и создание статического сайта, о котором позаботится звезды.

Скрипты python в папке scripts в значительной степени вдохновлены ytube_nlp, но генерируют файлы json для обработки с помощью astrojs. Он использует API данных YouTube для извлечения видео, которые были загружены за 24 часа для интересующих каналов (жестко закодировано в файле config.yml).

def search_videos_for_channel(channel_id, params=dict(part="snippet")):
    youtube_api = "
    youtube_api_key = os.getenv("YOUTUBE_API_KEY")
    if youtube_api_key is None:
        raise SystemExit("Need Youtube API KEY")
    params["channelId"] = channel_id
    params["order"] = "date"
    current_date = datetime.now(timezone.utc)
    # hardcoded fix for now, only query for videos in august
    publishedAfter = (current_date - timedelta(days=REF_DAYS)).isoformat()
    params["publishedAfter"] = publishedAfter
    params["maxResults"] = 100
    params["key"] = youtube_api_key

    r = requests.get(youtube_api, params=params).json()
    # Check if an error object is present
    if r.get("error") is not None:
        print(r)
        print("Add Authentication Key")
    return r
Войти в полноэкранный режим

Выйти из полноэкранного режима

Вышеупомянутая функция захватывает видео из API YouTube в течение параметризованного периода времени (обычно день для моих целей). Маловероятно, что пользователи создадут более 100 видеороликов, но это возможно для крупных новостных каналов, таких как cnbc.

def extract_key_video_data(video_data):
    # Takes video search response and extracts the data of interest
    # videoId, title, description, channelId, publishedAt
    key_video_data = []
    if video_data is None or video_data is []:
        return
    # video id is None do nothing, it happens during livestreams
    # before publishing
    for video in video_data.get("items"):
        snippet = video.get("snippet")
        vid_id = video.get("id")

        videoId = vid_id.get("videoId", None)
        if videoId == None:
            continue
        channelId = snippet.get("channelId")
        description = snippet.get("description")
        title = snippet.get("title")
        publishedAt = snippet.get("publishedAt")
        video_data = dict(
            videoId=videoId,
            channelId=channelId,
            description=description,
            title=title,
            publishedAt=publishedAt,
        )
        key_video_data.append(video_data)
    return key_video_data
Войти в полноэкранный режим

Выйти из полноэкранного режима

Это создает список ключевых данных, которые меня интересуют, publishDate, который полезен для определения вероятности наличия стенограммы.

После этого он использует youtube_transcript_api для извлечения стенограммы из видео. Для появления расшифровки видео требуется несколько часов.
После получения расшифровки spacy используется для обнаружения сущностей, а затем результаты записываются в файл json.

Теперь сайт astro может анализировать всю эту информацию, а затем выводить ее в статический html.

Итак, я создал два действия github, одно зависит от другого.

Задание Cron для сканирования файлов YouTube и обновления репозитория новыми данными стенограммы YouTube.

name: Scan YTube
# Don't want to burn my private minutes at this point
on:
  push:
    branches:
      - master
      - main
    paths-ignore:
      - "website/**"
  schedule:
    # * is a special character in YAML so you have to quote this string
    - cron:  '30 13 * * *'


env:
  YOUTUBE_API_KEY: ${{ secrets.YOUTUBE_API_KEY  }}
  MJ_APIKEY_PUBLIC: ${{ secrets.MJ_APIKEY_PUBLIC }}
  MJ_APIKEY_PRIVATE: ${{ secrets.MJ_APIKEY_PRIVATE }}
  DISCORD_CODE_STATUS_WEBHOOK: ${{ secrets.DISCORD_CODE_STATUS_WEBHOOK }}
  DISCORD_VIDEO_WEBHOOK: ${{ secrets.DISCORD_VIDEO_WEBHOOK }}

jobs:
  make_report:
    name: Generate Report
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: Set up Python 3.x
        uses: actions/setup-python@v1
        with:
          python-version: '3.8' # Semantic version range syntax or exact version of a Python version
          architecture: 'x64' # Optional - x64 or x86, defaults to x64
      - name: installation of dependencies
        run: |
          if [ -f scripts/requirements.txt ]; then pip install -r scripts/requirements.txt; fi
          python -m spacy download en_core_web_sm
          python -m textblob.download_corpora

      - name: Generate Report
        run:  python3 scripts/main.py

      - name: Commit files
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git add *.json
          git add data/ytube
          git commit -m "added json files"
      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

      - uses: actions/upload-artifact@v1
        name: Upload Report folder
        with:
          name: report
          path: data/ytube/investing
Войти в полноэкранный режим

Выйти из полноэкранного режима

Создайте файлы astro, когда данные будут успешно собраны из скрипта Python.

# Workflow to build and deploy to your GitHub Pages repo.

# Edit your project details here.
# Remember to add API_TOKEN_GITHUB in repo Settings > Secrets as well!
env:
  githubEmail: <YOUR GITHUB EMAIL ADDRESS>
  deployToRepo: <NAME OF REPO TO DEPLOY TO (E.G. <YOUR USERNAME>.github.io)>

name: Github Pages Astro CI

on:
  # Triggers the workflow on push and pull request events but only for the main branch
  push:
    branches: [main]
  pull_request:
    branches: [main]

  workflow_run:
    workflows: ["Scan YTube"]
    types:
      - completed

  # Allows you to run this workflow manually from the Actions tab.
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Install dependencies with npm
      - name: Install dependencies
        run: cd website && npm install

      # Build the project and add .nojekyll file to supress default behaviour
      - name: Build
        run: |
          cd website
          npm run build
          touch ./dist/.nojekyll
      # Push to your pages repo
      - name: Deploy 🚀
        uses: JamesIves/github-pages-deploy-action@v4.3.0
        with:
          branch: gh-pages # The branch the action should deploy to.
          folder: website/dist # The folder the action should deploy.
Войти в полноэкранный режим

Выйти из полноэкранного режима

Надеюсь, этого будет достаточно, чтобы понять, как работает общий рабочий процесс. Некоторые из вещей, которые я узнал:

  • Как использовать рабочий процесс действий github для запуска другого рабочего процесса
  • Как взаимодействовать с API данных YouTube
  • Базовый nlp со spacy не так уж полезен для этого проекта, но это хорошая отправная точка.
  • Если бы у меня было извлечение фраз, это могло бы стать довольно интересным.