Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
02c6197
dynamic file path to DataRetrieverFactory
KumudithaSilva Jan 29, 2026
6c07bcf
Add Interface for saving vocabulary data
KumudithaSilva Jan 29, 2026
0e786e0
Add Concrete implementation of IDataSaver with factory
KumudithaSilva Jan 29, 2026
417716b
updated IDataRetriever with DataRetrieverFactory interface
KumudithaSilva Jan 29, 2026
68e7f62
updated main
KumudithaSilva Jan 29, 2026
e79716e
restyle, added space
KumudithaSilva Jan 29, 2026
1547019
restyle, removed unused libraries
KumudithaSilva Jan 29, 2026
316b401
restyle, add extra space
KumudithaSilva Jan 29, 2026
03e3e06
restyle, remove indentation
KumudithaSilva Jan 29, 2026
92c7fb2
add icons
KumudithaSilva Jan 30, 2026
9db023c
modify load data file name
KumudithaSilva Jan 30, 2026
8cc1535
add icon to main
KumudithaSilva Jan 30, 2026
21d449a
add windows builder
KumudithaSilva Jan 30, 2026
4db38d2
updated CI/CD
KumudithaSilva Jan 30, 2026
396c852
updated CI/CD with pillow
KumudithaSilva Jan 30, 2026
5c95769
updated CI/CD with bundles the icon to pyinstaller
KumudithaSilva Jan 30, 2026
96428da
updated CI/CD with bundles the icon to pyinstaller
KumudithaSilva Jan 30, 2026
0f46dd1
updated CI/CD with bundles the icon to pyinstaller
KumudithaSilva Jan 30, 2026
97798fd
updated CI/CD with bundles the icon to pyinstaller
KumudithaSilva Jan 30, 2026
5e1f38b
fixed pyinstaller fill path
KumudithaSilva Jan 31, 2026
2dbce60
removed directory names, commented save to file
KumudithaSilva Jan 31, 2026
1c353c0
moved files to relevant directories
KumudithaSilva Jan 31, 2026
6240e96
move files and create backup files
KumudithaSilva Jan 31, 2026
5e1c894
updated CI/Cd with data file
KumudithaSilva Jan 31, 2026
e9052c2
add word manager contract
KumudithaSilva Jan 31, 2026
c856a12
add concrete wordManager for consistent handler for all word-related …
KumudithaSilva Jan 31, 2026
e09dc0d
removed data saver
KumudithaSilva Jan 31, 2026
8b0af19
added data saver
KumudithaSilva Jan 31, 2026
5191875
add contract of DataRemover
KumudithaSilva Jan 31, 2026
ab8d870
add concrete data remover that remove known words from original source
KumudithaSilva Jan 31, 2026
2fb8469
add abs path for both local and pyinstaller
KumudithaSilva Jan 31, 2026
4b3b783
add abs path for both local and pyinstaller
KumudithaSilva Jan 31, 2026
df8e0af
add abs path for both local and pyinstaller
KumudithaSilva Jan 31, 2026
281bcc0
fixed libraries with isort
KumudithaSilva Jan 31, 2026
8575e97
fixed libraries with isort
KumudithaSilva Jan 31, 2026
bc6792e
fixed style add extra spaces
KumudithaSilva Jan 31, 2026
059fda0
add pyttsx3
KumudithaSilva Feb 1, 2026
805734e
testing audio service
KumudithaSilva Feb 1, 2026
51dcf16
add controller and MacUiOrchestrator handel speak
KumudithaSilva Feb 1, 2026
1c477e5
Abstract base class for tts services.
KumudithaSilva Feb 1, 2026
e41e2f8
add handle speak abstract method
KumudithaSilva Feb 1, 2026
17475bb
develop handle speak method
KumudithaSilva Feb 1, 2026
e4cfa86
develop AudioService with pyttsx3
KumudithaSilva Feb 1, 2026
a869ff3
style changes and refactored
KumudithaSilva Feb 1, 2026
b1cf301
removed logs
KumudithaSilva Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/lexicards-ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,43 @@ jobs:
pip install -r requirements.txt
pip install pytest
- run: python -m pytest tests --maxfail=5 --disable-warnings -q

build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.12.9

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build pyinstaller pillow pyttsx3

- name: Build Python package (wheel and sdist)
run: python -m build

- name: Build Windows executable with PyInstaller (include assets)
shell: cmd
run: |
pyinstaller lexicards/main.py --onefile --noconsole --name LexiCards --icon=lexicards/assets/images/lexicards-main.ico ^
--add-data "lexicards/assets/images;assets/images" ^
--add-data "lexicards/assets/data;assets/data"

- name: Show dist folder contents
run: dir dist

- name: Upload Python package artifacts
uses: actions/upload-artifact@v4
with:
name: python-package
path: dist/*.whl

- name: Upload Windows executable artifact
uses: actions/upload-artifact@v4
with:
name: LexiCards-exe
path: dist/LexiCards.exe
File renamed without changes.
102 changes: 102 additions & 0 deletions lexicards/assets/data_backup/french_words.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
French,English
partie,part
histoire,history
chercher,search
seulement,only
police,police
pensais,thought
aide,help
demande,request
genre,kind
mois,month
frère,brother
laisser,let
car,because
mettre,to put
aucun,no
laisse,leash
eux,them
ville,city
chaque,each
parlé,speak
arrivé,come
devrait,should
bébé,baby
longtemps,long time
heures,hours
vont,will
pendant,while
revoir,meet again
aucune,any
place,square
parle,speak
compris,understood
savais,knew
étaient,were
attention,Warning
voici,here is
pourrais,could
affaire,case
donner,give
type,type
leurs,their
donné,given
train,train
corps,body
endroit,place
yeux,eyes
façon,way
écoute,listen
dont,whose
trouve,find
premier,first
perdu,lost
main,hand
première,first
côté,side
pouvoir,power
vieux,old
sois,be
tiens,here
matin,morning
tellement,so much
enfant,child
point,point
venu,came
suite,after
pardon,sorry
venez,come
devant,in front of
vers,towards
minutes,minutes
demandé,request
chambre,bedroom
mis,placed
belle,beautiful
droit,law
aimerais,would like to
aujourd'hui,today
mari,husband
cause,cause
enfin,finally
espère,hope
eau,water
attendez,Wait
parti,left
nouvelle,new
boulot,job
arrêter,Stop
dirait,would say
terre,Earth
compte,account
donne,given
loin,far
fin,end
croire,believe
chérie,sweetheart
gros,large
plutôt,rather
aura,will have
filles,girls
jouer,to play
bureau,office
101 changes: 101 additions & 0 deletions lexicards/assets/data_backup/japanese_words.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
Japanese,English
の,of
で,at
する,Do
です,is
宛先,to
だがしかし,But
そして,and
年,year
そして,And
いる,be
月,moon
また,also
差出人,from
太陽,sun
成る,become
物,thing
有る,have
夜,night
そして,and
等,etc
言う,say
日本,Japan
よし,good
これ,This
人,person
それ,that
迄,until
詰め込む,stuff
宛先,to
又,again
これ,This
する,do
ねえ,Hey
缶,can
駅,station
国,country
より,than
大学,university
プレゼント,present
後,after
又は,or
線,line
ニュー,Nu
放送,broadcast
数,number
陸軍,army
欠席する,absent
部,department
持つ,hold
場所,place
名前,name
時間,time
世界,world
時間,time
戦争,war
時代,era
東京,Tokyo
奥,Oku
だがしかし,But
呼び出し,call
その後,afterwards
会議,meeting
それ,That
織機,loom
会う,meet
受ける,receive
多い,many
プレーヤー,player
ケース,case
顔,face
しかし,however
溜める,amass
昭和,Showa
仕事,work
地球,earth
中央,middle
使う,use
一緒に,together
学校,school
言葉,word
彼,he
行く,go
アメリカ,America
その時には,at that time
プログラム,program
車,car
会社,company
川,river
映画,film
位,rank
見る,see
テレビ,television
制,system
研究,research
都市,town
東,east
存在,existence
活動,activity
販売,sale
他,other
Binary file added lexicards/assets/images/lexicards-main.ico
Binary file not shown.
Binary file added lexicards/assets/images/lexicards.ico
Binary file not shown.
79 changes: 79 additions & 0 deletions lexicards/audio/audio_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import threading

import pyttsx3

from lexicards.interfaces.audio.i_audio_servcie import IAudioService


class AudioService(IAudioService):
"""
Audio service implementation using pyttsx3 for real-time text-to-speech.

Attributes:
lock: Threading lock to ensure the TTS engine is used safely in multithreaded environment.
"""

def __init__(self):
"""
Initialize the TTS engine, detect available voices, and store them in a dictionary.
"""
self.lock = threading.Lock()

# --------------------------
# Real-time Speech
# --------------------------
def speak(self, text: str, lang: str):
"""
Speak the given text in the specified language.

Args:
text (str): Text to be spoken.
lang (str): Language code ('en', 'ja', 'fr').

Note:
pyttsx3 engines cannot be safely reused,
so a new engine is created per call to ensure speech always works.
"""
lang = lang.strip().lower().lstrip("\ufeff")[0:2]

with self.lock:
engine = pyttsx3.init()
voice_id = self._select_voice(engine, lang)
if not voice_id:
return

engine.setProperty("voice", voice_id)
engine.say(text)
engine.runAndWait()

def speak_async(self, text: str, lang: str):
"""Run speak in a background thread."""
threading.Thread(target=self.speak, args=(text, lang), daemon=True).start()

# --------------------------
# Voice Detection
# --------------------------
@staticmethod
def _select_voice(engine, lang: str) -> str | None:
"""
Select a voice matching the requested language.

Args:
engine: pyttsx3 engine instance.
lang (str): Language code ('ja', 'en', 'fr').

Returns:
str | None: Voice ID if found, otherwise None.
"""
for voice in engine.getProperty("voices"):
vid = voice.id.lower()
name = voice.name.lower()

if lang == "ja" and ("ja" in vid or "japanese" in name):
return voice.id
if lang == "fr" and ("fr" in vid or "french" in name):
return voice.id
if lang == "en" and ("en" in vid or "english" in name):
return voice.id

return None
Loading