diff --git "a/\\" "b/\\" new file mode 100644 index 0000000..7809987 --- /dev/null +++ "b/\\" @@ -0,0 +1,24 @@ +import re +from pylatexenc.latex2text import LatexNodes2Text + +class ConvertMdToPdf: + # Конвертирует md в pdf + def convertLatexToText(self, text:str): + # Обрабатываем только математические выражения + text = re.sub( + r'\$\$(.*?)\$\$|\$(.*?)\$', + self.replace_math, + text, + flags=re.DOTALL + ) + return text + + def replace_math(self, match): + math_content = match.group(1) or match.group(2) # $$...$$ или $...$ + try: + # Преобразуем только математическое выражение + converted = LatexNodes2Text().latex_to_text(math_content) + return converted + except: + return math_content # В случае ошибки оставляем как есть + diff --git a/app.py b/app.py index 33e6e78..18c6d70 100644 --- a/app.py +++ b/app.py @@ -1,9 +1,11 @@ import gradio as gr + from pathlib import Path # Подгрузка сервисов from services.llm import Llm from services.fasterWhisper import FasterWhisper +from services.convertMdToPdf import ConvertMdToPdf # Загрузка параметров конфигурации from config import * @@ -16,31 +18,39 @@ def generateByCondition(api_key, llm_model, system_prompt, recognized_text, llm_ if is_pipeline_enabled and trigger == "change": result, md = llm.generate(llm_model, system_prompt, recognized_text, llm_temperature) + # Конвертируем текст с латексом в юникод + unicodeText = ConvertMdToPdf().convertLatexToText(md) + if isSaveFile: saveFile("output.txt", result) - return result, result + return result, unicodeText # если чекбокс выключен и событие было click → обрабатываем if not is_pipeline_enabled and trigger == "click": result, md = llm.generate(llm_model, system_prompt, recognized_text, llm_temperature) + # Конвертируем текст с латексом в юникод + unicodeText = ConvertMdToPdf().convertLatexToText(md) + if isSaveFile: saveFile("output.txt", result) - return result, md + return result, unicodeText # если нет чекбокса и было событие change return gr.skip(), gr.skip() -# Функция сохранения файла +# Функция сохранеhния файла def saveFile(filename, text): directory = Path(OUTPUT_PATH) filePath = directory / filename filePath.parent.mkdir(parents=True, exist_ok=True) filePath.write_text(text, encoding='utf-8') +# ConvertMdToPdf().convert(text) + # Функция для динамического обновления кнопки в зависимости от состояния checkbox def updateButton(isChecked): if not isChecked: @@ -80,8 +90,10 @@ with gr.Blocks() as demo: with gr.Column(): with gr.Accordion(label='Settings'): # Первое поле на всю ширину в акордионе настроек - saveFileCheckbox = gr.Checkbox(label='save file', value=True, interactive=True) - filename = gr.Textbox(label='Output filename', value='output.txt', interactive=True) + with gr.Group(): + saveFileCheckbox = gr.Checkbox(label='save file', value=True, interactive=True) + filename = gr.Textbox(label='Output filename', value='output.txt', interactive=True) + # Акордион настроек faster whisper with gr.Accordion(label='Faster whisper settings'): diff --git a/config.py b/config.py index f51795d..2e18146 100644 --- a/config.py +++ b/config.py @@ -44,5 +44,6 @@ Guidelines: Final Output: A cohesive, detailed, and well-structured lecture summary, suitable for later studying and revision. Use only russian language! +USE LATEX IN DOLLAR SIGN ($)! ''' diff --git a/file.pdf b/file.pdf new file mode 100644 index 0000000..d49a762 Binary files /dev/null and b/file.pdf differ diff --git a/output.pdf b/output.pdf new file mode 100644 index 0000000..10a12b7 Binary files /dev/null and b/output.pdf differ diff --git a/requirements.txt b/requirements.txt index c028379..84affa3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,9 +4,11 @@ anyio==4.10.0 av==15.1.0 Brotli==1.1.0 certifi==2025.8.3 +cffi==2.0.0 charset-normalizer==3.4.3 click==8.2.1 coloredlogs==15.0.1 +cssselect2==0.8.0 ctranslate2==4.6.0 distro==1.9.0 dotenv==0.9.9 @@ -17,7 +19,9 @@ ffmpeg-python==0.2.0 ffmpy==0.6.1 filelock==3.19.1 flatbuffers==25.2.10 +fonttools==4.59.2 fsspec==2025.9.0 +future==1.0.0 gradio==5.44.1 gradio_client==1.12.1 groovy==0.1.2 @@ -30,7 +34,8 @@ humanfriendly==10.0 idna==3.10 Jinja2==3.1.6 jiter==0.10.0 -markdown-it-py==4.0.0 +markdown-it-py==3.0.0 +markdown2==2.5.4 MarkupSafe==3.0.2 mdurl==0.1.2 mpmath==1.3.0 @@ -42,10 +47,14 @@ packaging==25.0 pandas==2.3.2 pillow==11.3.0 protobuf==6.32.0 +pycparser==2.22 pydantic==2.11.7 pydantic_core==2.33.2 pydub==0.25.1 +pydyf==0.11.0 Pygments==2.19.2 +PyMuPDF==1.26.4 +pyphen==0.17.2 python-dateutil==2.9.0.post0 python-dotenv==1.1.1 python-multipart==0.0.20 @@ -61,6 +70,8 @@ six==1.17.0 sniffio==1.3.1 starlette==0.47.3 sympy==1.14.0 +tinycss2==1.4.0 +tinyhtml5==2.0.0 tokenizers==0.22.0 tomlkit==0.13.3 tqdm==4.67.1 @@ -70,4 +81,7 @@ typing_extensions==4.15.0 tzdata==2025.2 urllib3==2.5.0 uvicorn==0.35.0 +weasyprint==66.0 +webencodings==0.5.1 websockets==15.0.1 +zopfli==0.2.3.post1 diff --git a/services/convertMdToPdf.py b/services/convertMdToPdf.py new file mode 100644 index 0000000..7809987 --- /dev/null +++ b/services/convertMdToPdf.py @@ -0,0 +1,24 @@ +import re +from pylatexenc.latex2text import LatexNodes2Text + +class ConvertMdToPdf: + # Конвертирует md в pdf + def convertLatexToText(self, text:str): + # Обрабатываем только математические выражения + text = re.sub( + r'\$\$(.*?)\$\$|\$(.*?)\$', + self.replace_math, + text, + flags=re.DOTALL + ) + return text + + def replace_math(self, match): + math_content = match.group(1) or match.group(2) # $$...$$ или $...$ + try: + # Преобразуем только математическое выражение + converted = LatexNodes2Text().latex_to_text(math_content) + return converted + except: + return math_content # В случае ошибки оставляем как есть + diff --git a/services/fasterWhisper.py b/services/fasterWhisper.py index ddcf22e..8ac1e48 100644 --- a/services/fasterWhisper.py +++ b/services/fasterWhisper.py @@ -2,7 +2,7 @@ from faster_whisper import WhisperModel class FasterWhisper: def recognize(self, model, audioFile, beamSize, vadFilter, minSilenceDurationMs, speechPadMs, temp0, temp1, temp2, wordTimestamps, noSpeechThreshold, conditionOnPreviousText): - model = WhisperModel(model, device='cuda', compute_type='float16') # Задаем модель + model = WhisperModel(model, device='auto', compute_type='auto') # Задаем модель segments, _ = model.transcribe( # Распознаем текст audioFile, @@ -32,5 +32,3 @@ class FasterWhisper: seconds_int = (millis % (60 * 1000)) // 1000 millis = millis % 1000 return f"{hours:02d}:{minutes:02d}:{seconds_int:02d},{millis:03d}" - -