-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathchat.py
202 lines (166 loc) · 7.24 KB
/
chat.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# Copyright (c) Microsoft. All rights reserved.
# An example for building a simple message echo assistant using the AssistantApp from
# the semantic-workbench-assistant package.
#
# This example demonstrates how to use the AssistantApp to create a chat assistant,
# to add additional configuration fields and UI schema for the configuration fields,
# and to handle conversation events to respond to messages in the conversation.
# region Required
#
# The code in this region demonstrates the minimal code required to create a chat assistant
# using the AssistantApp class from the semantic-workbench-assistant package. This code
# demonstrates how to create an AssistantApp instance, define the service ID, name, and
# description, and create the FastAPI app instance. Start here to build your own chat
# assistant using the AssistantApp class.
#
# The code that follows this region is optional and demonstrates how to add event handlers
# to respond to conversation events. You can use this code as a starting point for building
# your own chat assistant with additional functionality.
#
import logging
from typing import Any
from semantic_workbench_api_model.workbench_model import (
ConversationEvent,
ConversationMessage,
MessageType,
NewConversationMessage,
UpdateParticipant,
)
from semantic_workbench_assistant.assistant_app import (
AlwaysWarnContentSafetyEvaluator,
AssistantApp,
BaseModelAssistantConfig,
ContentSafety,
ConversationContext,
)
from .config import AssistantConfigModel
logger = logging.getLogger(__name__)
#
# define the service ID, name, and description
#
# the service id to be registered in the workbench to identify the assistant
service_id = "python-01-echo-bot.workbench-explorer"
# the name of the assistant service, as it will appear in the workbench UI
service_name = "Python Example 01: Echo Bot"
# a description of the assistant service, as it will appear in the workbench UI
service_description = "A starter for building a chat assistant using the Semantic Workbench Assistant SDK."
#
# create the configuration provider, using the extended configuration model
#
assistant_config = BaseModelAssistantConfig(AssistantConfigModel)
content_safety = ContentSafety(AlwaysWarnContentSafetyEvaluator.factory)
# create the AssistantApp instance
assistant = AssistantApp(
assistant_service_id=service_id,
assistant_service_name=service_name,
assistant_service_description=service_description,
config_provider=assistant_config.provider,
)
#
# create the FastAPI app instance
#
app = assistant.fastapi_app()
# endregion
# region Optional
#
# Note: The code in this region is specific to this example and is not required for a basic assistant.
#
# The AssistantApp class provides a set of decorators for adding event handlers to respond to conversation
# events. In VS Code, typing "@assistant." (or the name of your AssistantApp instance) will show available
# events and methods.
#
# See the semantic-workbench-assistant AssistantApp class for more information on available events and methods.
# Examples:
# - @assistant.events.conversation.on_created (event triggered when the assistant is added to a conversation)
# - @assistant.events.conversation.participant.on_created (event triggered when a participant is added)
# - @assistant.events.conversation.message.on_created (event triggered when a new message of any type is created)
# - @assistant.events.conversation.message.chat.on_created (event triggered when a new chat message is created)
#
@assistant.events.conversation.message.chat.on_created
async def on_message_created(
context: ConversationContext, event: ConversationEvent, message: ConversationMessage
) -> None:
"""
Handle the event triggered when a new chat message is created in the conversation.
**Note**
- This event handler is specific to chat messages.
- To handle other message types, you can add additional event handlers for those message types.
- @assistant.events.conversation.message.log.on_created
- @assistant.events.conversation.message.command.on_created
- ...additional message types
- To handle all message types, you can use the root event handler for all message types:
- @assistant.events.conversation.message.on_created
"""
# ignore messages from this assistant
if message.sender.participant_id == context.assistant.id:
return
# update the participant status to indicate the assistant is thinking
await context.update_participant_me(UpdateParticipant(status="thinking..."))
try:
# replace the following with your own logic for processing a message created event
await respond_to_conversation(
context,
message=message,
metadata={"debug": {"content_safety": event.data.get(content_safety.metadata_key, {})}},
)
finally:
# update the participant status to indicate the assistant is done thinking
await context.update_participant_me(UpdateParticipant(status=None))
# Handle the event triggered when the assistant is added to a conversation.
@assistant.events.conversation.on_created
async def on_conversation_created(context: ConversationContext) -> None:
"""
Handle the event triggered when the assistant is added to a conversation.
"""
# replace the following with your own logic for processing a conversation created event
# get the assistant's configuration
config = await assistant_config.get(context.assistant)
# get the welcome message from the assistant's configuration
welcome_message = config.welcome_message
# send the welcome message to the conversation
await context.send_messages(
NewConversationMessage(
content=welcome_message,
message_type=MessageType.chat,
metadata={"generated_content": False},
)
)
# endregion
# region Custom
#
# This code was added specifically for this example to demonstrate how to respond to conversation
# messages simply echoing back the input message. For your own assistant, you could replace this
# code with your own logic for responding to conversation messages and add any additional
# functionality as needed.
#
# demonstrates how to respond to a conversation message echoing back the input message
async def respond_to_conversation(
context: ConversationContext, message: ConversationMessage, metadata: dict[str, Any] = {}
) -> None:
"""
Respond to a conversation message.
"""
# get the assistant's configuration
config = await assistant_config.get(context.assistant)
# send a new message with the echo response
await context.send_messages(
NewConversationMessage(
content=f"echo: {message.content}",
message_type=MessageType.chat,
# add debug metadata if debug output is enabled
# any content in the debug property on the metadata
# will be displayed in the workbench UI for inspection
metadata=(
{
"debug": {
"source": "echo",
"original_message": message,
**metadata,
}
}
if config.enable_debug_output
else metadata
),
)
)
# endregion