Add base version of run-transcribe.py
This commit is contained in:
parent
8f8e07ceae
commit
624923ef5f
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -6,4 +6,6 @@ node_modules/
|
|||
__pycache__
|
||||
|
||||
*.db
|
||||
*.db-journal
|
||||
*.db-journal
|
||||
|
||||
build/
|
||||
19
.vscode/launch.json
vendored
19
.vscode/launch.json
vendored
|
|
@ -13,8 +13,19 @@
|
|||
"FLASK_ENV": "development",
|
||||
"FLASK_DEBUG": "1"
|
||||
},
|
||||
"justMyCode": true
|
||||
"justMyCode": true,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Python: VK Transcribe",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"python": "${workspaceFolder}/env/Scripts/python.exe",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/run-transcribe.py",
|
||||
"justMyCode": true,
|
||||
"console": "integratedTerminal",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ CORS(
|
|||
# ----------------------------------------------- WebSocket Initialization ---------------------------------------------------------------
|
||||
|
||||
socketio = SocketIO(
|
||||
api, cors_allowed_origins="*") # В production настроить CORS строже
|
||||
api, cors_allowed_origins="*") # В production настроить CORS строже # , async_mode='eventlet' для компиляции в exe
|
||||
|
||||
graph_history_manager.set_socketio(socketio)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# отключаем 40-ка строчное ограничение для этого файла
|
||||
# ----------------------------------------------- Imports ------------------------------------------------------------
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
|
|
|||
|
|
@ -54,6 +54,16 @@ MODELS: Dict[str, Dict[str, Any]] = {
|
|||
"stream": True,
|
||||
"capabilities": ["vision"],
|
||||
},
|
||||
"gemini-2.5-flash-openrouter": {
|
||||
"name": "gemini-2.5-flash-openrouter",
|
||||
"provider": "openai", # Изменено на "openai"
|
||||
"model_name": "gemini-2.5-flash", # Добавлено имя модели для LangChain
|
||||
"apiBase":
|
||||
"https://openrouter.ai", # "generativelanguage.googleapis.com", # "https://render-service-gsu7.onrender.com/g/v1beta",
|
||||
"apiKey": "AIzaSyDpueKFWVqknVKlQn6TdasLmJ2lvAUiBik",
|
||||
"stream": True,
|
||||
"capabilities": ["vision"],
|
||||
},
|
||||
"gemini-2.5-flash-bh": {
|
||||
"name": "gemini-2.5-flash",
|
||||
"provider": "openai", # Изменено на "openai"
|
||||
|
|
@ -64,6 +74,26 @@ MODELS: Dict[str, Dict[str, Any]] = {
|
|||
"stream": True,
|
||||
"capabilities": ["vision"],
|
||||
},
|
||||
"gemini-3-flash-preview-bh": {
|
||||
"name": "gemini-3-flash-preview",
|
||||
"provider": "openai", # Изменено на "openai"
|
||||
"model_name": "gemini-3-flash-preview", # Добавлено имя модели для LangChain
|
||||
"apiBase": "https://bothub.chat/api/v2/openai/v1",
|
||||
"apiKey":
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ3MTMwYTk0LTJiNmMtNDgzZi04Y2NiLWM5MjgwNzlmNDFlZSIsImlzRGV2ZWxvcGVyIjp0cnVlLCJpYXQiOjE3NTQ0NzYwMDcsImV4cCI6MjA3MDA1MjAwN30._64_DXNZatdd4-4VbXp8dOXdDhIlNWMQt9A_Nn6mu3g",
|
||||
"stream": True,
|
||||
"capabilities": ["vision"],
|
||||
},
|
||||
"gemini-3.1-pro-preview-bh": {
|
||||
"name": "gemini-3.1-pro-preview",
|
||||
"provider": "openai", # Изменено на "openai"
|
||||
"model_name": "gemini-3.1-pro-preview", # Добавлено имя модели для LangChain
|
||||
"apiBase": "https://bothub.chat/api/v2/openai/v1",
|
||||
"apiKey":
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ3MTMwYTk0LTJiNmMtNDgzZi04Y2NiLWM5MjgwNzlmNDFlZSIsImlzRGV2ZWxvcGVyIjp0cnVlLCJpYXQiOjE3NTQ0NzYwMDcsImV4cCI6MjA3MDA1MjAwN30._64_DXNZatdd4-4VbXp8dOXdDhIlNWMQt9A_Nn6mu3g",
|
||||
"stream": True,
|
||||
"capabilities": ["vision"],
|
||||
},
|
||||
"claude-4.5-sonnet-bh": {
|
||||
"name": "claude-4.5-sonnet-bh",
|
||||
"provider": "openai", # Изменено на "openai"
|
||||
|
|
|
|||
BIN
geckodriver.exe
Normal file
BIN
geckodriver.exe
Normal file
Binary file not shown.
65
obfuscate.txt
Normal file
65
obfuscate.txt
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
Для создания исполняемого файла (.exe), который запускается без установки, с обфусцированным кодом Python лучше всего использовать связку PyArmor + PyInstaller:
|
||||
|
||||
1. Обфускация с PyArmor:
|
||||
- PyArmor шифрует и обфусцирует исходный Python-код, усложняя его анализ и обратную разработку.
|
||||
- Используется командой:
|
||||
```
|
||||
pyarmor gen -O dist --recursive путь/к/вашему/проекту
|
||||
```
|
||||
или
|
||||
```
|
||||
pyarmor gen -O dist --recursive .
|
||||
```
|
||||
- Это создаст обфусцированные версии скриптов с сохранением структуры.
|
||||
|
||||
2. Упаковка в exe с PyInstaller:
|
||||
- После обфускации используйте PyInstaller, чтобы упаковать проект в единый exe-файл с параметром `--onefile`:
|
||||
```
|
||||
pyinstaller --onefile --noconsole ваш_главный_скрипт.py
|
||||
```
|
||||
|
||||
? python -m PyInstaller --onefile --noconsole run.py
|
||||
? pyinstaller --onefile --noconsole --paths=./app run.py
|
||||
? pyinstaller --onefile --hidden-import=eventlet.green --hidden-import=eventlet.green.thread --hidden-import=engineio.async_eventlet --hidden-import=engineio.async_drivers.eventlet --noconsole --paths=./app run.py
|
||||
|
||||
|
||||
- Если нужно, добавляйте параметры `--add-data` для ресурсов.
|
||||
|
||||
3. Итог:
|
||||
- Итоговый .exe-файл будет содержать интерпретатор Python, все зависимости и обфусцированный код.
|
||||
- Запуск exe не требует предварительной установки Python или зависимостей.
|
||||
- Такой файл удобно выкладывать в релизы GitHub и распространять пользователям.
|
||||
|
||||
4. Важные советы:
|
||||
- Всегда тестируйте exe на чистой системе.
|
||||
- PyArmor даёт хорошую защиту, но не абсолютную.
|
||||
- Для повышения безопасности используйте активацию лицензий PyArmor (опционно).
|
||||
- Настройте spec-файл PyInstaller, чтобы включить все необходимые модули и ресурсы.
|
||||
|
||||
Пример типичного workflow:
|
||||
|
||||
```bash
|
||||
# Обфускация
|
||||
pyarmor obfuscate --recursive your_project/
|
||||
|
||||
# Переход в обфусцированную папку
|
||||
cd dist/your_project
|
||||
|
||||
# Создание exe
|
||||
pyinstaller --onefile --noconsole main.py
|
||||
```
|
||||
|
||||
Тогда в папке `dist` появится самодостаточный исполняемый файл.
|
||||
|
||||
Таким образом, PyArmor + PyInstaller позволяет создать exe с обфусцированным кодом, который не требует установки Python и готов к распространению через GitHub релизы.[1][7][9]
|
||||
|
||||
[1](https://pressanybutton.ru/post/poleznye-instrumenty/python-proektav-exe-fajl-i-obfuskaciya-koda/)
|
||||
[2](https://www.youtube.com/watch?v=15ho_Zg_Kq4)
|
||||
[3](https://www.youtube.com/watch?v=HtiYdCk0_J8)
|
||||
[4](https://www.reddit.com/r/learnpython/comments/144tdhy/obfuscating_python_script/)
|
||||
[5](https://stackoverflow.com/questions/58334936/pack-a-pyarmor-obfuscated-script-to-exe)
|
||||
[6](https://qna.habr.com/q/1055278)
|
||||
[7](https://pyarmor.readthedocs.io/en/v5.7.0/pack-obfuscated-scripts.html)
|
||||
[8](https://github.com/dashingsoft/pyarmor)
|
||||
[9](https://www.cyberforum.ru/python-ide/thread3151287.html)
|
||||
[10](https://www.reddit.com/r/learnpython/comments/1bdsnce/which_one_is_best_for_code_obfuscation/)
|
||||
|
|
@ -10,4 +10,6 @@ flask==3.1.2
|
|||
flask_cors==6.0.1
|
||||
flask_socketio
|
||||
|
||||
mistralai==1.9.10
|
||||
mistralai==1.9.10
|
||||
|
||||
selenium
|
||||
113
run-transcribe.py
Normal file
113
run-transcribe.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.firefox.service import Service
|
||||
from selenium.webdriver.firefox.options import Options
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
# --- НАСТРОЙКИ ---
|
||||
OBSIDIAN_PATH = r"D:\Work\Software_Development\Projects\ttrpg-obsidian-vault\scripts\transcrib\VK_Call_Notes.md"
|
||||
CHECK_INTERVAL = 0.5 # Частота проверки текста
|
||||
RECONNECT_INTERVAL = 6.0 # Частота поиска вкладки
|
||||
|
||||
def append_to_obsidian(text, new_line=True):
|
||||
"""
|
||||
Записывает текст.
|
||||
new_line=True: создает новую строку с таймстампом.
|
||||
new_line=False: дописывает в конец существующей строки.
|
||||
"""
|
||||
try:
|
||||
with open(OBSIDIAN_PATH, "a", encoding="utf-8") as f:
|
||||
if new_line:
|
||||
timestamp = datetime.now().strftime("\n[%H:%M:%S] ")
|
||||
f.write(f"{timestamp}{text}")
|
||||
else:
|
||||
f.write(f"{text}") # f.write(f" {text}")
|
||||
print(f"Дописано: {text}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка записи: {e}")
|
||||
|
||||
def find_vk_tab(driver):
|
||||
"""Пытается найти и переключиться на вкладку ВК."""
|
||||
try:
|
||||
for handle in driver.window_handles:
|
||||
driver.switch_to.window(handle)
|
||||
if "vk.com" in driver.current_url or "Call" in driver.title:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def run_capture():
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
driver_path = os.path.join(current_dir, "geckodriver.exe")
|
||||
|
||||
options = Options()
|
||||
options.add_argument("--debugger-address 127.0.0.1:9222")
|
||||
service = Service(executable_path=driver_path)
|
||||
|
||||
try:
|
||||
driver = webdriver.Firefox(service=service, options=options)
|
||||
print("--- Соединение с браузером установлено ---")
|
||||
except Exception as e:
|
||||
print(f"Критическая ошибка: {e}")
|
||||
return
|
||||
|
||||
last_text = ""
|
||||
active_tab_found = False
|
||||
|
||||
try:
|
||||
while True:
|
||||
# 1. Если вкладка не найдена — ищем её
|
||||
if not active_tab_found:
|
||||
if find_vk_tab(driver):
|
||||
print(f"Нашел звонок: {driver.title}. Начинаю слежку...")
|
||||
active_tab_found = True
|
||||
else:
|
||||
print("Жду открытия вкладки со звонком ВК...")
|
||||
time.sleep(RECONNECT_INTERVAL)
|
||||
continue
|
||||
|
||||
# 2. Попытка прочитать текст
|
||||
try:
|
||||
element = driver.find_element(By.CLASS_NAME, "CallsSubtitles__content")
|
||||
current_full_text = element.text.strip()
|
||||
|
||||
if current_full_text:
|
||||
# Случай 1: Это продолжение текущей фразы
|
||||
if last_full_text and current_full_text.startswith(last_full_text):
|
||||
# Берем только то, чего еще не было
|
||||
added_part = current_full_text[len(last_full_text):] #.strip()
|
||||
if added_part:
|
||||
append_to_obsidian(added_part, new_line=False)
|
||||
last_full_text = current_full_text
|
||||
|
||||
# Случай 2: Это абсолютно новая фраза (предыдущая исчезла)
|
||||
elif current_full_text != last_full_text:
|
||||
append_to_obsidian(current_full_text, new_line=True)
|
||||
last_full_text = current_full_text
|
||||
|
||||
else:
|
||||
# В элементе пусто — сбрасываем кэш, чтобы следующая фраза шла с новой строки
|
||||
last_full_text = ""
|
||||
|
||||
time.sleep(CHECK_INTERVAL)
|
||||
|
||||
except Exception:
|
||||
# Если элемент потерян, сбрасываем состояние
|
||||
last_full_text = ""
|
||||
try:
|
||||
_ = driver.current_url
|
||||
except:
|
||||
print("Вкладка потеряна. Ищу...")
|
||||
active_tab_found = False
|
||||
time.sleep(CHECK_INTERVAL)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nСкрипт остановлен.")
|
||||
finally:
|
||||
print("Сессия завершена.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_capture()
|
||||
1
run.py
1
run.py
|
|
@ -10,6 +10,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
# ----------------------------------------------- Main ------------------------------------------------------------
|
||||
if __name__ == "__main__":
|
||||
# Добавляем папку app в Python path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
||||
from app.api import api
|
||||
from app.heartbeat_monitor import HeartbeatMonitor
|
||||
|
|
|
|||
38
run.spec
Normal file
38
run.spec
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['run.py'],
|
||||
pathex=['./app'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['eventlet.green', 'eventlet.green.thread', 'engineio.async_eventlet', 'engineio.async_drivers.eventlet'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='run',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user