Редактировать file_service.py
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
хирургическая замена в DOCX, создание DOCX из текста,
|
||||
транскрипция аудио через SaluteSpeech.
|
||||
Все методы, которые могут быть асинхронными, теперь async.
|
||||
Добавлено экранирование путей через shlex.quote.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -13,6 +14,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
import zipfile
|
||||
@@ -81,8 +83,6 @@ class FileService:
|
||||
# ---------- Синхронные методы извлечения (вызываются через to_thread) ----------
|
||||
def extract_text_from_docx(self, file_path: str) -> str:
|
||||
"""Извлекает текст из DOCX, включая колонтитулы, таблицы и сноски."""
|
||||
# ... (код без изменений, полная версия была ранее)
|
||||
# Я приведу полный код этого метода, чтобы сохранить целостность.
|
||||
try:
|
||||
doc = DocxReader(file_path)
|
||||
full_text = []
|
||||
@@ -235,6 +235,7 @@ class FileService:
|
||||
"""
|
||||
Асинхронно транскрибирует аудиофайл через SaluteSpeech API.
|
||||
Все блокирующие вызовы (subprocess.run, requests.post) обёрнуты в asyncio.to_thread.
|
||||
Пути экранируются через shlex.quote.
|
||||
"""
|
||||
import uuid
|
||||
|
||||
@@ -247,14 +248,17 @@ class FileService:
|
||||
if not shutil.which('ffmpeg') and not os.path.exists(ffmpeg_bin):
|
||||
return "[Ошибка: на сервере не установлен ffmpeg]"
|
||||
|
||||
# Экранируем пути
|
||||
safe_file_path = shlex.quote(file_path)
|
||||
pcm_output = file_path + ".raw"
|
||||
safe_pcm_output = shlex.quote(pcm_output)
|
||||
|
||||
try:
|
||||
# Конвертация ffmpeg
|
||||
def _run_ffmpeg():
|
||||
cmd_ffmpeg = [
|
||||
ffmpeg_bin, '-y', '-i', file_path,
|
||||
'-ac', '1', '-ar', '16000', '-f', 's16le', '-filter:a', 'volume=2.0', pcm_output
|
||||
ffmpeg_bin, '-y', '-i', safe_file_path,
|
||||
'-ac', '1', '-ar', '16000', '-f', 's16le', '-filter:a', 'volume=2.0', safe_pcm_output
|
||||
]
|
||||
return subprocess.run(cmd_ffmpeg, capture_output=True)
|
||||
|
||||
@@ -276,7 +280,7 @@ class FileService:
|
||||
'-H', f'Authorization: Bearer {token}',
|
||||
'-H', 'Content-Type: audio/x-pcm;bit=16;rate=16000',
|
||||
'-H', f'RqUID: {str(uuid.uuid4())}',
|
||||
'--data-binary', f'@{pcm_output}'
|
||||
'--data-binary', f'@{safe_pcm_output}'
|
||||
]
|
||||
return subprocess.run(curl_cmd, capture_output=True, text=True)
|
||||
|
||||
@@ -326,7 +330,6 @@ class FileService:
|
||||
try:
|
||||
def _sync_request():
|
||||
return requests.post(url, headers=headers, data=payload, verify=False)
|
||||
# ОБЁРТКА: синхронный запрос выполняется в отдельном потоке
|
||||
response = await asyncio.to_thread(_sync_request)
|
||||
token = response.json().get('access_token')
|
||||
logger.info("SaluteSpeech token получен")
|
||||
@@ -479,7 +482,7 @@ class FileService:
|
||||
return text, count
|
||||
|
||||
# ============================================================
|
||||
# ОСНОВНОЙ МЕТОД – теперь асинхронный!
|
||||
# ОСНОВНОЙ МЕТОД
|
||||
# ============================================================
|
||||
|
||||
async def process_any_file(self, file_path: str) -> Tuple[str, int]:
|
||||
|
||||
Reference in New Issue
Block a user