ebk 0.1.0__py3-none-any.whl → 0.3.2__py3-none-any.whl

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.

Potentially problematic release.


This version of ebk might be problematic. Click here for more details.

Files changed (84) hide show
  1. ebk/__init__.py +35 -0
  2. ebk/ai/__init__.py +23 -0
  3. ebk/ai/knowledge_graph.py +443 -0
  4. ebk/ai/llm_providers/__init__.py +21 -0
  5. ebk/ai/llm_providers/base.py +230 -0
  6. ebk/ai/llm_providers/ollama.py +362 -0
  7. ebk/ai/metadata_enrichment.py +396 -0
  8. ebk/ai/question_generator.py +328 -0
  9. ebk/ai/reading_companion.py +224 -0
  10. ebk/ai/semantic_search.py +434 -0
  11. ebk/ai/text_extractor.py +394 -0
  12. ebk/cli.py +2828 -680
  13. ebk/config.py +260 -22
  14. ebk/db/__init__.py +37 -0
  15. ebk/db/migrations.py +180 -0
  16. ebk/db/models.py +526 -0
  17. ebk/db/session.py +144 -0
  18. ebk/decorators.py +132 -0
  19. ebk/exports/base_exporter.py +218 -0
  20. ebk/exports/html_library.py +1390 -0
  21. ebk/exports/html_utils.py +117 -0
  22. ebk/exports/hugo.py +7 -3
  23. ebk/exports/jinja_export.py +287 -0
  24. ebk/exports/multi_facet_export.py +164 -0
  25. ebk/exports/symlink_dag.py +479 -0
  26. ebk/extract_metadata.py +76 -7
  27. ebk/library_db.py +899 -0
  28. ebk/plugins/__init__.py +42 -0
  29. ebk/plugins/base.py +502 -0
  30. ebk/plugins/hooks.py +444 -0
  31. ebk/plugins/registry.py +500 -0
  32. ebk/repl/__init__.py +9 -0
  33. ebk/repl/find.py +126 -0
  34. ebk/repl/grep.py +174 -0
  35. ebk/repl/shell.py +1677 -0
  36. ebk/repl/text_utils.py +320 -0
  37. ebk/search_parser.py +413 -0
  38. ebk/server.py +1633 -0
  39. ebk/services/__init__.py +11 -0
  40. ebk/services/import_service.py +442 -0
  41. ebk/services/tag_service.py +282 -0
  42. ebk/services/text_extraction.py +317 -0
  43. ebk/similarity/__init__.py +77 -0
  44. ebk/similarity/base.py +154 -0
  45. ebk/similarity/core.py +445 -0
  46. ebk/similarity/extractors.py +168 -0
  47. ebk/similarity/metrics.py +376 -0
  48. ebk/vfs/__init__.py +101 -0
  49. ebk/vfs/base.py +301 -0
  50. ebk/vfs/library_vfs.py +124 -0
  51. ebk/vfs/nodes/__init__.py +54 -0
  52. ebk/vfs/nodes/authors.py +196 -0
  53. ebk/vfs/nodes/books.py +480 -0
  54. ebk/vfs/nodes/files.py +155 -0
  55. ebk/vfs/nodes/metadata.py +385 -0
  56. ebk/vfs/nodes/root.py +100 -0
  57. ebk/vfs/nodes/similar.py +165 -0
  58. ebk/vfs/nodes/subjects.py +184 -0
  59. ebk/vfs/nodes/tags.py +371 -0
  60. ebk/vfs/resolver.py +228 -0
  61. ebk-0.3.2.dist-info/METADATA +755 -0
  62. ebk-0.3.2.dist-info/RECORD +69 -0
  63. {ebk-0.1.0.dist-info → ebk-0.3.2.dist-info}/WHEEL +1 -1
  64. ebk-0.3.2.dist-info/licenses/LICENSE +21 -0
  65. ebk/imports/__init__.py +0 -0
  66. ebk/imports/calibre.py +0 -144
  67. ebk/imports/ebooks.py +0 -116
  68. ebk/llm.py +0 -58
  69. ebk/manager.py +0 -44
  70. ebk/merge.py +0 -308
  71. ebk/streamlit/__init__.py +0 -0
  72. ebk/streamlit/__pycache__/__init__.cpython-310.pyc +0 -0
  73. ebk/streamlit/__pycache__/display.cpython-310.pyc +0 -0
  74. ebk/streamlit/__pycache__/filters.cpython-310.pyc +0 -0
  75. ebk/streamlit/__pycache__/utils.cpython-310.pyc +0 -0
  76. ebk/streamlit/app.py +0 -185
  77. ebk/streamlit/display.py +0 -168
  78. ebk/streamlit/filters.py +0 -151
  79. ebk/streamlit/utils.py +0 -58
  80. ebk/utils.py +0 -311
  81. ebk-0.1.0.dist-info/METADATA +0 -457
  82. ebk-0.1.0.dist-info/RECORD +0 -29
  83. {ebk-0.1.0.dist-info → ebk-0.3.2.dist-info}/entry_points.txt +0 -0
  84. {ebk-0.1.0.dist-info → ebk-0.3.2.dist-info}/top_level.txt +0 -0
ebk/repl/grep.py ADDED
@@ -0,0 +1,174 @@
1
+ """grep implementation for REPL shell."""
2
+
3
+ import re
4
+ from typing import List, Tuple, Optional
5
+ from pathlib import Path
6
+
7
+ from ebk.vfs import LibraryVFS, DirectoryNode, FileNode
8
+
9
+
10
+ class GrepMatcher:
11
+ """Unix-like grep functionality for VFS."""
12
+
13
+ def __init__(self, vfs: LibraryVFS):
14
+ """Initialize grep matcher.
15
+
16
+ Args:
17
+ vfs: VFS instance
18
+ """
19
+ self.vfs = vfs
20
+
21
+ def grep(
22
+ self,
23
+ pattern: str,
24
+ paths: List[str],
25
+ recursive: bool = False,
26
+ ignore_case: bool = False,
27
+ line_numbers: bool = False,
28
+ ) -> List[Tuple[str, int, str]]:
29
+ """Search for pattern in files.
30
+
31
+ Args:
32
+ pattern: Regex pattern to search for
33
+ paths: List of paths to search (files or directories)
34
+ recursive: Search directories recursively
35
+ ignore_case: Case-insensitive matching
36
+ line_numbers: Include line numbers in output
37
+
38
+ Returns:
39
+ List of (file_path, line_number, line_content) tuples
40
+ """
41
+ results = []
42
+
43
+ # Compile regex
44
+ flags = re.IGNORECASE if ignore_case else 0
45
+ try:
46
+ regex = re.compile(pattern, flags)
47
+ except re.error as e:
48
+ raise ValueError(f"Invalid regex pattern: {e}")
49
+
50
+ # Process each path
51
+ for path in paths:
52
+ results.extend(
53
+ self._search_path(path, regex, recursive, line_numbers)
54
+ )
55
+
56
+ return results
57
+
58
+ def _search_path(
59
+ self,
60
+ path: str,
61
+ regex: re.Pattern,
62
+ recursive: bool,
63
+ line_numbers: bool,
64
+ ) -> List[Tuple[str, int, str]]:
65
+ """Search a single path.
66
+
67
+ Args:
68
+ path: Path to search
69
+ regex: Compiled regex pattern
70
+ recursive: Search recursively
71
+ line_numbers: Include line numbers
72
+
73
+ Returns:
74
+ List of matches
75
+ """
76
+ results = []
77
+
78
+ # Resolve path
79
+ node = self.vfs.get_node(path)
80
+ if node is None:
81
+ return results
82
+
83
+ # If it's a file, search it
84
+ if isinstance(node, FileNode):
85
+ results.extend(self._search_file(node, regex, line_numbers))
86
+
87
+ # If it's a directory, search children
88
+ elif isinstance(node, DirectoryNode):
89
+ if recursive:
90
+ results.extend(
91
+ self._search_directory_recursive(node, regex, line_numbers)
92
+ )
93
+ else:
94
+ # Just search immediate children that are files
95
+ for child in node.list_children():
96
+ if isinstance(child, FileNode):
97
+ results.extend(
98
+ self._search_file(child, regex, line_numbers)
99
+ )
100
+
101
+ return results
102
+
103
+ def _search_file(
104
+ self,
105
+ file_node: FileNode,
106
+ regex: re.Pattern,
107
+ line_numbers: bool,
108
+ ) -> List[Tuple[str, int, str]]:
109
+ """Search a single file.
110
+
111
+ Args:
112
+ file_node: File node to search
113
+ regex: Compiled regex pattern
114
+ line_numbers: Include line numbers
115
+
116
+ Returns:
117
+ List of matches
118
+ """
119
+ results = []
120
+
121
+ try:
122
+ content = file_node.read_content()
123
+ lines = content.split("\n")
124
+
125
+ file_path = file_node.get_path()
126
+
127
+ for i, line in enumerate(lines, start=1):
128
+ if regex.search(line):
129
+ line_num = i if line_numbers else 0
130
+ results.append((file_path, line_num, line))
131
+
132
+ except Exception:
133
+ # Skip files that can't be read
134
+ pass
135
+
136
+ return results
137
+
138
+ def _search_directory_recursive(
139
+ self,
140
+ dir_node: DirectoryNode,
141
+ regex: re.Pattern,
142
+ line_numbers: bool,
143
+ ) -> List[Tuple[str, int, str]]:
144
+ """Search directory recursively.
145
+
146
+ Args:
147
+ dir_node: Directory node to search
148
+ regex: Compiled regex pattern
149
+ line_numbers: Include line numbers
150
+
151
+ Returns:
152
+ List of matches
153
+ """
154
+ results = []
155
+
156
+ try:
157
+ children = dir_node.list_children()
158
+
159
+ for child in children:
160
+ if isinstance(child, FileNode):
161
+ results.extend(self._search_file(child, regex, line_numbers))
162
+ elif isinstance(child, DirectoryNode):
163
+ # Recurse into subdirectory
164
+ results.extend(
165
+ self._search_directory_recursive(
166
+ child, regex, line_numbers
167
+ )
168
+ )
169
+
170
+ except Exception:
171
+ # Skip directories that can't be read
172
+ pass
173
+
174
+ return results