chengzhiedu commited on
Commit
c2ab585
·
1 Parent(s): a771506

feat(ui): opening message in chat

Browse files
SEL/assistant_config.py CHANGED
@@ -1,6 +1,10 @@
1
 
2
  ASSISTANT_MODEL = "gpt-4o-mini"
3
  ASSISTANT_NAME = "陪你師展魔法-Coach Chat"
 
 
 
 
4
  ASSISTANT_DESCRIPTION = "協助台灣國中小教師運用KIST方法,提供微時刻對話、班級經營建議與親師溝通技巧。"
5
  ASSISTANT_INSTRUCTION = """
6
  你是一位 **專為台灣公立國中小老師設計的 AI 班級經營顧問/SEL 教練**。
 
1
 
2
  ASSISTANT_MODEL = "gpt-4o-mini"
3
  ASSISTANT_NAME = "陪你師展魔法-Coach Chat"
4
+ ASSISTANT_OPENING = """嗨,我是你的 SEL 陪伴教練。最近在和孩子互動時,有沒有哪個狀況,讓你感到特別困擾或疲憊?
5
+
6
+ 如果一時想不到,也可以參考一下這些例子:像是學生說謊、不交作業、上課不專心、頂嘴、冷漠……你覺得哪個最貼近?
7
+ """
8
  ASSISTANT_DESCRIPTION = "協助台灣國中小教師運用KIST方法,提供微時刻對話、班級經營建議與親師溝通技巧。"
9
  ASSISTANT_INSTRUCTION = """
10
  你是一位 **專為台灣公立國中小老師設計的 AI 班級經營顧問/SEL 教練**。
app/config/base.py CHANGED
@@ -12,6 +12,7 @@ class AppName:
12
  REQUIRED_ATTRIBUTES: Set[str] = {
13
  'ASSISTANT_MODEL',
14
  'ASSISTANT_NAME',
 
15
  'ASSISTANT_DESCRIPTION',
16
  'ASSISTANT_INSTRUCTION',
17
  'RESPONSE_FORMAT',
@@ -30,10 +31,10 @@ CONFIG_MAPPING: Dict[str, str] = {
30
  def validate_config(config: Type) -> tuple[bool, list[str]]:
31
  """
32
  Validate that the config has all required attributes.
33
-
34
  Args:
35
  config: The configuration module to validate
36
-
37
  Returns:
38
  tuple[bool, list[str]]: (is_valid, list of missing attributes)
39
  """
@@ -44,29 +45,29 @@ def get_app_name_and_config() -> tuple[str, Type]:
44
  """
45
  Get the appropriate configuration module based on APP_NAME.
46
  Validates that the config has all required attributes.
47
-
48
  Returns:
49
  Type: The configuration module
50
-
51
  Raises:
52
  ImportError: If the config module cannot be imported
53
  ValueError: If the config is missing required attributes
54
  """
55
  app_name = os.getenv('app_name')
56
  config_path = CONFIG_MAPPING.get(app_name, CONFIG_MAPPING['default'])
57
-
58
  try:
59
  config = importlib.import_module(config_path)
60
  except ImportError as e:
61
  print(f"Error importing config {config_path}: {e}")
62
  config = importlib.import_module(CONFIG_MAPPING['default'])
63
-
64
  # Validate the config
65
  is_valid, missing_attrs = validate_config(config)
66
  if not is_valid:
67
  error_msg = f"Config {config_path} is missing required attributes: {missing_attrs}"
68
  print(f"Warning: {error_msg}")
69
-
70
  # Try to load default config if current config is invalid
71
  if config_path != CONFIG_MAPPING['default']:
72
  print("Attempting to load default config...")
@@ -77,5 +78,5 @@ def get_app_name_and_config() -> tuple[str, Type]:
77
  return default_config
78
  else:
79
  raise ValueError(error_msg)
80
-
81
- return app_name, config
 
12
  REQUIRED_ATTRIBUTES: Set[str] = {
13
  'ASSISTANT_MODEL',
14
  'ASSISTANT_NAME',
15
+ 'ASSISTANT_OPENING',
16
  'ASSISTANT_DESCRIPTION',
17
  'ASSISTANT_INSTRUCTION',
18
  'RESPONSE_FORMAT',
 
31
  def validate_config(config: Type) -> tuple[bool, list[str]]:
32
  """
33
  Validate that the config has all required attributes.
34
+
35
  Args:
36
  config: The configuration module to validate
37
+
38
  Returns:
39
  tuple[bool, list[str]]: (is_valid, list of missing attributes)
40
  """
 
45
  """
46
  Get the appropriate configuration module based on APP_NAME.
47
  Validates that the config has all required attributes.
48
+
49
  Returns:
50
  Type: The configuration module
51
+
52
  Raises:
53
  ImportError: If the config module cannot be imported
54
  ValueError: If the config is missing required attributes
55
  """
56
  app_name = os.getenv('app_name')
57
  config_path = CONFIG_MAPPING.get(app_name, CONFIG_MAPPING['default'])
58
+
59
  try:
60
  config = importlib.import_module(config_path)
61
  except ImportError as e:
62
  print(f"Error importing config {config_path}: {e}")
63
  config = importlib.import_module(CONFIG_MAPPING['default'])
64
+
65
  # Validate the config
66
  is_valid, missing_attrs = validate_config(config)
67
  if not is_valid:
68
  error_msg = f"Config {config_path} is missing required attributes: {missing_attrs}"
69
  print(f"Warning: {error_msg}")
70
+
71
  # Try to load default config if current config is invalid
72
  if config_path != CONFIG_MAPPING['default']:
73
  print("Attempting to load default config...")
 
78
  return default_config
79
  else:
80
  raise ValueError(error_msg)
81
+
82
+ return app_name, config
app/main.py CHANGED
@@ -32,6 +32,7 @@ existed_assistants = client.beta.assistants.list(
32
  assistant_id = os.getenv('assistant_id')
33
  ASSISTANT_MODEL = active_config.ASSISTANT_MODEL
34
  ASSISTANT_NAME = active_config.ASSISTANT_NAME
 
35
  ASSISTANT_DESCRIPTION = active_config.ASSISTANT_DESCRIPTION
36
  ASSISTANT_INSTRUCTION = active_config.ASSISTANT_INSTRUCTION
37
  RESPONSE_FORMAT = active_config.RESPONSE_FORMAT
@@ -106,7 +107,11 @@ def handle_new_chat(user_id, session_state):
106
 
107
  def handle_page_load(username, session_state):
108
  """Handle page load - reset chat and update selector"""
109
- return chat_manager.reset_chat_on_load(username, session_state)
 
 
 
 
110
 
111
  # Main UI
112
  with gr.Blocks(
@@ -184,7 +189,8 @@ with gr.Blocks(
184
  with gr.Column():
185
  chatbot.render()
186
  prompt_input.render()
187
- quick_response.render()
 
188
  hidden_list.render()
189
  with gr.Column(elem_classes="full-height", visible=SHOW_CANVAS) as textbox_column:
190
  textbox.render()
 
32
  assistant_id = os.getenv('assistant_id')
33
  ASSISTANT_MODEL = active_config.ASSISTANT_MODEL
34
  ASSISTANT_NAME = active_config.ASSISTANT_NAME
35
+ ASSISTANT_OPENING = active_config.ASSISTANT_OPENING
36
  ASSISTANT_DESCRIPTION = active_config.ASSISTANT_DESCRIPTION
37
  ASSISTANT_INSTRUCTION = active_config.ASSISTANT_INSTRUCTION
38
  RESPONSE_FORMAT = active_config.RESPONSE_FORMAT
 
107
 
108
  def handle_page_load(username, session_state):
109
  """Handle page load - reset chat and update selector"""
110
+ init_chat = []
111
+ if ASSISTANT_OPENING: # 檢查字串是否非空
112
+ init_chat.append({'role': 'assistant', 'content': ASSISTANT_OPENING})
113
+
114
+ return chat_manager.reset_chat_on_load(username, session_state, init_chat)
115
 
116
  # Main UI
117
  with gr.Blocks(
 
189
  with gr.Column():
190
  chatbot.render()
191
  prompt_input.render()
192
+ # for K camp test path, allow users to start directly
193
+ # quick_response.render()
194
  hidden_list.render()
195
  with gr.Column(elem_classes="full-height", visible=SHOW_CANVAS) as textbox_column:
196
  textbox.render()
app/utils/chat.py CHANGED
@@ -35,13 +35,13 @@ class ChatManager:
35
  current_chat_id = self.create_new_chat(session_state)
36
  return current_chat_id
37
 
38
- def reset_chat_on_load(self, username: str, session_state) -> Tuple[gr.update, list]:
39
  """Reset chat ID on page load and update chat selector"""
40
  self.create_new_chat(session_state)
41
-
42
  # Update chat selector with available chats for this user
43
  chats = self.list_user_chats(username)
44
- return gr.update(choices=[(c["preview"], c["chat_id"]) for c in chats], value=self.get_current_chat_id(session_state)), []
45
 
46
  def load_chat_history(self, user_id="default_user"):
47
  """Load chat history for a user"""
@@ -56,13 +56,13 @@ class ChatManager:
56
  .select("chat_id,last_updated,messages") \
57
  .eq("user_id", user_id) \
58
  .execute()
59
-
60
  chats = [{
61
  "chat_id": chat["chat_id"],
62
  "last_updated": chat["last_updated"],
63
  "preview": chat["messages"][0]["content"] if chat["messages"] else "Empty chat"
64
  } for chat in response.data]
65
-
66
  return sorted(chats, key=lambda x: x["last_updated"], reverse=True)
67
 
68
  def switch_chat(self, chat_id, user_id="default_user", session_state=None):
@@ -71,7 +71,7 @@ class ChatManager:
71
  self.set_current_chat_id(session_state, chat_id)
72
  messages = self.load_chat(user_id, chat_id)
73
  return messages
74
-
75
  def save_chat(self, user_id, chat_id, messages, current_lesson_plan, app_name):
76
  """Save chat history to Supabase"""
77
  chat_data = {
@@ -82,7 +82,7 @@ class ChatManager:
82
  "current_lesson_plan": current_lesson_plan,
83
  "app_name": app_name
84
  }
85
-
86
  # Check if chat exists
87
  existing_chat = self.supabase.table("chats") \
88
  .select("*") \
@@ -110,7 +110,7 @@ class ChatManager:
110
  .eq("user_id", user_id) \
111
  .eq("chat_id", chat_id) \
112
  .execute()
113
-
114
  return response.data[0]["messages"] if response.data else []
115
 
116
  def get_latest_chat_id(self, user_id):
 
35
  current_chat_id = self.create_new_chat(session_state)
36
  return current_chat_id
37
 
38
+ def reset_chat_on_load(self, username: str, session_state, init_chat=[]) -> Tuple[gr.update, list]:
39
  """Reset chat ID on page load and update chat selector"""
40
  self.create_new_chat(session_state)
41
+
42
  # Update chat selector with available chats for this user
43
  chats = self.list_user_chats(username)
44
+ return gr.update(choices=[(c["preview"], c["chat_id"]) for c in chats], value=self.get_current_chat_id(session_state)), init_chat
45
 
46
  def load_chat_history(self, user_id="default_user"):
47
  """Load chat history for a user"""
 
56
  .select("chat_id,last_updated,messages") \
57
  .eq("user_id", user_id) \
58
  .execute()
59
+
60
  chats = [{
61
  "chat_id": chat["chat_id"],
62
  "last_updated": chat["last_updated"],
63
  "preview": chat["messages"][0]["content"] if chat["messages"] else "Empty chat"
64
  } for chat in response.data]
65
+
66
  return sorted(chats, key=lambda x: x["last_updated"], reverse=True)
67
 
68
  def switch_chat(self, chat_id, user_id="default_user", session_state=None):
 
71
  self.set_current_chat_id(session_state, chat_id)
72
  messages = self.load_chat(user_id, chat_id)
73
  return messages
74
+
75
  def save_chat(self, user_id, chat_id, messages, current_lesson_plan, app_name):
76
  """Save chat history to Supabase"""
77
  chat_data = {
 
82
  "current_lesson_plan": current_lesson_plan,
83
  "app_name": app_name
84
  }
85
+
86
  # Check if chat exists
87
  existing_chat = self.supabase.table("chats") \
88
  .select("*") \
 
110
  .eq("user_id", user_id) \
111
  .eq("chat_id", chat_id) \
112
  .execute()
113
+
114
  return response.data[0]["messages"] if response.data else []
115
 
116
  def get_latest_chat_id(self, user_id):