wordflow-cli 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/PKG-INFO +11 -10
  2. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/README.md +10 -9
  3. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/pyproject.toml +1 -1
  4. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/anki_flashcard.py +10 -4
  5. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/cli.py +14 -5
  6. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/configuration.py +1 -1
  7. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/translator.py +2 -2
  8. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/workflows.py +43 -5
  9. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/PKG-INFO +11 -10
  10. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/LICENSE +0 -0
  11. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/setup.cfg +0 -0
  12. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/__init__.py +0 -0
  13. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/clipboard.py +0 -0
  14. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/data/default_config.toml +0 -0
  15. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/data/logo.txt +0 -0
  16. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/data/logo2.txt +0 -0
  17. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/my_classes.py +0 -0
  18. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/notifications.py +0 -0
  19. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/text_to_speech.py +0 -0
  20. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow/wizard.py +0 -0
  21. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/SOURCES.txt +0 -0
  22. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/dependency_links.txt +0 -0
  23. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/entry_points.txt +0 -0
  24. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/requires.txt +0 -0
  25. {wordflow_cli-0.1.4 → wordflow_cli-0.1.6}/src/wordflow_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wordflow-cli
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Automate Anki flashcard creation and text translation directly from your clipboard.
5
5
  Author-email: Mathéo Tritschler <tritschler.matheo@gmail.com>
6
6
  License: MIT
@@ -19,15 +19,6 @@ Requires-Dist: requests>=2.28.0
19
19
  Requires-Dist: tomli-w>=1.0.0
20
20
  Dynamic: license-file
21
21
 
22
- $$\ $$\ $$\ $$$$$$$$\ $$\
23
- $$ | $\ $$ | $$ | $$ _____|$$ |
24
- $$ |$$$\ $$ | $$$$$$\ $$$$$$\ $$$$$$$ | $$ | $$ | $$$$$$\ $$\ $$\ $$\
25
- $$ $$ $$\$$ |$$ __$$\ $$ __$$\ $$ __$$ | $$$$$\ $$ |$$ __$$\ $$ | $$ | $$ |
26
- $$$$ _$$$$ |$$ / $$ |$$ | \__|$$ / $$ | $$ __| $$ |$$ / $$ |$$ | $$ | $$ |
27
- $$$ / \$$$ |$$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ | $$ |$$ | $$ | $$ |
28
- $$ / \$$ |\$$$$$$ |$$ | \$$$$$$$ | $$ | $$ |\$$$$$$ |\$$$$$\$$$$ |
29
- \__/ \__| \______/ \__| \_______| \__| \__| \______/ \_____\____/
30
-
31
22
  # Wordflow
32
23
 
33
24
  A lightning-fast, dependency-free, keyboard-driven language acquisition tool for Linux.
@@ -163,12 +154,16 @@ Wordflow automatically routes audio to native speakers of the detected language.
163
154
  ## Instant Translation (-t)
164
155
 
165
156
  Highlight any text on your screen and trigger the wordflow --translate command. Wordflow detects the language, translates it, and sends a desktop notification. Clicking the notification copies the translation to your clipboard.
157
+
166
158
  ## Cloze Card Creation (-c)
167
159
 
168
160
  To create a flashcard, highlight the target word/sentence and trigger wordflow --cloze. Wordflow will parse all dictionary data, build the card according to your TOML layout, and push it directly to Anki.
169
161
 
170
162
  Use wordflow --help to list all command-line arguments.
171
163
 
164
+ ## Undo Last Card (-u / --undo)
165
+
166
+ If you accidentally create a card with a typo or the wrong highlighted text, simply trigger the `wordflow --undo` command. Wordflow remembers the ID of the last flashcard it generated and will instantly delete it from your Anki database.
172
167
  # ⌨️ Creating Shortcuts
173
168
 
174
169
  Wordflow is designed to be bound to your window manager's shortcuts, allowing you to seamlessly translate and capture vocabulary without losing focus on your current task.
@@ -186,6 +181,11 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
186
181
  hl.dispatch(hl.dsp.submap("reset"))
187
182
  hl.dispatch(hl.dsp.exec_cmd("wordflow -c"))
188
183
  end)
184
+ --u : Undo last card
185
+ hl.bind("U", function()
186
+ hl.dispatch(hl.dsp.submap("reset"))
187
+ hl.dispatch(hl.dsp.exec_cmd("wordflow -u"))
188
+ end)
189
189
 
190
190
  hl.bind("catchall", hl.dsp.submap("reset"))
191
191
  end)
@@ -193,3 +193,4 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
193
193
  ## Sway / i3 Example
194
194
  bindsym Mod4+t exec "wordflow -t"
195
195
  bindsym Mod4+c exec "wordflow -c"
196
+ bindsym Mod4+u exec "wordflow -u"
@@ -1,12 +1,3 @@
1
- $$\ $$\ $$\ $$$$$$$$\ $$\
2
- $$ | $\ $$ | $$ | $$ _____|$$ |
3
- $$ |$$$\ $$ | $$$$$$\ $$$$$$\ $$$$$$$ | $$ | $$ | $$$$$$\ $$\ $$\ $$\
4
- $$ $$ $$\$$ |$$ __$$\ $$ __$$\ $$ __$$ | $$$$$\ $$ |$$ __$$\ $$ | $$ | $$ |
5
- $$$$ _$$$$ |$$ / $$ |$$ | \__|$$ / $$ | $$ __| $$ |$$ / $$ |$$ | $$ | $$ |
6
- $$$ / \$$$ |$$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ | $$ |$$ | $$ | $$ |
7
- $$ / \$$ |\$$$$$$ |$$ | \$$$$$$$ | $$ | $$ |\$$$$$$ |\$$$$$\$$$$ |
8
- \__/ \__| \______/ \__| \_______| \__| \__| \______/ \_____\____/
9
-
10
1
  # Wordflow
11
2
 
12
3
  A lightning-fast, dependency-free, keyboard-driven language acquisition tool for Linux.
@@ -142,12 +133,16 @@ Wordflow automatically routes audio to native speakers of the detected language.
142
133
  ## Instant Translation (-t)
143
134
 
144
135
  Highlight any text on your screen and trigger the wordflow --translate command. Wordflow detects the language, translates it, and sends a desktop notification. Clicking the notification copies the translation to your clipboard.
136
+
145
137
  ## Cloze Card Creation (-c)
146
138
 
147
139
  To create a flashcard, highlight the target word/sentence and trigger wordflow --cloze. Wordflow will parse all dictionary data, build the card according to your TOML layout, and push it directly to Anki.
148
140
 
149
141
  Use wordflow --help to list all command-line arguments.
150
142
 
143
+ ## Undo Last Card (-u / --undo)
144
+
145
+ If you accidentally create a card with a typo or the wrong highlighted text, simply trigger the `wordflow --undo` command. Wordflow remembers the ID of the last flashcard it generated and will instantly delete it from your Anki database.
151
146
  # ⌨️ Creating Shortcuts
152
147
 
153
148
  Wordflow is designed to be bound to your window manager's shortcuts, allowing you to seamlessly translate and capture vocabulary without losing focus on your current task.
@@ -165,6 +160,11 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
165
160
  hl.dispatch(hl.dsp.submap("reset"))
166
161
  hl.dispatch(hl.dsp.exec_cmd("wordflow -c"))
167
162
  end)
163
+ --u : Undo last card
164
+ hl.bind("U", function()
165
+ hl.dispatch(hl.dsp.submap("reset"))
166
+ hl.dispatch(hl.dsp.exec_cmd("wordflow -u"))
167
+ end)
168
168
 
169
169
  hl.bind("catchall", hl.dsp.submap("reset"))
170
170
  end)
@@ -172,3 +172,4 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
172
172
  ## Sway / i3 Example
173
173
  bindsym Mod4+t exec "wordflow -t"
174
174
  bindsym Mod4+c exec "wordflow -c"
175
+ bindsym Mod4+u exec "wordflow -u"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wordflow-cli"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "Automate Anki flashcard creation and text translation directly from your clipboard."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -111,9 +111,10 @@ def setup_anki_model(url: str, model_name: str, fields: dict):
111
111
 
112
112
  def make_cloze(
113
113
  anki_config: AnkiConfig, sentence_data: TranslationData, word_data: TranslationData
114
- ):
114
+ ) -> str:
115
115
  """
116
116
  makes a cloze flashcard and sends it to anki through AnkiConnect
117
+ returns the id of the created card
117
118
  """
118
119
  # before doing anything, checks that the word is in the sentence
119
120
  if word_data.source_data.lower() not in sentence_data.source_data.lower():
@@ -142,14 +143,14 @@ def make_cloze(
142
143
  }
143
144
 
144
145
  try:
145
- invoke(anki_config.url, "addNote", note=note)
146
+ note_id = invoke(anki_config.url, "addNote", note=note)
146
147
  except AnkiConnectError as e:
147
148
  if "duplicate" in str(e).lower():
148
149
  raise DuplicateNoteError(
149
150
  f"A note for '{word_data.source_data}' already exists."
150
151
  )
151
- raise e
152
- return True
152
+ raise AnkiConnectError(e)
153
+ return note_id
153
154
 
154
155
 
155
156
  def add_audio_to_anki(url: str, text: str, lang_code: str, accent: str):
@@ -281,3 +282,8 @@ def process_fields(
281
282
 
282
283
  print("fields sent to anki: ", formatted_anki_fields)
283
284
  return formatted_anki_fields
285
+
286
+
287
+ def delete_note(anki_url: str, note_id: int):
288
+ invoke(anki_url, "deleteNotes", notes=[note_id])
289
+ return True
@@ -4,7 +4,7 @@ import traceback
4
4
 
5
5
  # local modules
6
6
  from .configuration import create_config, load_config, print_config
7
- from .workflows import translate_workflow, cloze_workflow
7
+ from .workflows import translate_workflow, cloze_workflow, undo_workflow
8
8
  from .wizard import launch_wizard
9
9
  from .my_classes import GlobalConfig, AnkiConfig
10
10
  from .notifications import notify
@@ -36,6 +36,9 @@ def get_parser():
36
36
  action="store_true",
37
37
  help="Launch the interactive configuration wizard.",
38
38
  )
39
+ group.add_argument(
40
+ "-u", "--undo", action="store_true", help="cancel last created card"
41
+ )
39
42
 
40
43
  group.add_argument(
41
44
  "--print_config",
@@ -77,8 +80,8 @@ def main():
77
80
 
78
81
  args = parser.parse_args()
79
82
 
83
+ # handle correct operation
80
84
  try:
81
- # 2. Handle config and wizard
82
85
  if args.wizard:
83
86
  config = launch_wizard()
84
87
  create_config(config)
@@ -87,17 +90,23 @@ def main():
87
90
  print_config()
88
91
  sys.exit(0)
89
92
 
90
- # 3. loads configuration
93
+ # loads configuration
91
94
  global_config, raw_anki_data = load_config(
92
95
  args.source_language, args.target_language, args.notify
93
96
  )
94
97
 
95
- # 4. trigger workflow
96
98
  if args.translate:
97
99
  translate_workflow(global_config)
100
+ sys.exit(0)
98
101
 
99
- elif args.cloze:
102
+ if args.cloze:
100
103
  cloze_workflow(global_config, raw_anki_data)
104
+ sys.exit(0)
105
+
106
+ if args.undo:
107
+ url = raw_anki_data.get("default", {}).get("url", "http://localhost:8765")
108
+ undo_workflow(url, global_config.enable_notifications)
109
+ sys.exit(0)
101
110
 
102
111
  except KeyboardInterrupt:
103
112
  notify(
@@ -138,7 +138,7 @@ def resolve_anki_config(
138
138
  anki_override_fields = anki_override.get("fields", {})
139
139
 
140
140
  anki_config = AnkiConfig(
141
- url=anki_override.get("url", anki_defaults.get("url")),
141
+ url=anki_override.get("url", anki_defaults.get("url", "http://localhost:8765")),
142
142
  deck=anki_override.get(
143
143
  "deck", anki_defaults.get("deck", "Wordflow::{source_language}")
144
144
  ).replace("{source_language}", str(active_language)),
@@ -93,8 +93,8 @@ def translate(
93
93
  examples=data.get("examples"),
94
94
  )
95
95
  # DEBUG
96
- print("json data: ", response.json())
97
- print("translation data: ", translation_data)
96
+ # print("json data: ", response.json())
97
+ # print("translation data: ", translation_data)
98
98
  return translation_data
99
99
 
100
100
  except requests.RequestException as e:
@@ -1,11 +1,41 @@
1
+ import os
2
+ import tempfile
3
+
1
4
  from .clipboard import get_text, ClipboardError, TimeOutError
2
5
  from .translator import translate, TranslationError
3
6
  from .notifications import notify
4
- from .anki_flashcard import AnkiConnectError, DuplicateNoteError, make_cloze
7
+ from .anki_flashcard import (
8
+ AnkiConnectError,
9
+ DuplicateNoteError,
10
+ make_cloze,
11
+ delete_note,
12
+ )
5
13
  from .my_classes import TranslationData, AnkiConfig, GlobalConfig
6
14
  from .configuration import resolve_anki_config
7
15
 
8
16
 
17
+ CACHE_FILE = os.path.join(tempfile.gettempdir(), "wordflow_last_note.txt")
18
+
19
+
20
+ def undo_workflow(anki_url, enable_notifications):
21
+ """tries to delete the last card created using wordflow"""
22
+ try:
23
+ with open(CACHE_FILE, "r") as f:
24
+ last_id = int(f.read().strip())
25
+ delete_note(anki_url, last_id)
26
+
27
+ # Clear the cache
28
+ os.remove(CACHE_FILE)
29
+ notify(
30
+ "Undo OK",
31
+ f"Successfully deleted the last created flashcard (ID: {last_id}).",
32
+ enable_notifications=enable_notifications,
33
+ )
34
+
35
+ except (FileNotFoundError, ValueError):
36
+ print("No recent flashcard found to undo.")
37
+
38
+
9
39
  def translate_workflow(global_config: GlobalConfig):
10
40
  """translates a word or sentence and outputs it in a clickable notification"""
11
41
  try:
@@ -59,7 +89,10 @@ def cloze_workflow(
59
89
  global_config: GlobalConfig,
60
90
  raw_anki_data: dict,
61
91
  ):
62
- """creates an anki cloze flashcard from clipboard, automatically detecting correct language settings"""
92
+ """
93
+ creates an anki cloze flashcard from clipboard, automatically detecting correct language settings
94
+ writes the id of the resulting card in a temp file
95
+ """
63
96
  try:
64
97
  # 1. Get sentence
65
98
  original_sentence = get_text()
@@ -88,14 +121,19 @@ def cloze_workflow(
88
121
  resolved_anki_config = resolve_anki_config(
89
122
  raw_anki_data, sentence_translation_data.source_language
90
123
  )
91
- #
124
+
92
125
  # 5. Make the cloze card and send it to anki
93
- make_cloze(
126
+ note_id = make_cloze(
94
127
  anki_config=resolved_anki_config,
95
128
  sentence_data=sentence_translation_data,
96
129
  word_data=word_translation_data,
97
130
  )
98
- # 5. Notify success
131
+
132
+ # 6. write note id in temp file (for potential undo)
133
+ with open(CACHE_FILE, "w") as f:
134
+ f.write(str(note_id))
135
+
136
+ # 7. Notify success
99
137
  notify(
100
138
  "Anki Success",
101
139
  f"Cloze card created for: '{word_to_cloze}' in {resolved_anki_config.deck}",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wordflow-cli
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Automate Anki flashcard creation and text translation directly from your clipboard.
5
5
  Author-email: Mathéo Tritschler <tritschler.matheo@gmail.com>
6
6
  License: MIT
@@ -19,15 +19,6 @@ Requires-Dist: requests>=2.28.0
19
19
  Requires-Dist: tomli-w>=1.0.0
20
20
  Dynamic: license-file
21
21
 
22
- $$\ $$\ $$\ $$$$$$$$\ $$\
23
- $$ | $\ $$ | $$ | $$ _____|$$ |
24
- $$ |$$$\ $$ | $$$$$$\ $$$$$$\ $$$$$$$ | $$ | $$ | $$$$$$\ $$\ $$\ $$\
25
- $$ $$ $$\$$ |$$ __$$\ $$ __$$\ $$ __$$ | $$$$$\ $$ |$$ __$$\ $$ | $$ | $$ |
26
- $$$$ _$$$$ |$$ / $$ |$$ | \__|$$ / $$ | $$ __| $$ |$$ / $$ |$$ | $$ | $$ |
27
- $$$ / \$$$ |$$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ | $$ |$$ | $$ | $$ |
28
- $$ / \$$ |\$$$$$$ |$$ | \$$$$$$$ | $$ | $$ |\$$$$$$ |\$$$$$\$$$$ |
29
- \__/ \__| \______/ \__| \_______| \__| \__| \______/ \_____\____/
30
-
31
22
  # Wordflow
32
23
 
33
24
  A lightning-fast, dependency-free, keyboard-driven language acquisition tool for Linux.
@@ -163,12 +154,16 @@ Wordflow automatically routes audio to native speakers of the detected language.
163
154
  ## Instant Translation (-t)
164
155
 
165
156
  Highlight any text on your screen and trigger the wordflow --translate command. Wordflow detects the language, translates it, and sends a desktop notification. Clicking the notification copies the translation to your clipboard.
157
+
166
158
  ## Cloze Card Creation (-c)
167
159
 
168
160
  To create a flashcard, highlight the target word/sentence and trigger wordflow --cloze. Wordflow will parse all dictionary data, build the card according to your TOML layout, and push it directly to Anki.
169
161
 
170
162
  Use wordflow --help to list all command-line arguments.
171
163
 
164
+ ## Undo Last Card (-u / --undo)
165
+
166
+ If you accidentally create a card with a typo or the wrong highlighted text, simply trigger the `wordflow --undo` command. Wordflow remembers the ID of the last flashcard it generated and will instantly delete it from your Anki database.
172
167
  # ⌨️ Creating Shortcuts
173
168
 
174
169
  Wordflow is designed to be bound to your window manager's shortcuts, allowing you to seamlessly translate and capture vocabulary without losing focus on your current task.
@@ -186,6 +181,11 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
186
181
  hl.dispatch(hl.dsp.submap("reset"))
187
182
  hl.dispatch(hl.dsp.exec_cmd("wordflow -c"))
188
183
  end)
184
+ --u : Undo last card
185
+ hl.bind("U", function()
186
+ hl.dispatch(hl.dsp.submap("reset"))
187
+ hl.dispatch(hl.dsp.exec_cmd("wordflow -u"))
188
+ end)
189
189
 
190
190
  hl.bind("catchall", hl.dsp.submap("reset"))
191
191
  end)
@@ -193,3 +193,4 @@ Wordflow is designed to be bound to your window manager's shortcuts, allowing yo
193
193
  ## Sway / i3 Example
194
194
  bindsym Mod4+t exec "wordflow -t"
195
195
  bindsym Mod4+c exec "wordflow -c"
196
+ bindsym Mod4+u exec "wordflow -u"
File without changes
File without changes