Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d231707572 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
.env
|
.env
|
||||||
__pycache__/
|
__pycache__/
|
||||||
outputs/*
|
outputs/*
|
||||||
venv/
|
venv/
|
||||||
|
|
||||||
|
|||||||
20
app.py
20
app.py
@@ -5,11 +5,13 @@ from config import *
|
|||||||
|
|
||||||
# Подгрузка сервисов
|
# Подгрузка сервисов
|
||||||
from services.llm_factory import get_llm_provider
|
from services.llm_factory import get_llm_provider
|
||||||
from services.fasterWhisper import FasterWhisper
|
|
||||||
|
|
||||||
|
|
||||||
# Загрузка доп. модулей
|
# Загрузка доп. модулей
|
||||||
from handlers.gradioHandler import GradioHandlers
|
from handlers.gradioHandler import GradioHandlers
|
||||||
from handlers.fileHandlers import FileHandlers
|
from handlers.fileHandlers import FileHandlers
|
||||||
|
from services.fasterWhisper import FasterWhisper
|
||||||
from handlers.convertMdToPdf import ConvertMdToPdf
|
from handlers.convertMdToPdf import ConvertMdToPdf
|
||||||
from handlers.glueAudio import GlueAudio
|
from handlers.glueAudio import GlueAudio
|
||||||
|
|
||||||
@@ -113,20 +115,13 @@ def main():
|
|||||||
saveFileCheckbox.change(gh.updateTextbox, inputs=saveFileCheckbox, outputs=filename)
|
saveFileCheckbox.change(gh.updateTextbox, inputs=saveFileCheckbox, outputs=filename)
|
||||||
saveFileCheckbox.change(gh.updateTextbox, inputs=saveFileCheckbox, outputs=filenamePdf)
|
saveFileCheckbox.change(gh.updateTextbox, inputs=saveFileCheckbox, outputs=filenamePdf)
|
||||||
|
|
||||||
recognizeBtn.click(
|
recognizeBtn.click(gh.handleRecognizeBtn, outputs=[recognizedText], inputs=[audioFiles, fastWhisperModel, device, compute_type, beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText, gr.State(GLUED_AUDIO_FILENAME), gr.State(OUTPUT_PATH)])
|
||||||
gh.handleRecognizeBtn,
|
|
||||||
inputs=[audioFiles, fastWhisperModel, device, compute_type, beamSize,
|
|
||||||
vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2,
|
|
||||||
wordTimestamps, noSpeechThreshold, conditionOnPreviousText, gr.State(GLUED_AUDIO_FILENAME), gr.State(OUTPUT_PATH)],
|
|
||||||
outputs=[recognizedText],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Если пайплайн включен то тогда делаем автоматически
|
# Если пайплайн включен то тогда делаем автоматически
|
||||||
# автоматический пайплайн
|
# автоматический пайплайн
|
||||||
recognizedText.change(
|
recognizedText.change(
|
||||||
gh.generateByCondition,
|
gh.generateByCondition,
|
||||||
inputs=[apiKey, llmProvider, llmModel, systemPrompt, recognizedText, llmTemperature,
|
inputs=[apiKey, llmProvider, llmModel, systemPrompt, recognizedText, llmTemperature, isPipelineEnabledCheckbox, gr.State("change"), saveFileCheckbox, filename, filenamePdf, gr.State(OUTPUT_PATH)],
|
||||||
isPipelineEnabledCheckbox, gr.State("change"), saveFileCheckbox, filename, filenamePdf, gr.State(OUTPUT_PATH)],
|
|
||||||
outputs=[refinedText, refinedTextMD]
|
outputs=[refinedText, refinedTextMD]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -136,12 +131,11 @@ def main():
|
|||||||
llmProvider.change(
|
llmProvider.change(
|
||||||
gh.update_model_dropdown,
|
gh.update_model_dropdown,
|
||||||
inputs=llmProvider,
|
inputs=llmProvider,
|
||||||
outputs=[llmModel, apiKey]
|
outputs=llmModel
|
||||||
)
|
)
|
||||||
refineTextBtn.click(
|
refineTextBtn.click(
|
||||||
gh.generateByCondition,
|
gh.generateByCondition,
|
||||||
inputs=[apiKey, llmProvider, llmModel, systemPrompt, recognizedText, llmTemperature,
|
inputs=[apiKey, llmProvider, llmModel, systemPrompt, recognizedText, llmTemperature, isPipelineEnabledCheckbox, gr.State("click"), saveFileCheckbox, filename, filenamePdf, gr.State(OUTPUT_PATH)],
|
||||||
isPipelineEnabledCheckbox, gr.State("click"), saveFileCheckbox, filename, filenamePdf, gr.State(OUTPUT_PATH)],
|
|
||||||
outputs=[refinedText, refinedTextMD]
|
outputs=[refinedText, refinedTextMD]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
65
config.py
65
config.py
@@ -8,10 +8,7 @@ DEVICES = ['cpu', 'cuda']
|
|||||||
COMPUTE_TYPE = ['auto', 'int8', 'float16', 'float32']
|
COMPUTE_TYPE = ['auto', 'int8', 'float16', 'float32']
|
||||||
|
|
||||||
# Стандартный API ключ
|
# Стандартный API ключ
|
||||||
IO_API_KEY=os.getenv('IO_API_KEY')
|
DEFAULT_API_KEY=os.getenv('API_KEY')
|
||||||
GEMINI_API_KEY=os.getenv('GEMINI_API_KEY')
|
|
||||||
DEFAULT_API_KEY=IO_API_KEY
|
|
||||||
|
|
||||||
|
|
||||||
# Словарь провайдеров и их моделей
|
# Словарь провайдеров и их моделей
|
||||||
LLM_PROVIDERS = ['io.net', 'Gemini', 'gpt4free']
|
LLM_PROVIDERS = ['io.net', 'Gemini', 'gpt4free']
|
||||||
@@ -49,38 +46,42 @@ OUTPUT_PATH='outputs'
|
|||||||
|
|
||||||
GLUED_AUDIO_FILENAME='glued.mp3'
|
GLUED_AUDIO_FILENAME='glued.mp3'
|
||||||
|
|
||||||
DEFAULT_SYSTEM_PROMPT='''You are a diligent university student who has recorded a lecture as an audio file and later transcribed it into raw text.
|
DEFAULT_SYSTEM_PROMPT='''
|
||||||
Your task is to rewrite this unstructured transcript into a clear, logically organized, and detailed lecture summary (lecture notes).
|
You are a smart university student creating easy-to-understand study notes summary of lesson for a classmate who is a beginner. Your source is a raw text/audio transcript.
|
||||||
|
|
||||||
Guidelines:
|
GOAL: rewrite the information into a clear, structured summary in RUSSIAN.
|
||||||
1. Structure:
|
|
||||||
- Organize the text into a hierarchy of sections and subsections.
|
|
||||||
- Use headings, bullet points, or numbering where appropriate.
|
|
||||||
- Present the material in a logical flow (from introduction → main points → details → examples → conclusion).
|
|
||||||
|
|
||||||
2. Clarity & Cohesion:
|
KEY RULES FOR CONTENT:
|
||||||
- Remove filler words, repetitions, and irrelevant fragments.
|
1. **Logical Structure:** Use Markdown headers (#, ##), bullet points, and short paragraphs.
|
||||||
- Rewrite incomplete sentences into full, grammatically correct sentences.
|
2. **No "Water":** Remove filler words. Keep only practical information.
|
||||||
- Ensure smooth transitions between topics, making the summary feel continuous and well-connected.
|
3. **Student Tone:** Write naturally, as if sharing notes with a friend. Avoid robotic phrases like "It is important to note".
|
||||||
|
|
||||||
3. Depth & Detail:
|
KEY RULES FOR LATEX (CRITICAL FOR PYLATEXENC):
|
||||||
- Capture all important concepts, definitions, examples, and explanations from the lecture.
|
1. **Math Mode:** ANY variable (like t, L, C), number in a formula, or equation MUST be wrapped in dollar signs `$`.
|
||||||
- Expand shorthand or fragmented thoughts into full, precise explanations.
|
* BAD: i(t) = i_pr + i_sv
|
||||||
- Where appropriate, rephrase or clarify confusing passages for better understanding.
|
* GOOD: $i(t) = i_{pr} + i_{sv}$
|
||||||
|
2. **Subscripts:** Always use curly braces `{}` for subscripts longer than one character.
|
||||||
|
* BAD: $i_pr$
|
||||||
|
* GOOD: $i_{pr}$ (or $i_{пр}$ if using cyrillic)
|
||||||
|
3. **Symbols:** Use standard LaTeX commands for symbols.
|
||||||
|
* Arrow: use `\to` (e.g., $t \to \infty$).
|
||||||
|
* Infinity: use `\infty`.
|
||||||
|
* Multiplication: use `\cdot` or just space.
|
||||||
|
4. **Consistency:** Never leave a mathematical symbol as plain text. If you mention "current i", write "ток $i$".
|
||||||
|
|
||||||
4. Accuracy:
|
EXAMPLE OF DESIRED OUTPUT FORMAT:
|
||||||
- Preserve the lecturer’s original meaning, intent, and terminology.
|
# Тема лекции
|
||||||
- Avoid adding personal opinions or new information that was not in the lecture.
|
## Основные понятия
|
||||||
|
* **Переходный процесс** — это когда цепь перестраивается с одного режима на другой (например, щелкнули выключателем).
|
||||||
|
* Математически это описывается дифференциальными уравнениями. Порядок уравнения = количеству реактивных элементов ($L$ и $C$).
|
||||||
|
|
||||||
5. Style:
|
## Классический метод
|
||||||
- Write in a formal, academic tone suitable for study notes.
|
Решение ищется в виде суммы двух частей:
|
||||||
- Aim for readability: concise sentences, but thorough coverage of concepts.
|
$$i(t) = i_{pr} + i_{sv}$$
|
||||||
- Use emphasis (e.g., bold or italic text) only when it improves comprehension.
|
|
||||||
|
|
||||||
Final Output: A cohesive, detailed, and well-structured lecture summary, suitable for later studying and revision.
|
1. **Принужденная составляющая** ($i_{pr}$) — это режим, который установится в будущем, когда все успокоится ($t \to \infty$).
|
||||||
Use only russian language!
|
2. **Свободная составляющая** ($i_{sv}$) — это то, что происходит "само по себе" из-за энергии, запасенной в $L$ и $C$.
|
||||||
USE LATEX IN DOLLAR SIGN ($)!
|
|
||||||
EXTRA BIG LENTH OF CONSPECT!
|
***
|
||||||
MAKE AS LONG AS POSIBLE AND AS BE GOOD!
|
STRICTLY FOLLOW THESE FORMATTING RULES. OUTPUT IN RUSSIAN.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +1,11 @@
|
|||||||
import subprocess
|
from pydub import AudioSegment
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
class GlueAudio():
|
class GlueAudio():
|
||||||
def glue(self, audio_files: list, output_path: str, output_filename: str) -> Path:
|
def glue(self, audioFiles):
|
||||||
"""
|
glued = AudioSegment.empty()
|
||||||
Склеивает аудиофайлы с помощью FFmpeg, используя промежуточный список файлов.
|
|
||||||
Этот метод чрезвычайно эффективен по памяти и скорости.
|
|
||||||
|
|
||||||
Args:
|
for audioFile in audioFiles:
|
||||||
audio_files (list): Список путей к исходным аудиофайлам.
|
audio = AudioSegment.from_file(audioFile)
|
||||||
output_path (str): Директория для сохранения итогового файла.
|
glued += audio
|
||||||
output_filename (str): Имя итогового склеенного файла.
|
|
||||||
|
|
||||||
Returns:
|
return glued
|
||||||
Path: Путь к созданному склеенному файлу.
|
|
||||||
"""
|
|
||||||
output_dir = Path(output_path)
|
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
final_audio_path = output_dir / output_filename
|
|
||||||
|
|
||||||
if not audio_files:
|
|
||||||
raise ValueError("Список аудиофайлов для склейки пуст.")
|
|
||||||
|
|
||||||
# 1. Формируем часть команды с входными файлами (-i file1 -i file2 ...)
|
|
||||||
input_args = []
|
|
||||||
for file_path in audio_files:
|
|
||||||
input_args.extend(['-i', str(Path(file_path).resolve())])
|
|
||||||
|
|
||||||
# 2. Формируем строку для filter_complex
|
|
||||||
num_files = len(audio_files)
|
|
||||||
stream_specifiers = "".join([f"[{i}:a]" for i in range(num_files)])
|
|
||||||
filter_complex_str = f"{stream_specifiers}concat=n={num_files}:v=0:a=1[outa]"
|
|
||||||
|
|
||||||
# 3. Собираем полную команду
|
|
||||||
command = [
|
|
||||||
'ffmpeg',
|
|
||||||
*input_args, # Распаковываем список входных файлов
|
|
||||||
'-filter_complex', filter_complex_str,
|
|
||||||
'-map', '[outa]',
|
|
||||||
'-c:a', 'libmp3lame',
|
|
||||||
'-q:a', '2',
|
|
||||||
str(final_audio_path),
|
|
||||||
'-y'
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 4. Выполняем команду
|
|
||||||
print(f"Выполнение команды FFmpeg: {' '.join(command)}")
|
|
||||||
subprocess.run(command, check=True, capture_output=True, text=True)
|
|
||||||
print("FFmpeg успешно завершил склейку.")
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise FileNotFoundError("FFmpeg не найден. Убедитесь, что он установлен и доступен в системной переменной PATH.")
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print("Ошибка при выполнении FFmpeg!")
|
|
||||||
print("Stderr:", e.stderr)
|
|
||||||
raise RuntimeError(f"Ошибка FFmpeg при склейке файлов: {e.stderr}")
|
|
||||||
|
|
||||||
return final_audio_path
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from config import LLM_MODELS # Импортируем словарь моделей
|
from config import LLM_MODELS # Импортируем словарь моделей
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
from config import GEMINI_API_KEY, IO_API_KEY
|
|
||||||
|
|
||||||
class GradioHandlers:
|
class GradioHandlers:
|
||||||
def __init__(self, llm_factory, ConvertMdToPdf, FileHandlers, FasterWhisper, GlueAudio):
|
def __init__(self, llm_factory, ConvertMdToPdf, FileHandlers, FasterWhisper, GlueAudio):
|
||||||
@@ -9,39 +9,23 @@ class GradioHandlers:
|
|||||||
self.ga = GlueAudio()
|
self.ga = GlueAudio()
|
||||||
self.ConvertMdToPdf = ConvertMdToPdf()
|
self.ConvertMdToPdf = ConvertMdToPdf()
|
||||||
self.FasterWhisper = FasterWhisper()
|
self.FasterWhisper = FasterWhisper()
|
||||||
self.llm_factory = llm_factory
|
self.llm_factory = llm_factory # Сохраняем фабрику
|
||||||
|
|
||||||
def handleRecognizeBtn(
|
def handleRecognizeBtn(self, audioFiles, model, device, compute_type, beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText, filename, outPath):
|
||||||
self, audioFiles, model, device, compute_type, beamSize, vadFilter,
|
audioFile = self.ga.glue(audioFiles)
|
||||||
minSilenceDurationMs, speechPadMs, temp0, temp1, temp2,
|
file = self.fh.saveFile(filename, audioFile, outPath)
|
||||||
wordTimestamps, noSpeechThreshold, conditionOnPreviousText, filename, outPath
|
|
||||||
):
|
|
||||||
try:
|
|
||||||
glued_audio_path = self.ga.glue(
|
|
||||||
audio_files=[f.name for f in audioFiles], # Передаем список путей
|
|
||||||
output_path=outPath,
|
|
||||||
output_filename=filename
|
|
||||||
)
|
|
||||||
except (FileNotFoundError, RuntimeError) as e:
|
|
||||||
# Если FFmpeg не найден или произошла ошибка, сообщаем пользователю
|
|
||||||
gr.Warning(str(e))
|
|
||||||
return "" # Возвращаем пустую строку в текстовое поле
|
|
||||||
|
|
||||||
# Передаем путь к склеенному файлу в FasterWhisper
|
return self.FasterWhisper.recognize(model, device, compute_type, file, beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText)
|
||||||
return self.FasterWhisper.recognize(model, device, compute_type, str(glued_audio_path), beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText)
|
|
||||||
|
|
||||||
# Функция улучшения текста
|
# Функция улучшения текста
|
||||||
def generateByCondition(self, api_key, llm_provider,
|
def generateByCondition(self, api_key, llm_provider, llm_model, system_prompt, recognized_text, llm_temperature, is_pipeline_enabled, trigger, isSaveFile, filename, filenamePdf, output_path):
|
||||||
llm_model, system_prompt, recognized_text,
|
|
||||||
llm_temperature, is_pipeline_enabled, trigger,
|
|
||||||
isSaveFile, filename, filenamePdf, output_path):
|
|
||||||
try:
|
try:
|
||||||
# Получаем нужный провайдер через фабрику
|
# Получаем нужный провайдер через фабрику
|
||||||
provider = self.llm_factory(llm_provider, api_key)
|
provider = self.llm_factory(llm_provider, api_key)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
# Если API ключ не предоставлен для нужного провайдера, выводим ошибку
|
# Если API ключ не предоставлен для нужного провайдера, выводим ошибку
|
||||||
gr.Warning(str(e))
|
self.gr.Warning(str(e))
|
||||||
return gr.skip(), gr.skip()
|
return self.gr.skip(), self.gr.skip()
|
||||||
|
|
||||||
def process():
|
def process():
|
||||||
result, md = provider.generate(llm_model, system_prompt, recognized_text, llm_temperature)
|
result, md = provider.generate(llm_model, system_prompt, recognized_text, llm_temperature)
|
||||||
@@ -69,9 +53,7 @@ class GradioHandlers:
|
|||||||
default_value = models[0] if models else None
|
default_value = models[0] if models else None
|
||||||
|
|
||||||
# Возвращаем обновленный компонент. Используем 'gr' напрямую.
|
# Возвращаем обновленный компонент. Используем 'gr' напрямую.
|
||||||
if provider == 'io.net': return gr.update(choices=models, value=default_value), gr.update(label='API key (required for io.net, Gemini)', value=IO_API_KEY, interactive=True)
|
return gr.update(choices=models, value=default_value)
|
||||||
if provider == 'Gemini': return gr.update(choices=models, value=default_value), gr.update(label='API key (required for Oio.net, Gemini)', value=GEMINI_API_KEY, interactive=True)
|
|
||||||
if provider == 'gpt4free': return gr.update(choices=models, value=default_value), gr.update(label='API key (required for Oio.net, Gemini)', value="", interactive=True)
|
|
||||||
|
|
||||||
# Функция для динамического обновления кнопки
|
# Функция для динамического обновления кнопки
|
||||||
def updateButton(self, isChecked):
|
def updateButton(self, isChecked):
|
||||||
|
|||||||
115
requirements.txt
115
requirements.txt
@@ -100,118 +100,3 @@ uvicorn==0.35.0
|
|||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
websockets==15.0.1
|
websockets==15.0.1
|
||||||
zopfli==0.2.3.post1
|
zopfli==0.2.3.post1
|
||||||
aiofiles==24.1.0
|
|
||||||
aiohappyeyeballs==2.6.1
|
|
||||||
aiohttp==3.13.0
|
|
||||||
aiosignal==1.4.0
|
|
||||||
annotated-types==0.7.0
|
|
||||||
anyio==4.10.0
|
|
||||||
attrs==25.4.0
|
|
||||||
audioop-lts==0.2.2
|
|
||||||
av==15.1.0
|
|
||||||
beautifulsoup4==4.13.5
|
|
||||||
Brotli==1.1.0
|
|
||||||
bs4==0.0.2
|
|
||||||
certifi==2025.8.3
|
|
||||||
cffi==2.0.0
|
|
||||||
charset-normalizer==3.4.3
|
|
||||||
click==8.2.1
|
|
||||||
coloredlogs==15.0.1
|
|
||||||
colour==0.1.5
|
|
||||||
cssselect2==0.8.0
|
|
||||||
ctranslate2==4.6.0
|
|
||||||
distro==1.9.0
|
|
||||||
dotenv==0.9.9
|
|
||||||
exceptiongroup==1.3.0
|
|
||||||
fastapi==0.116.1
|
|
||||||
faster-whisper==1.2.0
|
|
||||||
ffmpeg-python==0.2.0
|
|
||||||
ffmpy==0.6.1
|
|
||||||
filelock==3.19.1
|
|
||||||
flatbuffers==25.2.10
|
|
||||||
flatlatex==0.15
|
|
||||||
fonttools==4.59.2
|
|
||||||
frozenlist==1.8.0
|
|
||||||
fsspec==2025.9.0
|
|
||||||
future==1.0.0
|
|
||||||
g4f==0.6.3.5
|
|
||||||
gradio==5.44.1
|
|
||||||
gradio_client==1.12.1
|
|
||||||
groovy==0.1.2
|
|
||||||
h11==0.16.0
|
|
||||||
hf-xet==1.1.9
|
|
||||||
httpcore==1.0.9
|
|
||||||
httpx==0.28.1
|
|
||||||
huggingface-hub==0.34.4
|
|
||||||
humanfriendly==10.0
|
|
||||||
idna==3.10
|
|
||||||
iso639-lang==2.6.3
|
|
||||||
Jinja2==3.1.6
|
|
||||||
jiter==0.10.0
|
|
||||||
joblib==1.5.2
|
|
||||||
langdetect==1.0.9
|
|
||||||
littleutils==0.2.4
|
|
||||||
markdown-it-py==3.0.0
|
|
||||||
markdown_pdf==1.9
|
|
||||||
MarkupSafe==3.0.2
|
|
||||||
mdurl==0.1.2
|
|
||||||
mpmath==1.3.0
|
|
||||||
multidict==6.7.0
|
|
||||||
nest-asyncio==1.6.0
|
|
||||||
nltk==3.9.1
|
|
||||||
numpy==2.2.6
|
|
||||||
onnxruntime==1.22.1
|
|
||||||
openai==1.106.1
|
|
||||||
orjson==3.11.3
|
|
||||||
outdated==0.2.2
|
|
||||||
packaging==25.0
|
|
||||||
pandas==2.3.2
|
|
||||||
pillow==11.3.0
|
|
||||||
propcache==0.4.0
|
|
||||||
protobuf==6.32.0
|
|
||||||
pycparser==2.22
|
|
||||||
pycryptodome==3.23.0
|
|
||||||
pydantic==2.11.7
|
|
||||||
pydantic_core==2.33.2
|
|
||||||
pydub==0.25.1
|
|
||||||
pydyf==0.11.0
|
|
||||||
Pygments==2.19.2
|
|
||||||
pylatexenc==2.10
|
|
||||||
pymultidictionary==1.3.2
|
|
||||||
PyMuPDF==1.26.4
|
|
||||||
pyperclip==1.9.0
|
|
||||||
pyphen==0.17.2
|
|
||||||
python-dateutil==2.9.0.post0
|
|
||||||
python-dotenv==1.1.1
|
|
||||||
python-multipart==0.0.20
|
|
||||||
pytz==2025.2
|
|
||||||
PyYAML==6.0.2
|
|
||||||
regex==2025.9.1
|
|
||||||
requests==2.32.5
|
|
||||||
rich==14.1.0
|
|
||||||
ruff==0.12.12
|
|
||||||
safehttpx==0.1.6
|
|
||||||
semantic-version==2.10.0
|
|
||||||
setuptools==80.9.0
|
|
||||||
shellingham==1.5.4
|
|
||||||
six==1.17.0
|
|
||||||
sniffio==1.3.1
|
|
||||||
soupsieve==2.8
|
|
||||||
starlette==0.47.3
|
|
||||||
sympy==1.14.0
|
|
||||||
tinycss2==1.4.0
|
|
||||||
tinyhtml5==2.0.0
|
|
||||||
tkmacosx==1.0.5
|
|
||||||
tokenizers==0.22.0
|
|
||||||
tomlkit==0.13.3
|
|
||||||
tqdm==4.67.1
|
|
||||||
typer==0.17.4
|
|
||||||
typing-inspection==0.4.1
|
|
||||||
typing_extensions==4.15.0
|
|
||||||
tzdata==2025.2
|
|
||||||
urllib3==2.5.0
|
|
||||||
uvicorn==0.35.0
|
|
||||||
webencodings==0.5.1
|
|
||||||
websockets==15.0.1
|
|
||||||
yarl==1.22.0
|
|
||||||
zopfli==0.2.3.post1
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
from faster_whisper import WhisperModel
|
from faster_whisper import WhisperModel
|
||||||
|
|
||||||
class FasterWhisper:
|
class FasterWhisper:
|
||||||
def recognize(self, model, device, compute_type,
|
def recognize(self, model, device, compute_type, audioFile, beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText):
|
||||||
audioFile, beamSize, vadFilter,
|
|
||||||
minSilenceDurationMs, speechPadMs,
|
|
||||||
temp0, temp1, temp2, wordTimestamps,
|
|
||||||
noSpeechThreshold, conditionOnPreviousText):
|
|
||||||
model = WhisperModel(model, device=device, compute_type=compute_type) # Задаем модель
|
model = WhisperModel(model, device=device, compute_type=compute_type) # Задаем модель
|
||||||
|
|
||||||
segments, _ = model.transcribe( # Распознаем текст
|
segments, _ = model.transcribe( # Распознаем текст
|
||||||
@@ -26,7 +22,6 @@ class FasterWhisper:
|
|||||||
|
|
||||||
for seg in segments:
|
for seg in segments:
|
||||||
text += f"[{self.format_timestamp(seg.start)} -> {self.format_timestamp(seg.end)}] {seg.text}" + '\n'
|
text += f"[{self.format_timestamp(seg.start)} -> {self.format_timestamp(seg.end)}] {seg.text}" + '\n'
|
||||||
print(f"[{self.format_timestamp(seg.start)} -> {self.format_timestamp(seg.end)}] {seg.text}")
|
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|||||||
19
test.py
19
test.py
@@ -1,19 +0,0 @@
|
|||||||
from handlers.convertMdToPdf import ConvertMdToPdf
|
|
||||||
import re
|
|
||||||
# Создаем экземпляр класса
|
|
||||||
converter = ConvertMdToPdf()
|
|
||||||
|
|
||||||
# Тестовые примеры дробей
|
|
||||||
test_cases = [
|
|
||||||
r"$\frac{1}{2}$", # простая дробь
|
|
||||||
r"$\dfrac{3}{4}$", # дробь с displaystyle
|
|
||||||
r"$\frac{a}{b} + \frac{c}{d}$", # сложение дробей
|
|
||||||
r"$$\frac{x^2}{y^3}$$", # блочная дробь
|
|
||||||
r"$\frac{\partial f}{\partial x}$" # частная производная
|
|
||||||
]
|
|
||||||
|
|
||||||
for latex in test_cases:
|
|
||||||
result = converter.replace_math(re.search(r'\$\$(.*?)\$\$|\$(.*?)\$', latex))
|
|
||||||
print(f"Input: {latex}")
|
|
||||||
print(f"Output: {result}")
|
|
||||||
print("---")
|
|
||||||
Reference in New Issue
Block a user