1
- import logging
1
+ import os
2
2
import re
3
3
import time
4
4
5
5
from dask .distributed import Client as DaskClient
6
6
from importlib_metadata import entry_points
7
7
from jupyter_ai .chat_handlers .learn import Retriever
8
+ from jupyter_ai_magics import JupyternautPersona
8
9
from jupyter_ai_magics .utils import get_em_providers , get_lm_providers
9
10
from jupyter_server .extension .application import ExtensionApp
11
+ from tornado .web import StaticFileHandler
10
12
from traitlets import Dict , List , Unicode
11
13
12
14
from .chat_handlers import (
18
20
HelpChatHandler ,
19
21
LearnChatHandler ,
20
22
)
21
- from .chat_handlers .help import HelpMessage
23
+ from .chat_handlers .help import build_help_message
22
24
from .completions .handlers import DefaultInlineCompletionHandler
23
25
from .config_manager import ConfigManager
24
26
from .handlers import (
30
32
RootChatHandler ,
31
33
)
32
34
35
+ JUPYTERNAUT_AVATAR_ROUTE = JupyternautPersona .avatar_route
36
+ JUPYTERNAUT_AVATAR_PATH = str (
37
+ os .path .join (os .path .dirname (__file__ ), "static" , "jupyternaut.svg" )
38
+ )
39
+
33
40
34
41
class AiExtension (ExtensionApp ):
35
42
name = "jupyter_ai"
@@ -41,6 +48,14 @@ class AiExtension(ExtensionApp):
41
48
(r"api/ai/providers?" , ModelProviderHandler ),
42
49
(r"api/ai/providers/embeddings?" , EmbeddingsModelProviderHandler ),
43
50
(r"api/ai/completion/inline/?" , DefaultInlineCompletionHandler ),
51
+ # serve the default persona avatar at this path.
52
+ # the `()` at the end of the URL denotes an empty regex capture group,
53
+ # required by Tornado.
54
+ (
55
+ rf"{ JUPYTERNAUT_AVATAR_ROUTE } ()" ,
56
+ StaticFileHandler ,
57
+ {"path" : JUPYTERNAUT_AVATAR_PATH },
58
+ ),
44
59
]
45
60
46
61
allowed_providers = List (
@@ -303,14 +318,36 @@ def initialize_settings(self):
303
318
# Make help always appear as the last command
304
319
jai_chat_handlers ["/help" ] = help_chat_handler
305
320
306
- self .settings ["chat_history" ].append (
307
- HelpMessage (chat_handlers = jai_chat_handlers )
308
- )
321
+ # bind chat handlers to settings
309
322
self .settings ["jai_chat_handlers" ] = jai_chat_handlers
310
323
324
+ # show help message at server start
325
+ self ._show_help_message ()
326
+
311
327
latency_ms = round ((time .time () - start ) * 1000 )
312
328
self .log .info (f"Initialized Jupyter AI server extension in { latency_ms } ms." )
313
329
330
+ def _show_help_message (self ):
331
+ """
332
+ Method that ensures a dynamically-generated help message is included in
333
+ the chat history shown to users.
334
+ """
335
+ chat_handlers = self .settings ["jai_chat_handlers" ]
336
+ config_manager : ConfigManager = self .settings ["jai_config_manager" ]
337
+ lm_provider = config_manager .lm_provider
338
+
339
+ if not lm_provider :
340
+ return
341
+
342
+ persona = config_manager .persona
343
+ unsupported_slash_commands = (
344
+ lm_provider .unsupported_slash_commands if lm_provider else set ()
345
+ )
346
+ help_message = build_help_message (
347
+ chat_handlers , persona , unsupported_slash_commands
348
+ )
349
+ self .settings ["chat_history" ].append (help_message )
350
+
314
351
async def _get_dask_client (self ):
315
352
return DaskClient (processes = False , asynchronous = True )
316
353
0 commit comments