abstractassistant 0.2.0__py3-none-any.whl → 0.2.6__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.
@@ -1,16 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstractassistant
3
- Version: 0.2.0
3
+ Version: 0.2.6
4
4
  Summary: A sleek (macOS) system tray application providing instant access to LLMs
5
5
  Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/lpalbou/abstractassistant
8
8
  Project-URL: Repository, https://github.com/lpalbou/abstractassistant
9
9
  Project-URL: Issues, https://github.com/lpalbou/abstractassistant/issues
10
10
  Keywords: ai,llm,macos,system-tray,assistant
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: End Users/Desktop
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Operating System :: MacOS
15
14
  Classifier: Programming Language :: Python :: 3
16
15
  Classifier: Programming Language :: Python :: 3.9
@@ -22,12 +21,13 @@ Classifier: Topic :: Desktop Environment
22
21
  Requires-Python: >=3.9
23
22
  Description-Content-Type: text/markdown
24
23
  License-File: LICENSE
25
- Requires-Dist: abstractcore[all]>=2.4.2
24
+ Requires-Dist: abstractcore[all]>=2.4.5
26
25
  Requires-Dist: pystray>=0.19.4
27
26
  Requires-Dist: Pillow>=10.0.0
28
27
  Requires-Dist: PyQt5>=5.15.0
29
28
  Requires-Dist: markdown>=3.5.0
30
29
  Requires-Dist: pygments>=2.16.0
30
+ Requires-Dist: pymdown-extensions>=10.0
31
31
  Requires-Dist: abstractvoice>=0.5.0
32
32
  Requires-Dist: pyperclip>=1.8.2
33
33
  Requires-Dist: plyer>=2.1.0
@@ -66,17 +66,40 @@ A sleek macOS system tray application providing instant access to Large Language
66
66
  ## 🚀 Quick Start
67
67
 
68
68
  ### 1. Installation
69
+
70
+ #### 🍎 macOS Users (Recommended)
71
+ ```bash
72
+ # Enhanced installation with Dock integration
73
+ python3 install.py
74
+ ```
75
+
76
+ This will:
77
+ - Install AbstractAssistant from PyPI
78
+ - Create a macOS app bundle in `/Applications`
79
+ - Add AbstractAssistant to your Dock for easy access
80
+
81
+ #### 🔧 Standard Installation
69
82
  ```bash
70
- # Install from PyPI (recommended)
83
+ # Install from PyPI
71
84
  pip install abstractassistant
72
85
  ```
73
86
 
74
87
  For detailed installation instructions including prerequisites and voice setup, see **[📖 Installation Guide](docs/installation.md)**.
75
88
 
76
89
  ### 2. First Launch
90
+
91
+ #### 🍎 macOS App Bundle Users
92
+ - **Dock**: Click the AbstractAssistant icon in your Dock
93
+ - **Spotlight**: Search for "AbstractAssistant" and press Enter
94
+ - **Finder**: Open `/Applications/AbstractAssistant.app`
95
+
96
+ #### 🔧 Terminal Users
77
97
  ```bash
78
98
  # Launch the assistant
79
99
  assistant
100
+
101
+ # Or create macOS app bundle after installation
102
+ create-app-bundle
80
103
  ```
81
104
 
82
105
  ### 3. Start Using
@@ -1,26 +1,28 @@
1
+ setup_macos_app.py,sha256=PP-X7UVfv8VmwaOtmNao0Bn3P5oXRAgfs13TXMpNhA8,8806
1
2
  abstractassistant/__init__.py,sha256=homfqMDh6sX2nBROtk6-y72jnrStPph8gEOeT0OjKyU,35
2
3
  abstractassistant/app.py,sha256=-Nkgj1IruGhiuyMt7-EQPBwxXoeIykaO1FYKlS520zA,34032
3
4
  abstractassistant/cli.py,sha256=SQPxQCLjX-LOlhSEvG302D0AOyxlxo5QM2imxr9wxmc,4385
4
5
  abstractassistant/config.py,sha256=KodfPYTpHtavJyne-h-B-r3kbEt1uusSY8GknGLtDL8,5809
6
+ abstractassistant/create_app_bundle.py,sha256=PrOKIaYMW-v3gAEPCxaS2FUkhCfVd6PRU99DxYEEcXs,1471
5
7
  abstractassistant/web_server.py,sha256=_pqMzy13qfim9BMBqQJQifWyX7UQXFD_sZeiu4ZBt40,12816
6
8
  abstractassistant/core/__init__.py,sha256=TETStgToTe7QSsCZgRHDk2oSErlLJoeGN0sFg4Yx2_c,15
7
- abstractassistant/core/llm_manager.py,sha256=00bIacRnthoVA576nZY3J_PQVXhfID3efO1UEV89AVg,11176
9
+ abstractassistant/core/llm_manager.py,sha256=yIvFj0pSLeC22PsaD0a3I4PjylO5Qvju8P_1e9iyXAM,11376
8
10
  abstractassistant/core/tts_manager.py,sha256=vE5SOh16CmeWp_ml_tehmSZxj503KEjz0uCQPXpWOpQ,7819
9
11
  abstractassistant/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
10
12
  abstractassistant/ui/chat_bubble.py,sha256=TE6zPtQ46I9grKGAb744wHqk4yO6-und3iif8_33XGk,11357
11
- abstractassistant/ui/history_dialog.py,sha256=SPMzq-SxNPIkgbdv94sUimLVpjTp0rmx7PIEvWn9uuE,14219
13
+ abstractassistant/ui/history_dialog.py,sha256=jLi8JV6z_yN6yXBsRAF6cPfyPjwsUB-FYlBaInQRF3U,18523
12
14
  abstractassistant/ui/provider_manager.py,sha256=9IM-BxIs6lUlk6cDCBi7oZFMXmn4CFMlxh0s-_vhzXY,8403
13
- abstractassistant/ui/qt_bubble.py,sha256=3cirXQoHzgU4GYIvqZD6zer_rRLoxnOCgAcvy4uPplw,82620
15
+ abstractassistant/ui/qt_bubble.py,sha256=X9cgvV-s1V_kFQNCB9lr9ODc-raeFoYTIFYepz_uCRc,89142
14
16
  abstractassistant/ui/toast_manager.py,sha256=1aU4DPo-J45bC61gTEctHq98ZrHIFxRfZa_9Q8KF588,13721
15
- abstractassistant/ui/toast_window.py,sha256=jBxFHDwFsj3NVcWr-azgw06Y81gDipoyd6SRW3pTXyI,21465
17
+ abstractassistant/ui/toast_window.py,sha256=EYGRQOzQeR9MYrfdzkxN6FH-y7CaW8Noy5kw3CpQlmw,21609
16
18
  abstractassistant/ui/tts_state_manager.py,sha256=UF_zrfl9wf0hNHBGxevcoKxW5Dh7zXibUSVoSSjGP4o,10565
17
- abstractassistant/ui/ui_styles.py,sha256=0sjqsDYSfm4KKBTYKRj9h3VY5IC_UHVBK81ndWZK38w,13144
19
+ abstractassistant/ui/ui_styles.py,sha256=VoGlrZI3YJzDKPv9LWz39W3XcFI4N952rkzXb8Musfw,13150
18
20
  abstractassistant/utils/__init__.py,sha256=7Q3BxyXETkt3tm5trhuLTyL8PoECOK0QiK-0KUVAR2Q,16
19
21
  abstractassistant/utils/icon_generator.py,sha256=MH3giercjE6Dh100EZ_8kw5WC0PVwd5F4inKfRDLp2w,10455
20
- abstractassistant/utils/markdown_renderer.py,sha256=vGi38p7qkEtb9gT6UigNekToPYr5DpizMhKq0Qiz_tc,12602
21
- abstractassistant-0.2.0.dist-info/licenses/LICENSE,sha256=QUjFNAE-0yOkW9-Rle2axkpkt9H7xiZ2VbN-VeONhxc,1106
22
- abstractassistant-0.2.0.dist-info/METADATA,sha256=MJxz1PxGeBXPpdiy61Oldid5dROxk9xN28bIah6nNIU,10567
23
- abstractassistant-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- abstractassistant-0.2.0.dist-info/entry_points.txt,sha256=hSNmsf88uDC7eDA2yeTK17IFz5MtaPZEx5_0jQJ2aAY,57
25
- abstractassistant-0.2.0.dist-info/top_level.txt,sha256=qZc_LQH3CBxLq2P4B1aHayzkj8hn0euR31edkXQVzDA,18
26
- abstractassistant-0.2.0.dist-info/RECORD,,
22
+ abstractassistant/utils/markdown_renderer.py,sha256=sTn045glqxh5QU3LIuYp7zQpBIuwf5e3cWZzDz5i0Yw,12620
23
+ abstractassistant-0.2.6.dist-info/licenses/LICENSE,sha256=QUjFNAE-0yOkW9-Rle2axkpkt9H7xiZ2VbN-VeONhxc,1106
24
+ abstractassistant-0.2.6.dist-info/METADATA,sha256=7OmP5oqZ9ZPzCyTWGbRH-xCBmpr92q-jKnofEmC4u_8,11156
25
+ abstractassistant-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
+ abstractassistant-0.2.6.dist-info/entry_points.txt,sha256=MIzeCh0XG6MbhIzBHtkdEjmjxYBsQrGFevq8Y1L8Jkc,118
27
+ abstractassistant-0.2.6.dist-info/top_level.txt,sha256=oEcSXZAqbflTfZRfF4dogUq6TC1Nqyplq4JgC0CZnLI,34
28
+ abstractassistant-0.2.6.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ assistant = abstractassistant.cli:main
3
+ create-app-bundle = abstractassistant.create_app_bundle:main
@@ -1 +1,2 @@
1
1
  abstractassistant
2
+ setup_macos_app
setup_macos_app.py ADDED
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ macOS App Bundle Generator for AbstractAssistant.
4
+
5
+ This module creates a macOS .app bundle during installation,
6
+ allowing users to launch AbstractAssistant from the Dock.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+ import shutil
12
+ import subprocess
13
+ from pathlib import Path
14
+ from typing import Optional
15
+
16
+ try:
17
+ from PIL import Image
18
+ PIL_AVAILABLE = True
19
+ except ImportError:
20
+ PIL_AVAILABLE = False
21
+
22
+
23
+ class MacOSAppBundleGenerator:
24
+ """Generates macOS app bundles for AbstractAssistant."""
25
+
26
+ def __init__(self, package_dir: Path):
27
+ """Initialize the app bundle generator.
28
+
29
+ Args:
30
+ package_dir: Path to the abstractassistant package directory
31
+ """
32
+ self.package_dir = package_dir
33
+ self.app_name = "AbstractAssistant"
34
+ self.app_bundle_path = Path("/Applications") / f"{self.app_name}.app"
35
+
36
+ def is_macos(self) -> bool:
37
+ """Check if running on macOS."""
38
+ return sys.platform == "darwin"
39
+
40
+ def has_permissions(self) -> bool:
41
+ """Check if we have permissions to write to /Applications."""
42
+ try:
43
+ test_file = Path("/Applications") / ".test_write_permission"
44
+ test_file.touch()
45
+ test_file.unlink()
46
+ return True
47
+ except (PermissionError, OSError):
48
+ return False
49
+
50
+ def create_app_bundle_structure(self) -> bool:
51
+ """Create the basic app bundle directory structure."""
52
+ try:
53
+ # Create main directories
54
+ contents_dir = self.app_bundle_path / "Contents"
55
+ macos_dir = contents_dir / "MacOS"
56
+ resources_dir = contents_dir / "Resources"
57
+
58
+ for directory in [contents_dir, macos_dir, resources_dir]:
59
+ directory.mkdir(parents=True, exist_ok=True)
60
+
61
+ return True
62
+ except Exception as e:
63
+ print(f"Error creating app bundle structure: {e}")
64
+ return False
65
+
66
+ def generate_app_icon(self) -> bool:
67
+ """Generate the app icon using the existing icon generator."""
68
+ try:
69
+ # Import the icon generator
70
+ sys.path.insert(0, str(self.package_dir))
71
+ from abstractassistant.utils.icon_generator import IconGenerator
72
+
73
+ # Generate high-resolution icon
74
+ generator = IconGenerator(size=512)
75
+ icon = generator.create_app_icon('blue', animated=False)
76
+
77
+ # Save as PNG
78
+ icon_path = self.app_bundle_path / "Contents" / "Resources" / "icon.png"
79
+ icon.save(str(icon_path))
80
+
81
+ # Create ICNS file
82
+ return self._create_icns_file(icon_path)
83
+
84
+ except Exception as e:
85
+ print(f"Error generating app icon: {e}")
86
+ return False
87
+
88
+ def _create_icns_file(self, png_path: Path) -> bool:
89
+ """Create ICNS file from PNG using macOS iconutil."""
90
+ try:
91
+ # Create iconset directory
92
+ iconset_dir = png_path.parent / "temp_icons.iconset"
93
+ iconset_dir.mkdir(exist_ok=True)
94
+
95
+ # Load the PNG and create different sizes
96
+ icon = Image.open(png_path)
97
+ sizes = [
98
+ (16, 'icon_16x16.png'),
99
+ (32, 'icon_16x16@2x.png'),
100
+ (32, 'icon_32x32.png'),
101
+ (64, 'icon_32x32@2x.png'),
102
+ (128, 'icon_128x128.png'),
103
+ (256, 'icon_128x128@2x.png'),
104
+ (256, 'icon_256x256.png'),
105
+ (512, 'icon_256x256@2x.png'),
106
+ (512, 'icon_512x512.png'),
107
+ (1024, 'icon_512x512@2x.png')
108
+ ]
109
+
110
+ for size, filename in sizes:
111
+ resized = icon.resize((size, size), Image.Resampling.LANCZOS)
112
+ resized.save(iconset_dir / filename)
113
+
114
+ # Convert to ICNS
115
+ icns_path = png_path.parent / "icon.icns"
116
+ result = subprocess.run([
117
+ 'iconutil', '-c', 'icns', str(iconset_dir),
118
+ '-o', str(icns_path)
119
+ ], capture_output=True, text=True)
120
+
121
+ # Clean up
122
+ shutil.rmtree(iconset_dir)
123
+
124
+ return result.returncode == 0
125
+
126
+ except Exception as e:
127
+ print(f"Error creating ICNS file: {e}")
128
+ return False
129
+
130
+ def create_info_plist(self) -> bool:
131
+ """Create the Info.plist file."""
132
+ try:
133
+ plist_content = '''<?xml version="1.0" encoding="UTF-8"?>
134
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
135
+ <plist version="1.0">
136
+ <dict>
137
+ <key>CFBundleExecutable</key>
138
+ <string>AbstractAssistant</string>
139
+ <key>CFBundleIdentifier</key>
140
+ <string>ai.abstractcore.abstractassistant</string>
141
+ <key>CFBundleName</key>
142
+ <string>AbstractAssistant</string>
143
+ <key>CFBundleDisplayName</key>
144
+ <string>AbstractAssistant</string>
145
+ <key>CFBundleVersion</key>
146
+ <string>0.2.5</string>
147
+ <key>CFBundleShortVersionString</key>
148
+ <string>0.2.5</string>
149
+ <key>CFBundlePackageType</key>
150
+ <string>APPL</string>
151
+ <key>CFBundleSignature</key>
152
+ <string>????</string>
153
+ <key>CFBundleIconFile</key>
154
+ <string>icon.icns</string>
155
+ <key>LSMinimumSystemVersion</key>
156
+ <string>10.15</string>
157
+ <key>NSHighResolutionCapable</key>
158
+ <true/>
159
+ <key>NSRequiresAquaSystemAppearance</key>
160
+ <false/>
161
+ <key>LSUIElement</key>
162
+ <true/>
163
+ <key>NSAppleScriptEnabled</key>
164
+ <false/>
165
+ <key>CFBundleDocumentTypes</key>
166
+ <array/>
167
+ <key>NSPrincipalClass</key>
168
+ <string>NSApplication</string>
169
+ </dict>
170
+ </plist>'''
171
+
172
+ plist_path = self.app_bundle_path / "Contents" / "Info.plist"
173
+ plist_path.write_text(plist_content)
174
+ return True
175
+
176
+ except Exception as e:
177
+ print(f"Error creating Info.plist: {e}")
178
+ return False
179
+
180
+ def create_launch_script(self) -> bool:
181
+ """Create the executable launch script."""
182
+ try:
183
+ script_content = '''#!/bin/bash
184
+
185
+ # AbstractAssistant macOS App Launcher
186
+ # This script launches the AbstractAssistant application
187
+
188
+ # Find the Python executable and package
189
+ PYTHON_EXEC="$(which python3)"
190
+ if [ -z "$PYTHON_EXEC" ]; then
191
+ PYTHON_EXEC="$(which python)"
192
+ fi
193
+
194
+ if [ -z "$PYTHON_EXEC" ]; then
195
+ echo "Error: Python not found in PATH"
196
+ exit 1
197
+ fi
198
+
199
+ # Launch the assistant
200
+ exec "$PYTHON_EXEC" -m abstractassistant.cli "$@"'''
201
+
202
+ script_path = self.app_bundle_path / "Contents" / "MacOS" / "AbstractAssistant"
203
+ script_path.write_text(script_content)
204
+
205
+ # Make executable
206
+ os.chmod(script_path, 0o755)
207
+ return True
208
+
209
+ except Exception as e:
210
+ print(f"Error creating launch script: {e}")
211
+ return False
212
+
213
+ def generate_app_bundle(self) -> bool:
214
+ """Generate the complete macOS app bundle."""
215
+ if not self.is_macos():
216
+ print("macOS app bundle generation is only available on macOS")
217
+ return False
218
+
219
+ if not self.has_permissions():
220
+ print("Insufficient permissions to create app bundle in /Applications")
221
+ print("Please run with sudo or manually copy the app bundle")
222
+ return False
223
+
224
+ print("Creating macOS app bundle...")
225
+
226
+ # Remove existing bundle if it exists
227
+ if self.app_bundle_path.exists():
228
+ shutil.rmtree(self.app_bundle_path)
229
+
230
+ # Create bundle structure
231
+ if not self.create_app_bundle_structure():
232
+ return False
233
+
234
+ # Generate icon
235
+ if not self.generate_app_icon():
236
+ return False
237
+
238
+ # Create Info.plist
239
+ if not self.create_info_plist():
240
+ return False
241
+
242
+ # Create launch script
243
+ if not self.create_launch_script():
244
+ return False
245
+
246
+ print(f"✅ macOS app bundle created successfully!")
247
+ print(f" Location: {self.app_bundle_path}")
248
+ print(f" You can now launch AbstractAssistant from the Dock!")
249
+
250
+ return True
251
+
252
+
253
+ def create_macos_app_bundle():
254
+ """Main function to create macOS app bundle during installation."""
255
+ try:
256
+ # Find the package directory
257
+ package_dir = Path(__file__).parent
258
+
259
+ generator = MacOSAppBundleGenerator(package_dir)
260
+ return generator.generate_app_bundle()
261
+
262
+ except Exception as e:
263
+ print(f"Error creating macOS app bundle: {e}")
264
+ return False
265
+
266
+
267
+ if __name__ == "__main__":
268
+ success = create_macos_app_bundle()
269
+ sys.exit(0 if success else 1)
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- assistant = abstractassistant.cli:main