Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Taehyun-Sung committed Jun 12, 2024
2 parents c9f30fd + f47d14b commit f0c40e9
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 25 deletions.
2 changes: 2 additions & 0 deletions app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,10 @@ def send_to_ide():
code = request.get_json().get("code_snippet")
unescaped_code = html.unescape(code)
if utils.send_code_snippet_to_ide(filename, unescaped_code):
utils.playsound_notification("success.mp3")
return "success"
else:
utils.playsound_notification("error.mp3")
return "fail"


Expand Down
3 changes: 3 additions & 0 deletions app/extract_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ def extract_code_at_timestamp(filename: str, timestamp: float) -> str:
:param timestamp: Time stamp of the frame to extract
:return: Formatted code as a string
"""
utils.playsound_notification("capture.mp3")
frame = ExtractText.extract_frame_at_timestamp(filename, timestamp)
if frame is not None:
extracted_text = pytesseract.image_to_string(frame)
logging.info(f"Successfully extracted code from frame @ {timestamp}s in file {filename}")
return ExtractText.format_raw_ocr_string(extracted_text)
else:
utils.playsound_notification("capture_fail_tone.wav")
logging.error(f"Unable to extract code from frame @ {timestamp}s in file {filename}")
return "ERROR"

Expand All @@ -50,6 +52,7 @@ def format_raw_ocr_string(extracted_text: str) -> str:
formatted_text = formatted_text.replace("```", "")
if config("Formatting", "remove_language_name"):
formatted_text = formatted_text.replace(language, "", 1)
utils.playsound_notification("success.mp3")
return formatted_text

@staticmethod
Expand Down
Binary file added app/static/audio/capture.mp3
Binary file not shown.
Binary file added app/static/audio/error.mp3
Binary file not shown.
Binary file added app/static/audio/success.mp3
Binary file not shown.
38 changes: 19 additions & 19 deletions app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,34 @@
import time
import cv2
from json import JSONDecodeError
from typing import Union, Optional, Any, List, Dict
from typing import Union, Optional, Any, List
import openai
import pytesseract
from pytube import YouTube
from pytube.exceptions import RegexMatchError
from configparser import ConfigParser
from playsound import playsound


def playsound_notification(audio_file):
"""
Play a notification sound. Requires the playsound package to be installed.
:args: audio_file: Path to the audio_file in the app/static/audio folder
"""
file_path = os.getcwd()
file_path += "//static/audio/"
file_name = audio_file
file_path = os.path.join(file_path, file_name)
print(file_path)
if audio_file is not None:
playsound(file_path)


FILE_PATH = Path(__file__).resolve() # Absolute Path of utils.py
APP_DIR = FILE_PATH.parent
PROJ_ROOT = APP_DIR.parent


def config(section: str = None, option: str = None) -> Union[ConfigParser, str]:
"""
Loads config variables from file and returns either specified variable or parser object. If attempting to
Expand All @@ -28,7 +45,6 @@ def config(section: str = None, option: str = None) -> Union[ConfigParser, str]:
:param option: [Optional] Key/option of value to retrieve
:return: Return string or ConfigParser object
"""

if (section is None) != (option is None):
raise SyntaxError("section AND option parameters OR no parameters must be passed to function config()")
parser = ConfigParser()
Expand Down Expand Up @@ -113,14 +129,11 @@ def directory_append_slash(directory: str) -> str:
:param directory: The directory path to which a trailing slash will be appended, if missing.
:return: The directory path with a trailing slash appended, if necessary.
"""

# Check if directory already have trailing slash
if directory.endswith(('/', '\\')):
return directory

# Append trailing slash
directory += '\\' if os.name == 'nt' else '/'

directory += '\\' if os.name == 'nt' else '/'
return directory


Expand All @@ -130,18 +143,14 @@ def get_vid_save_path() -> str:
:return: file path as string
"""
vid_download_path = config("UserSettings", "video_save_path")

# Set default output path for video download path
if vid_download_path == "output_path":
default_path = PROJ_ROOT / 'out' / 'videos'
if not default_path.exists():
default_path.mkdir(parents=True, exist_ok=True)

default_path = str(default_path)
return directory_append_slash(default_path)

vid_download_path = str(Path(vid_download_path))

return directory_append_slash(vid_download_path)


Expand All @@ -152,16 +161,12 @@ def get_output_path() -> str:
"""
output_path = config("UserSettings", "capture_output_path")
# Set default output path for code files

if output_path == "output_path":
default_path = PROJ_ROOT / 'out'
if not default_path.exists():
default_path.mkdir(parents=True, exist_ok=True)

default_path = str(default_path)

return directory_append_slash(default_path)

output_path = str(Path(output_path))
return directory_append_slash(output_path)

Expand Down Expand Up @@ -311,7 +316,6 @@ def add_video_to_user_data(filename: str, video_title: str, video_hash: str, you
user_data = read_user_data()
if user_data is None:
return

video_path = str(Path(get_vid_save_path(), f'{filename}').resolve())
video_capture = cv2.VideoCapture(video_path)
if not video_capture.isOpened():
Expand All @@ -326,12 +330,10 @@ def add_video_to_user_data(filename: str, video_title: str, video_hash: str, you
return
thumbnail = str(int(time.time())) + ".png"
# Check if img dir exists if not create

static_dir = APP_DIR / 'static'
img_dir = static_dir / 'img'
if not img_dir.exists():
img_dir.mkdir(parents=True, exist_ok=True)

cv2.imwrite(str(img_dir / f'{thumbnail}'), frame)
new_video = {
"video_hash": video_hash,
Expand Down Expand Up @@ -480,7 +482,6 @@ def delete_video_from_userdata(filename: str) -> None:
if current_video["filename"] == filename:
all_videos.remove(current_video)
break

with (APP_DIR / 'data' / 'userdata.json').open('w') as json_data:
json.dump(user_data, json_data, indent=4)

Expand All @@ -501,7 +502,6 @@ def update_configuration(new_values_dict) -> None:
if isinstance(value, bool) or isinstance(value, int):
value = str(value)
config_file.set(section, key, value)

# save the file
with (APP_DIR / 'config.ini').open('w') as config_file_save:
config_file.write(config_file_save)
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ openai==0.28.1
opencv-python==4.8.1.78
packaging==23.2
Pillow==10.1.0
playsound==1.2.2
pydantic==2.4.2
pydantic_core==2.10.1
pytesseract==0.3.10
Expand All @@ -28,4 +29,4 @@ typing_extensions==4.8.0
Werkzeug==3.0.1
pytest==7.4.3
pytest-cov==4.1.0
pytest-mock==3.12.0
pytest-mock==3.12.0
28 changes: 23 additions & 5 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,25 +119,25 @@ def test_hash_string():
def test_get_output_path(mocker):
project_root = str(utils.PROJ_ROOT)
default_path = utils.directory_append_slash(os.path.join(project_root, 'out'))

test_output_paths = {
"output_path": default_path,
}

assert os.name in ['nt', 'posix']

# Windows
if os.name == 'nt':
test_output_paths["c:\\users\\program files\\app"] = "c:\\users\\program files\\app\\"
test_output_paths["videos\\my_videos\\"] = "videos\\my_videos\\"

# Linux or macOS (Note: GitHub Runner is using ubuntu)
else:
assert os.name == 'posix'
users_dir = 'home' if 'home' in os.path.expanduser("~") else 'Users'
test_output_paths[f"/{users_dir}/program_files/app"] = f"/{users_dir}/program_files/app/"
test_output_paths["videos/my_videos/"] = "videos/my_videos/"

for paths in test_output_paths:
mocker.patch("app.utils.config", return_value=paths)
assert utils.get_output_path() == test_output_paths[paths]
Expand All @@ -156,3 +156,21 @@ def test_file_already_exists_false(mocker):
def test_file_already_exists_no_user_data(mocker):
mocker.patch("app.utils.read_user_data", return_value=None)
assert not utils.file_already_exists("4aj3sdl5a4k2sjd091u091j")


def test_audio_file_exists_in_audio_file_directory():
file_path = os.getcwd()
file_path += "//static/audio/"
edit_path = file_path.replace('tests', 'app')
audio_file = 'success.mp3'
file_path = os.path.join(edit_path, audio_file)
assert os.path.exists(file_path)


def test_audio_file_does_not_exist_in_audio_file_directory():
file_path = os.getcwd()
file_path += "//static/audio/"
edit_path = file_path.replace('tests', 'app')
audio_file = 'non_existent_file.mp3'
file_path = os.path.join(edit_path, audio_file)
assert not os.path.exists(file_path)

0 comments on commit f0c40e9

Please sign in to comment.