-
Couldn't load subscription status.
- Fork 4
Add avatar path support for personas #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
0b8dc05
0460b68
03abc2d
e250e3f
df09c6c
fac6f66
bea930c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,82 @@ | ||
| import json | ||
| import mimetypes | ||
| import os | ||
| from functools import lru_cache | ||
| from typing import Optional | ||
|
|
||
| from jupyter_server.base.handlers import APIHandler | ||
| from jupyter_server.base.handlers import JupyterHandler | ||
| import tornado | ||
|
|
||
| class RouteHandler(APIHandler): | ||
|
|
||
| class RouteHandler(JupyterHandler): | ||
Zsailer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # The following decorator should be present on all verb methods (head, get, post, | ||
| # patch, put, delete, options) to ensure only authorized user can request the | ||
| # Jupyter server | ||
| @tornado.web.authenticated | ||
| def get(self): | ||
| self.set_header("Content-Type", "application/json") | ||
| self.finish(json.dumps({ | ||
| "data": "This is /jupyter-ai-persona-manager/get-example endpoint!" | ||
| })) | ||
|
|
||
|
|
||
| class AvatarHandler(JupyterHandler): | ||
| """ | ||
| Handler for serving persona avatar files. | ||
| Looks up avatar files through the PersonaManager to find the correct file path, | ||
| then serves the file with appropriate content-type headers. | ||
| """ | ||
|
|
||
| @tornado.web.authenticated | ||
| async def get(self, filename: str): | ||
Zsailer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """Serve an avatar file by filename.""" | ||
| # Get the avatar file path from persona managers | ||
| avatar_path = self._find_avatar_file(filename) | ||
|
||
|
|
||
| if avatar_path is None: | ||
| raise tornado.web.HTTPError(404, f"Avatar file not found: {filename}") | ||
|
|
||
| # Serve the file | ||
| try: | ||
| # Set content type based on file extension | ||
| content_type, _ = mimetypes.guess_type(avatar_path) | ||
| if content_type: | ||
| self.set_header("Content-Type", content_type) | ||
|
|
||
| # Read and serve the file | ||
| with open(avatar_path, 'rb') as f: | ||
Zsailer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| content = f.read() | ||
| self.write(content) | ||
|
|
||
| await self.finish() | ||
| except Exception as e: | ||
| self.log.error(f"Error serving avatar file {filename}: {e}") | ||
| raise tornado.web.HTTPError(500, f"Error serving avatar file: {str(e)}") | ||
|
|
||
| @lru_cache(maxsize=128) | ||
|
||
| def _find_avatar_file(self, filename: str) -> Optional[str]: | ||
| """ | ||
| Find the avatar file path by searching through all persona managers. | ||
| Uses LRU cache to avoid repeated lookups for the same filename. | ||
| """ | ||
| # Get all persona managers from settings | ||
| persona_managers = self.settings.get('jupyter-ai', {}).get('persona-managers', {}) | ||
|
|
||
| for room_id, persona_manager in persona_managers.items(): | ||
| # Check each persona's avatar path | ||
| for persona in persona_manager.personas.values(): | ||
| try: | ||
| avatar_path = persona.defaults.avatar_path | ||
Zsailer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if avatar_path and os.path.basename(avatar_path) == filename: | ||
| # Found a match, return the absolute path | ||
| if os.path.exists(avatar_path): | ||
| return avatar_path | ||
| else: | ||
| self.log.warning(f"Avatar file not found at path: {avatar_path}") | ||
| except Exception as e: | ||
| self.log.warning(f"Error checking avatar for persona {persona.name}: {e}") | ||
| continue | ||
|
|
||
| return None | ||
Uh oh!
There was an error while loading. Please reload this page.