홈으로 돌아가기

Claude 음성 입력 러시아어 오프라인

Whisper, Flask 서버 및 Chrome 확장을 사용한 Claude.ai용 러시아어 로컬 음성 입력 시스템 생성 지침. 메뉴바 앱이 서비스를 관리하며, 모든 것이 제한 없이 오프라인으로 작동. 전체 코드와 일반 오류 해결책.

Claude 오프라인 음성: Whisper + rumps + Chrome
Advertisement 728x90

Claude 음성 입력: 러시아어 오프라인 구현, 저녁에 완성

localhost:5555에서 실행되는 Flask 서버가 Chrome 확장 프로그램에서 오디오를 받아 Whisper(소형 모델)로 로컬에서 음성을 텍스트로 변환한 후 Claude.ai 입력 필드에 전송합니다. rumps로 만든 메뉴바 앱이 시작/중지를 담당하며, 메뉴 아이콘이 🤖에서 🎤로 바뀝니다. 모든 게 완전 오프라인으로 동작하며 제한 없고 완전 무료입니다. macOS에서 작동하며 Linux로 쉽게 이식 가능합니다.

사전 준비

필요 패키지 설치:

  • Whisper: brew install openai-whisper
  • ffmpeg: brew install ffmpeg
  • Python 3와 Chrome

Whisper 테스트:

Google AdInline article slot
whisper --version

출력에 러시아어가 보이는지 확인하세요. 프로젝트 구조 설정:

mkdir -p ~/projects/whisper-claude
cd ~/projects/whisper-claude
python3 -m venv venv
source venv/bin/activate
pip install flask flask-cors rumps
mkdir -p extension/icons

macOS Ventura 이상에서는 시스템 Python 충돌을 피하기 위해 가상환경이 필수입니다.

음성 인식 서버 (server.py)

서버는 POST /transcribe로 base64 또는 파일 오디오를 처리하며, Apple Silicon에 최적화된 --language ru --fp16 False 옵션으로 Whisper를 호출해 JSON 텍스트를 반환합니다. /ping과 /shutdown 엔드포인트도 포함됩니다.

Google AdInline article slot
from flask import Flask, request, jsonify
from flask_cors import CORS
import subprocess
import tempfile
import os
import threading

app = Flask(__name__)
CORS(app)

WHISPER_PATH = "/opt/homebrew/bin/whisper"
WHISPER_MODEL = "small"
PORT = 5555

@app.route("/ping", methods=["GET"])
def ping():
    return jsonify({"status": "ok"})

@app.route("/transcribe", methods=["POST"])
def transcribe():
    if "audio" not in request.files:
        return jsonify({"error": "No audio file found"}), 400

    audio_file = request.files["audio"]

    with tempfile.NamedTemporaryFile(suffix=".webm", delete=False) as tmp:
        tmp_path = tmp.name
        audio_file.save(tmp_path)

    try:
        result = subprocess.run(
            [
                WHISPER_PATH, tmp_path,
                "--model", WHISPER_MODEL,
                "--language", "ru",
                "--output_format", "txt",
                "--output_dir", tempfile.gettempdir(),
                "--fp16", "False",
            ],
            capture_output=True, text=True, timeout=60
        )

        txt_path = tmp_path.replace(".webm", ".txt")
        if os.path.exists(txt_path):
            with open(txt_path, "r", encoding="utf-8") as f:
                text = f.read().strip()
            os.unlink(txt_path)
        else:
            text = result.stdout.strip()

        return jsonify({"text": text})

    except subprocess.TimeoutExpired:
        return jsonify({"error": "Timeout"}), 500
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        os.unlink(tmp_path)

@app.route("/shutdown", methods=["POST"])
def shutdown():
    threading.Timer(0.5, lambda: os._exit(0)).start()
    return jsonify({"status": "shutting down"})

if __name__ == "__main__":
    print(f"[Whisper] Starting on port {PORT}, model: {WHISPER_MODEL}")
    app.run(host="127.0.0.1", port=PORT, debug=False)

핵심 팁: M1/M2/M3 칩에서 충돌을 막기 위해 --fp16 False가 필수입니다.

메뉴바 컨트롤러 (menubar.py)

앱은 rumps.Timer로 5초마다 포트 상태를 확인하며, 스레드에서 서버 시작/중지를 처리합니다. TOOLS 설정으로 한 줄만 추가하면 새 서비스를 확장할 수 있습니다. 상태는 이모지로 표시: ✅ 실행 중, ⏸ 일시 중지.

import rumps
import subprocess
import threading
import os
import time
import urllib.request

BASE_DIR = "~/projects/whisper-claude"
VENV_PYTHON = os.path.join(BASE_DIR, "venv/bin/python3")

TOOLS = [
    {
        "name": "Whisper → Claude",
        "script": os.path.join(BASE_DIR, "server.py"),
        "port": 5555,
        "description": "러시아어 음성 입력",
    },
]

# ... (원본 코드 나머지 부분 생략)

class AILauncher(rumps.App):
    # 위 구현 참조
    pass

if __name__ == "__main__":
    AILauncher().run()

전체 코드는 ToolController에 토글, 전체 확인, 정상 종료 기능을 포함합니다.

Google AdInline article slot

Chrome 확장 프로그램

manifest.json (MV3):

{
  "manifest_version": 3,
  "name": "Whisper for Claude",
  "version": "1.0",
  "permissions": ["activeTab", "scripting"],
  "host_permissions": [
    "https://claude.ai/*",
    "http://127.0.0.1:5555/*"
  ],
  "content_scripts": [
    {
      "matches": ["https://claude.ai/*"],
      "js": ["content.js"],
      "run_at": "document_end"
    }
  ],
  "background": {
    "service_worker": "background.js"
  }
}

background.js는 혼합 콘텐츠를 처리: content.js의 base64 오디오 → 백그라운드 fetch → 서버.

const SERVER_URL = "http://127.0.0.1:5555";

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === "transcribe") {
    handleTranscribe(message.audio).then(sendResponse);
    return true;
  }
});

async function handleTranscribe(base64Audio) {
  // base64 to Blob to FormData to POST /transcribe
}

content.js는 입력 필드 옆에 🎤 버튼을 추가하고 MediaRecorder로 오디오를 캡처합니다.

주요 특징

  • 로컬 Whisper 소형 모델: ~1GB, 러시아어 오프라인 변환 10-30초.
  • 확장성 있는 구조: TOOLS에 코드 변경 없이 새 AI 도구 추가.
  • 보안: localhost 전용, 클라우드 호출 없음, Chrome용 CORS.
  • 호환성: macOS Apple Silicon (fp16=False), 경로 조정으로 Linux.
  • 성능: 60초 타임아웃, 자동 임시 파일 정리.

— Editorial Team

Advertisement 728x90

다음 읽기