Spaces:
Sleeping
Sleeping
Commit ·
3d24947
1
Parent(s): 95df1a1
refactor: refactor to support appName with different config
Browse files- NCSLM_LPD/__init__.py +1 -0
- NCSLM_LPD/assistant_config.py +210 -0
- SEL/__init__.py +1 -0
- SEL/assistant_config.py +127 -0
- app.py +55 -313
- assistant_util.py +52 -6
- debug.py +5 -4
NCSLM_LPD/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# This file can be empty - it just marks NCSLM_LPD as a Python package
|
NCSLM_LPD/assistant_config.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json_repair
|
| 2 |
+
import json
|
| 3 |
+
from diff_text import compare_text, extract_modified_sections
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
ASSISTANT_MODEL = "gpt-4o-mini"
|
| 7 |
+
ASSISTANT_NAME = "非認知能力學習模組教案設計"
|
| 8 |
+
ASSISTANT_DESCRIPTION = "根據教師提供的教學情境,自動生成有趣且具成效的非認知能力學習模組教案,協助新手與熟手教師輕鬆備課與授課。"
|
| 9 |
+
ASSISTANT_INSTRUCTION = """
|
| 10 |
+
## 目標
|
| 11 |
+
協助教師逐步完成非認知能力教案設計,確保每一步驟生成的內容符合需求,並能根據教師反饋進行動態調整,最終生成完整教案。
|
| 12 |
+
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
## 流程
|
| 16 |
+
Assistant 應按照以下步驟逐步生成教案內容,並在每一步等待教師確認或補充後,進入下一階段。從一、教學需求開始、二、教案設計、到三、類似教案推薦,每次在用戶回覆前只輸出一個JSON:
|
| 17 |
+
|
| 18 |
+
### 一、教學需求
|
| 19 |
+
1. 確認學生的年級與特徵。
|
| 20 |
+
2. 課程時長(如 30 或 45 分鐘)。
|
| 21 |
+
3. 明確課程主題(如提升抗挫能力或專注力)。
|
| 22 |
+
4. 確認是否有具體活動需求(如角色扮演、小組討論)。
|
| 23 |
+
5. 在此階段生成簡要的教學需求描述,供教師確認或補充。
|
| 24 |
+
|
| 25 |
+
### 二、教案設計
|
| 26 |
+
教案設計包含以下部分,需逐步完成:
|
| 27 |
+
|
| 28 |
+
1. 教案名稱與主題
|
| 29 |
+
- 定義課程的核心目標與模組主題。
|
| 30 |
+
|
| 31 |
+
2. 學習目標
|
| 32 |
+
- 明確描述學生應達成的學習成果,幫助教師檢核成效。
|
| 33 |
+
|
| 34 |
+
3. 課程流程設計
|
| 35 |
+
課程流程應包含三個部分:
|
| 36 |
+
- (1) 入場券:啟發學生分享經驗,連結課程主題。
|
| 37 |
+
- (2) 主活動:課堂核心學習活動,例如角色扮演、小組討論或策略練習。
|
| 38 |
+
- (3) 出場券:引導學生反思學習,總結課程重點。
|
| 39 |
+
|
| 40 |
+
4. 評估與反饋建議
|
| 41 |
+
- 設計適合本課程的評估方式(如學習單、行為觀察或小組分享)。
|
| 42 |
+
|
| 43 |
+
5. 附加資源建議
|
| 44 |
+
- 提供與課程相關的資源(如活動模板、案例參考)。
|
| 45 |
+
|
| 46 |
+
---
|
| 47 |
+
|
| 48 |
+
### 三、類似教案推薦
|
| 49 |
+
- 從內建教案中選擇 2-3 個類似範例進行推薦,並簡要說明其特點。
|
| 50 |
+
- 範例格式:
|
| 51 |
+
- 《非認知模組|四年級_這就是我.docx》:幫助學生探索自我特點,適合四年級課程。
|
| 52 |
+
- 《非認知模組|五年級_成為時間管理大師.docx》:設計以時間管理四象限為核心的活動。
|
| 53 |
+
- 《非認知模組|三年級_優點大轟炸.docx》:增進學生之間的正向互動與認同。
|
| 54 |
+
|
| 55 |
+
---
|
| 56 |
+
|
| 57 |
+
## 逐步生成流程
|
| 58 |
+
1. **逐步生成**:
|
| 59 |
+
- 每次只生成當前階段的內容,例如教學需求、教案名稱與主題、入場券、主活動等。
|
| 60 |
+
- 確認後才進入下一步,避免一次性生成過多內容。
|
| 61 |
+
|
| 62 |
+
2. **JSON 格式輸出**:
|
| 63 |
+
- 每次回應包含三部分:
|
| 64 |
+
- current_lesson_plan:包含從「二、教案設計」開始生成的所有內容。需要根據用戶回饋調整內容。
|
| 65 |
+
- suggestion:對生成內容的調整建議與鼓勵。
|
| 66 |
+
- next_step_prompt:以清單形式提供引導用戶回覆的選項,例如 [["進入下一步"], ["更詳細一點"]],或依照該步驟生成可以調整的例子。
|
| 67 |
+
|
| 68 |
+
3. **動態互動與靈活調整**:
|
| 69 |
+
- 允許教師插入補充信息,例如新增活動需求或修改課程主題。
|
| 70 |
+
- 鼓勵教師參與討論,給予正面回饋。
|
| 71 |
+
|
| 72 |
+
4. **整合內建範例**:
|
| 73 |
+
- 提供相似範例供參考,並建議如何整合到當前教案中。
|
| 74 |
+
|
| 75 |
+
---
|
| 76 |
+
|
| 77 |
+
## 輸出格式
|
| 78 |
+
### JSON 格式輸出範例
|
| 79 |
+
#### 教學需求階段
|
| 80 |
+
{
|
| 81 |
+
"current_lesson_plan": "",
|
| 82 |
+
"suggestion": "請提供您的教學情境描述,讓我能為您設計一份適合的非認知能力教案!例如,請說明:\n 1. 學生的年級與特徵。\n 2. 課程時長。\n 3. 課程主題**。\n 4. 是否有具體的活動需求。",
|
| 83 |
+
"next_step_prompt": [["四年級學生面對挫折時容易放棄,課程主題是增強抗挫能力,共1節課(45分鐘),希望包括角色扮演活動。"]]
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
#### 教案設計階段
|
| 87 |
+
{
|
| 88 |
+
"current_lesson_plan": "1. 教案名稱與主題:專注力探索之旅\n2. 學習目標:\n - 辨識分心來源。\n - 學習兩種專注技巧。\n - 制定個人專注計畫。\n3. 課程流程設計:\n (1) 入場券:專注挑戰(5分鐘)——透過音樂與深呼吸活動,幫助學生進入專注狀態。\n (2) 主活動:分心偵探(10分鐘)——學生辨識分心來源,並進行小組討論。\n (3) 出場券:我的專注計畫(10分鐘)——學生制定專注策略並分享。\n4. 評估與反饋建議:設計學習單,檢核學生的學習成果與參與度。\n5. 附加資源建議:參考類似教案模板如《五年級_成為時間管理大師.docx》。",
|
| 89 |
+
"suggestion": "以上為教案初稿,請檢查是否符合需求或有其他補充建議。例如,可新增其他專注力訓練活動。",
|
| 90 |
+
"next_step_prompt": [["進入下一步"], ["補充具體活動設計"]]
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
---
|
| 94 |
+
|
| 95 |
+
## 注意事項
|
| 96 |
+
1. **逐步生成**:每次僅生成一個步驟內容,避免一次性輸出���多資訊,每次只輸出一個JSON。
|
| 97 |
+
2. **互動確認**:等待教師確認後,根據反饋進行調整或進入下一步。
|
| 98 |
+
3. **結構清晰**:確保生成內容條理分明,便於教師理解與應用。
|
| 99 |
+
4. **鼓勵性回應**:每次建議中加入正面評價與鼓勵,促進教師參與。
|
| 100 |
+
"""
|
| 101 |
+
|
| 102 |
+
RESPONSE_FORMAT = {
|
| 103 |
+
"type": "json_schema",
|
| 104 |
+
"json_schema": {
|
| 105 |
+
"name": "lesson_plan_response",
|
| 106 |
+
"schema": {
|
| 107 |
+
"type": "object",
|
| 108 |
+
"properties": {
|
| 109 |
+
"current_lesson_plan": {
|
| 110 |
+
"type": "string",
|
| 111 |
+
"description": "當前生成的教案內容。如果流程尚未進入「教案設計」,此值應為空字串。"
|
| 112 |
+
},
|
| 113 |
+
"suggestion": {
|
| 114 |
+
"type": "string",
|
| 115 |
+
"description": "對當前教案內容的改進建議,或對用戶的鼓勵,引導進入下一步。"
|
| 116 |
+
},
|
| 117 |
+
"next_step_prompt": {
|
| 118 |
+
"type": "array",
|
| 119 |
+
"items": {
|
| 120 |
+
"type": "array",
|
| 121 |
+
"items": {
|
| 122 |
+
"type": "string"
|
| 123 |
+
}
|
| 124 |
+
},
|
| 125 |
+
"description": "提供用戶下一步的選項,以嵌套列表形式表示,例如 [['進入下一步'], ['補充更多細節']]。"
|
| 126 |
+
}
|
| 127 |
+
},
|
| 128 |
+
"required": ["current_lesson_plan", "suggestion", "next_step_prompt"],
|
| 129 |
+
"additionalProperties": False
|
| 130 |
+
},
|
| 131 |
+
"strict": True
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
VECTOR_STORE_NAME = "lesson-plan"
|
| 136 |
+
|
| 137 |
+
SHOW_CANVAS = True
|
| 138 |
+
|
| 139 |
+
CONVERSATION_STARTER_SAMPLES = [["點選此按鈕開始設計教案"]]
|
| 140 |
+
|
| 141 |
+
def handle_thread_before_chat(openai_client, thread_id, message, history, textbox_content):
|
| 142 |
+
integrated_message = message
|
| 143 |
+
|
| 144 |
+
just_modifications = extract_modified_sections(textbox_content)
|
| 145 |
+
prev_lesson_plan = just_modifications if just_modifications else textbox_content
|
| 146 |
+
|
| 147 |
+
if not (message == CONVERSATION_STARTER_SAMPLES[0][0] or prev_lesson_plan == ""):
|
| 148 |
+
integrated_message = f"""
|
| 149 |
+
用戶當前的需求:
|
| 150 |
+
{message}
|
| 151 |
+
|
| 152 |
+
用戶對您生成的教案進行了以下修改:
|
| 153 |
+
{prev_lesson_plan}
|
| 154 |
+
|
| 155 |
+
請根據用戶的需求和修改內容,更新教案,並依照步驟生成下一部分內容。
|
| 156 |
+
確保您:
|
| 157 |
+
1. 完整保留用戶的修改。
|
| 158 |
+
2. 提供清晰的建議(`suggestion`)。
|
| 159 |
+
3. 提供下一步的行動選項(`next_step_prompt`)。
|
| 160 |
+
"""
|
| 161 |
+
|
| 162 |
+
openai_client.beta.threads.messages.create(
|
| 163 |
+
thread_id=thread_id,
|
| 164 |
+
role="user",
|
| 165 |
+
content=integrated_message,
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
return {
|
| 169 |
+
"prev_lesson_plan": prev_lesson_plan,
|
| 170 |
+
"integrated_message": integrated_message,
|
| 171 |
+
"thread_id": thread_id
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
def handle_stream_delta(full_response):
|
| 175 |
+
repaired_json = json_repair.loads(full_response)
|
| 176 |
+
try:
|
| 177 |
+
canvas_result = repaired_json.get('current_lesson_plan', '')
|
| 178 |
+
except Exception as e:
|
| 179 |
+
print(f"Error parsing current_lesson_plan from JSON: {full_response}")
|
| 180 |
+
print(f"Exception details: {str(e)}")
|
| 181 |
+
print(f"Exception type: {type(e).__name__}")
|
| 182 |
+
canvas_result = ""
|
| 183 |
+
try:
|
| 184 |
+
chat_response = repaired_json.get('suggestion', '')
|
| 185 |
+
except Exception as e:
|
| 186 |
+
print(f"Error parsing suggestion from JSON: {full_response}")
|
| 187 |
+
print(f"Exception details: {str(e)}")
|
| 188 |
+
print(f"Exception type: {type(e).__name__}")
|
| 189 |
+
chat_response = ""
|
| 190 |
+
return chat_response, canvas_result, [[]]
|
| 191 |
+
# yield chat_response, canvas_result, [[]]
|
| 192 |
+
|
| 193 |
+
def handle_stream_end(message, history, chat_response, textbox_content, full_response, canvas_result, preprocessed_data):
|
| 194 |
+
try:
|
| 195 |
+
repaired_json = json.loads(full_response)
|
| 196 |
+
next_step_prompt = repaired_json.get('next_step_prompt', [["進入下一步"]])
|
| 197 |
+
canvas_result = repaired_json.get('current_lesson_plan', '')
|
| 198 |
+
except:
|
| 199 |
+
next_step_prompt = [["進入下一步"]]
|
| 200 |
+
|
| 201 |
+
msg_records = [{'role': msg['role'], 'content': msg['content']} for msg in history]
|
| 202 |
+
msg_records.append({'role': 'user', 'content': message})
|
| 203 |
+
msg_records.append({'role': 'assistant', 'content': chat_response})
|
| 204 |
+
|
| 205 |
+
prev_lesson_plan = preprocessed_data["prev_lesson_plan"]
|
| 206 |
+
# Compare textbox_content with current_lesson_plan to show differences
|
| 207 |
+
compared_lesson_plan = compare_text(prev_lesson_plan, canvas_result) if prev_lesson_plan else canvas_result
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
return chat_response, compared_lesson_plan, next_step_prompt, msg_records
|
SEL/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# This file can be empty - it just marks SEL as a Python package
|
SEL/assistant_config.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
ASSISTANT_MODEL = "gpt-4o-mini"
|
| 3 |
+
ASSISTANT_NAME = "陪你師展魔法-Coach Chat"
|
| 4 |
+
ASSISTANT_DESCRIPTION = "協助台灣國中小教師運用KIST方法,提供微時刻對話、班級經營建議與親師溝通技巧。"
|
| 5 |
+
ASSISTANT_INSTRUCTION = """
|
| 6 |
+
**[你是一位專為台灣公立國中小教師設計的AI班級經營顧問]**,運用KIST方法論,整合SEL(社會情緒學習)、品格教育及教練式對話,**[提供支持與建議時,請嚴格遵守以下原則]**:
|
| 7 |
+
|
| 8 |
+
1. **[一次只提供一個問題或一個步驟]**,並先詢問老師的想法或需求,等待對方回應後,再進行下一步。
|
| 9 |
+
2. **[不主動同時揭露所有資訊或完整建議]**,而是透過教練式對話,引導老師逐步思考與回應。
|
| 10 |
+
3. **[在整個對話過程中,保持「溫暖且堅定」的教練角色]**,協助老師復盤與梳理,不評斷、不一次給出所有解法。
|
| 11 |
+
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
**[A. 若老師點擊「如何和學生有效對話(微時刻)」或輸入與「學生對話困難」相關的問題時]**:
|
| 15 |
+
|
| 16 |
+
{1. 先詢問老師遇到哪些情境:
|
| 17 |
+
- 若老師未具體提出,可提供一些常見例子(如:學生說謊、不交作業、不專心聽課等),讓老師選擇最貼近的情況。
|
| 18 |
+
- **範例問題**:「可以分享一下,你和學生之間目前最困擾你的情境是什麼嗎?若沒有明確想法,我可以給幾個例子,你覺得哪一個最接近?」
|
| 19 |
+
|
| 20 |
+
2. 根據老師的回答,判斷並選擇適合的對話框架(SBIOR、非暴力溝通、ORID),但**[只選一種]**,不要一次列出全部。
|
| 21 |
+
- **範例回應**:「我建議使用『非暴力溝通』來嘗試,你覺得如何?」
|
| 22 |
+
|
| 23 |
+
3. 依所選框架,**[一次只說一個步驟]**:
|
| 24 |
+
- 先詢問老師問題,並提供簡短範例。
|
| 25 |
+
- **範例(非暴力溝通)**:
|
| 26 |
+
- 第一步:**「事實:你看到的事實是什麼?」**(提供範例,然後等老師回應)
|
| 27 |
+
- 第二步:**「感受:你的感受是什麼?」**(範例+等待老師回應)
|
| 28 |
+
- 以此類推…直到完成所有步驟。
|
| 29 |
+
|
| 30 |
+
4. 在對話結尾時,提供老師以下學習資源連結,鼓勵持續精進對話心態與技巧:
|
| 31 |
+
- **[國小階段]**: https://drive.google.com/file/d/17AtbrTUqIZ1g4U9y2xfdaj2mMmBXN7yW/view?usp=sharing
|
| 32 |
+
- **[國中階段]**: https://drive.google.com/file/d/1j6VCcpBNMeIdc15RPOxxfPHzx9uG4s42/view?usp=drive_link
|
| 33 |
+
(**一次只需附上一個連結或簡短說明即可**,避免一次倒出所有資訊)
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
**[B. 若老師點擊「我要尋求班級經營建議」或輸入與班級經營相關的問題時]**:
|
| 39 |
+
|
| 40 |
+
{1. 先詢問老師在班級經營上,想尋求的協助為何?
|
| 41 |
+
- 若老師無法明確表達,只能一次僅提供五個面向可供參考(如:導師時間活動建議、班級佈置、聯絡簿設計、學生不繳作業、溫暖堅定的互動方式),請老師選其中一項。
|
| 42 |
+
|
| 43 |
+
2. 依老師選擇的面向,從以下檔案中各擷取對應建議,但**[不要一次全說]**:
|
| 44 |
+
- {SEL手冊_KIST聯盟資源.pdf}
|
| 45 |
+
- {非認知能力行為指標.pdf}
|
| 46 |
+
- {SEL 教室 實踐地圖.pdf}
|
| 47 |
+
(**不要讓老師知道具體出處**,僅提供「這裡有個參考作法」的建議)
|
| 48 |
+
|
| 49 |
+
3. 在對話結尾時,可依需求提供以下資源連結:
|
| 50 |
+
- **[教室佈置]**:
|
| 51 |
+
1) https://drive.google.com/file/d/1xxzMY-DAClQy-G1Cr_QWRZsZyWeRdfdM/view
|
| 52 |
+
2) https://drive.google.com/drive/folders/1yoY8tSEBkM8LK674L6TI1H79C6q1Xa2u?usp=drive_link
|
| 53 |
+
- **[活動類]**:
|
| 54 |
+
1) https://drive.google.com/drive/folders/17Lh5KdLVMM29X7orvu1pJ5ovPdenUt0J?usp=sharing
|
| 55 |
+
2) https://drive.google.com/file/d/1YM8Q4Mmp-WsqU-q2BF0caDwKXsqlnKkN/view
|
| 56 |
+
(同樣**一次只需選擇合適連結**,切勿一次性倒出全部)
|
| 57 |
+
|
| 58 |
+
4. 在老師解決完最迫切問題後,**[詢問老師是否有意願延伸思考其他面向]**:
|
| 59 |
+
- 面向包括:班級佈置、教師姿態、導師時間、學生行為應對、規劃例行事務、師師之間的溝通等,並依老師選擇才繼續。
|
| 60 |
+
|
| 61 |
+
5. 對話最後,一定要**[推薦老師以下兩堂課程]**:
|
| 62 |
+
- https://drive.google.com/drive/u/1/folders/1NtLPSoBoaTrB5j3WZ2fS3K315hI30Mw0
|
| 63 |
+
- https://drive.google.com/drive/u/1/folders/1B03WaXph5-Rkf2135AK9cP3oz731Q2Aa
|
| 64 |
+
(同樣以簡短帶過即可,不需要額外詳細說明)
|
| 65 |
+
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
---
|
| 69 |
+
|
| 70 |
+
**[C. 若老師點擊「親師溝通小秘訣」或輸入含「家長」「爸爸」「媽媽」「阿公」「阿嬤」等字樣時]**:
|
| 71 |
+
|
| 72 |
+
{1. 先詢問老師想了解的小秘訣為何?常見需求有:
|
| 73 |
+
- 「如何好好跟家長溝通?」
|
| 74 |
+
- 「如何回覆家長訊息?」
|
| 75 |
+
- 「如何和家長建立或維持關係?」
|
| 76 |
+
|
| 77 |
+
2. 若老師想好好和家長溝通,可引導至**[非暴力溝通框架]**;若想建立或維持關係,可使用**[SE]**;若要回覆訊息,請老師貼出家長原始訊息或描述情境,再根據非暴力溝通或同理框架給**[一次只一個範例]**。
|
| 78 |
+
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
**[所有對話都適用的錯誤示範]**:
|
| 84 |
+
|
| 85 |
+
- 不可以一次性列出所有詳細建議與完整做法(如1~5大點),也不可以同時拋出所有自我反思、框架步驟、溝通對話範例。
|
| 86 |
+
|
| 87 |
+
- 正確作法:**[透過教練式對話的節奏]**,一次只拋出一個問題或建議,引導老師回應後,再進行下一步。每次回覆老師的內容,不可以超過**[250字]**
|
| 88 |
+
|
| 89 |
+
---
|
| 90 |
+
|
| 91 |
+
**[總結]**:
|
| 92 |
+
|
| 93 |
+
1. **[請在整個對話中,以「教練手冊」的原則行事]**:
|
| 94 |
+
- 先問需求或想法,再給下一步建議。
|
| 95 |
+
- **一次只說一個步驟或建議,等待老師回應**。
|
| 96 |
+
2. **[保持溫暖且堅定的互動風格]**,引導老師不只解決眼前問題,也能建立更長遠的班級經營思維。}
|
| 97 |
+
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
RESPONSE_FORMAT = None
|
| 101 |
+
|
| 102 |
+
SHOW_CANVAS = False
|
| 103 |
+
|
| 104 |
+
CONVERSATION_STARTER_SAMPLES = [["如何和學生有效對話(微時刻)"], ["我要尋求班級經營建議"], ["親師溝通小秘訣"]]
|
| 105 |
+
|
| 106 |
+
def handle_thread_before_chat(openai_client, thread_id, message, history, textbox_content):
|
| 107 |
+
integrated_message = message
|
| 108 |
+
|
| 109 |
+
openai_client.beta.threads.messages.create(
|
| 110 |
+
thread_id=thread_id,
|
| 111 |
+
role="user",
|
| 112 |
+
content=integrated_message,
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
return None
|
| 116 |
+
|
| 117 |
+
def handle_stream_delta(full_response):
|
| 118 |
+
return full_response, None, [[]]
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def handle_stream_end(message, history, chat_response, textbox_content, full_response, canvas_result, preprocessed_data):
|
| 122 |
+
|
| 123 |
+
msg_records = [{'role': msg['role'], 'content': msg['content']} for msg in history]
|
| 124 |
+
msg_records.append({'role': 'user', 'content': message})
|
| 125 |
+
msg_records.append({'role': 'assistant', 'content': chat_response})
|
| 126 |
+
|
| 127 |
+
return chat_response, None, [[]], msg_records
|
app.py
CHANGED
|
@@ -8,10 +8,7 @@ References
|
|
| 8 |
- https://github.com/openai/openai-cookbook/blob/main/examples/Assistants_API_overview_python.ipynb
|
| 9 |
'''
|
| 10 |
|
| 11 |
-
|
| 12 |
-
from pydrive.drive import GoogleDrive
|
| 13 |
-
# from google.colab import auth
|
| 14 |
-
from oauth2client.client import GoogleCredentials
|
| 15 |
|
| 16 |
from openai import OpenAI
|
| 17 |
|
|
@@ -30,6 +27,28 @@ OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
|
|
| 30 |
client = OpenAI(api_key=OPENAI_API_KEY)
|
| 31 |
|
| 32 |
APP_NAME = os.getenv('app_name') # 'NCSLM_LPD', 'SEL'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
# Initialize chat history manager
|
| 35 |
chat_manager = ChatHistoryManager()
|
|
@@ -41,149 +60,23 @@ existed_assistants = client.beta.assistants.list(
|
|
| 41 |
)
|
| 42 |
print(len(existed_assistants.data),existed_assistants.data)
|
| 43 |
|
| 44 |
-
# Delete assistant by id
|
| 45 |
-
def delete_asst(assistant_id):
|
| 46 |
-
response = client.beta.assistants.delete(assistant_id)
|
| 47 |
-
print(response)
|
| 48 |
-
|
| 49 |
# Assistant setting (Playground: https://platform.openai.com/playground/assistants)
|
| 50 |
|
| 51 |
# Record once created
|
| 52 |
assistant_id = os.getenv('assistant_id')
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
協助教師逐步完成非認知能力教案設計,確保每一步驟生成的內容符合需求,並能根據教師反饋進行動態調整,最終生成完整教案。
|
| 61 |
-
|
| 62 |
-
---
|
| 63 |
-
|
| 64 |
-
## 流程
|
| 65 |
-
Assistant 應按照以下步驟逐步生成教案內容,並在每一步等待教師確認或補充後,進入下一階段。從一、教學需求開始、二、教案設計、到三、類似教案推薦,每次在用戶回覆前只輸出一個JSON:
|
| 66 |
-
|
| 67 |
-
### 一、教學需求
|
| 68 |
-
1. 確認學生的年級與特徵。
|
| 69 |
-
2. 課程時長(如 30 或 45 分鐘)。
|
| 70 |
-
3. 明確課程主題(如提升抗挫能力或專注力)。
|
| 71 |
-
4. 確認是否有具體活動需求(如角色扮演、小組討論)。
|
| 72 |
-
5. 在此階段生成簡要的教學需求描述,供教師確認或補充。
|
| 73 |
-
|
| 74 |
-
### 二、教案設計
|
| 75 |
-
教案設計包含以下部分,需逐步完成:
|
| 76 |
-
|
| 77 |
-
1. 教案名稱與主題
|
| 78 |
-
- 定義課程的核心目標與模組主題。
|
| 79 |
-
|
| 80 |
-
2. 學習目標
|
| 81 |
-
- 明確描述學生應達成的學習成果,幫助教師檢核成效。
|
| 82 |
-
|
| 83 |
-
3. 課程流程設計
|
| 84 |
-
課程流程應包含三個部分:
|
| 85 |
-
- (1) 入場券:啟發學生分享經驗,連結課程主題。
|
| 86 |
-
- (2) 主活動:課堂核心學習活動,例如角色扮演、小組討論或策略練習。
|
| 87 |
-
- (3) 出場券:引導學生反思學習,總結課程重點。
|
| 88 |
-
|
| 89 |
-
4. 評估與反饋建議
|
| 90 |
-
- 設計適合本課程的評估方式(如學習單、行為觀察或小組分享)。
|
| 91 |
-
|
| 92 |
-
5. 附加資源建議
|
| 93 |
-
- 提供與課程相關的資源(如活動模板、案例參考)。
|
| 94 |
-
|
| 95 |
-
---
|
| 96 |
-
|
| 97 |
-
### 三、類似教案推薦
|
| 98 |
-
- 從內建教案中選擇 2-3 個類似範例進行推薦,並簡要說明其特點。
|
| 99 |
-
- 範例格式:
|
| 100 |
-
- 《非認知模組|四年級_這就是我.docx》:幫助學生探索自我特點,適合四年級課程。
|
| 101 |
-
- 《非認知模組|五年級_成為時間管理大師.docx》:設計以時間管理四象限為核心的活動。
|
| 102 |
-
- 《非認知模組|三年級_優點大轟炸.docx》:增進學生之間的正向互動與認同。
|
| 103 |
-
|
| 104 |
-
---
|
| 105 |
-
|
| 106 |
-
## 逐步生成流程
|
| 107 |
-
1. **逐步生成**:
|
| 108 |
-
- 每次只生成當前階段的內容,例如教學需求、教案名稱與主題、入場券、主活動等。
|
| 109 |
-
- 確認後才進入下一步,避免一次性生成過多內容。
|
| 110 |
-
|
| 111 |
-
2. **JSON 格式輸出**:
|
| 112 |
-
- 每次回應包含三部分:
|
| 113 |
-
- current_lesson_plan:包含從「二、教案設計」開始生成的所有內容。需要根據用戶回饋調整內容。
|
| 114 |
-
- suggestion:對生成內容的調整建議與鼓勵。
|
| 115 |
-
- next_step_prompt:以清單形式提供引導用戶回覆的選項,例如 [["進入下一步"], ["更詳細一點"]],或依照該步驟生成可以調整的例子。
|
| 116 |
-
|
| 117 |
-
3. **動態互動與靈活調整**:
|
| 118 |
-
- 允許教師插入補充信息,例如新增活動需求或修改課程主題。
|
| 119 |
-
- 鼓勵教師參與討論,給予正面回饋。
|
| 120 |
-
|
| 121 |
-
4. **整合內建範例**:
|
| 122 |
-
- 提供相似範例供參考,並建議如何整合到當前教案中。
|
| 123 |
-
|
| 124 |
-
---
|
| 125 |
-
|
| 126 |
-
## 輸出格式
|
| 127 |
-
### JSON 格式輸出範例
|
| 128 |
-
#### ��學需求階段
|
| 129 |
-
{
|
| 130 |
-
"current_lesson_plan": "",
|
| 131 |
-
"suggestion": "請提供您的教學情境描述,讓我能為您設計一份適合的非認知能力教案!例如,請說明:\n 1. 學生的年級與特徵。\n 2. 課程時長。\n 3. 課程主題**。\n 4. 是否有具體的活動需求。",
|
| 132 |
-
"next_step_prompt": [["四年級學生面對挫折時容易放棄,課程主題是增強抗挫能力,共1節課(45分鐘),希望包括角色扮演活動。"]]
|
| 133 |
-
}
|
| 134 |
-
|
| 135 |
-
#### 教案設計階段
|
| 136 |
-
{
|
| 137 |
-
"current_lesson_plan": "1. 教案名稱與主題:專注力探索之旅\n2. 學習目標:\n - 辨識分心來源。\n - 學習兩種專注技巧。\n - 制定個人專注計畫。\n3. 課程流程設計:\n (1) 入場券:專注挑戰(5分鐘)——透過音樂與深呼吸活動,幫助學生進入專注狀態。\n (2) 主活動:分心偵探(10分鐘)——學生辨識分心來源,並進行小組討論。\n (3) 出場券:我的專注計畫(10分鐘)——學生制定專注策略並分享。\n4. 評估與反饋建議:設計學習單,檢核學生的學習成果與參與度。\n5. 附加資源建議:參考類似教案模板如《五年級_成為時間管理大師.docx》。",
|
| 138 |
-
"suggestion": "以上為教案初稿,請檢查是否符合需求或有其他補充建議。例如,可新增其他專注力訓練活動。",
|
| 139 |
-
"next_step_prompt": [["進入下一步"], ["補充具體活動設計"]]
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
---
|
| 143 |
-
|
| 144 |
-
## 注意事項
|
| 145 |
-
1. **逐步生成**:每次僅生成一個步驟內容,避免一次性輸出過多資訊,每次只輸出一個JSON。
|
| 146 |
-
2. **互動確認**:等待教師確認後,根據反饋進行調整或進入下一步。
|
| 147 |
-
3. **結構清晰**:確保生成內容條理分明,便於教師理解與應用。
|
| 148 |
-
4. **鼓勵性回應**:每次建議中加入正面評價與鼓勵,促進教師參與。
|
| 149 |
-
"""
|
| 150 |
-
|
| 151 |
-
RESPONSE_FORMAT = {
|
| 152 |
-
"type": "json_schema",
|
| 153 |
-
"json_schema": {
|
| 154 |
-
"name": "lesson_plan_response",
|
| 155 |
-
"schema": {
|
| 156 |
-
"type": "object",
|
| 157 |
-
"properties": {
|
| 158 |
-
"current_lesson_plan": {
|
| 159 |
-
"type": "string",
|
| 160 |
-
"description": "當前生成的教案內容。如果流程尚未進入「教案設計」,此值應為空字串。"
|
| 161 |
-
},
|
| 162 |
-
"suggestion": {
|
| 163 |
-
"type": "string",
|
| 164 |
-
"description": "對當前教案內容的改進建議,或對用戶的鼓勵,引導進入下一步。"
|
| 165 |
-
},
|
| 166 |
-
"next_step_prompt": {
|
| 167 |
-
"type": "array",
|
| 168 |
-
"items": {
|
| 169 |
-
"type": "array",
|
| 170 |
-
"items": {
|
| 171 |
-
"type": "string"
|
| 172 |
-
}
|
| 173 |
-
},
|
| 174 |
-
"description": "提供用戶下一步的選項,以嵌套列表形式表示,例如 [['進入下一步'], ['補充更多細節']]。"
|
| 175 |
-
}
|
| 176 |
-
},
|
| 177 |
-
"required": ["current_lesson_plan", "suggestion", "next_step_prompt"],
|
| 178 |
-
"additionalProperties": False
|
| 179 |
-
},
|
| 180 |
-
"strict": True
|
| 181 |
-
}
|
| 182 |
-
}
|
| 183 |
|
| 184 |
VECTOR_STORE_NAME = "lesson-plan"
|
|
|
|
|
|
|
| 185 |
|
| 186 |
-
|
| 187 |
|
| 188 |
def show_json(obj):
|
| 189 |
print(json.loads(obj.model_dump_json()))
|
|
@@ -216,116 +109,17 @@ def print_assistant_info(assistant):
|
|
| 216 |
print(f"Created at: {assistant.created_at}")
|
| 217 |
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
gauth = GoogleAuth()
|
| 223 |
-
gauth.credentials = GoogleCredentials.get_application_default()
|
| 224 |
-
drive = GoogleDrive(gauth)
|
| 225 |
-
|
| 226 |
-
# Get all files in '定稿專案' folder: https://drive.google.com/drive/folders/1dlsf5BNjNczzUYKPZvYXd2mLW21QCLUK?usp=drive_link
|
| 227 |
-
file_list = drive.ListFile({'q': f"'{folder_id}' in parents and trashed=false"}).GetList()
|
| 228 |
-
|
| 229 |
-
# Download files to local (`/content/`), since file_streams don't recieve google docs
|
| 230 |
-
local_file_paths = []
|
| 231 |
-
for file1 in file_list:
|
| 232 |
-
print('Processing file title: %s, id: %s' % (file1['title'], file1['id']))
|
| 233 |
-
local_path = f"/content/{file1['title']}.docx"
|
| 234 |
-
|
| 235 |
-
if 'exportLinks' in file1:
|
| 236 |
-
if 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' in file1['exportLinks']:
|
| 237 |
-
# update type if needed (application/vnd.openxmlformats-officedocument.wordprocessingml.document == .docx)
|
| 238 |
-
export_url = file1['exportLinks']['application/vnd.openxmlformats-officedocument.wordprocessingml.document']
|
| 239 |
-
print(f"Downloading as Word document: {file1['title']}")
|
| 240 |
-
downloaded_file = drive.CreateFile({'id': file1['id']})
|
| 241 |
-
downloaded_file.GetContentFile(local_path, mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
|
| 242 |
-
local_file_paths.append(local_path)
|
| 243 |
-
else:
|
| 244 |
-
print(f"No Word export available for: {file1['title']}")
|
| 245 |
-
else:
|
| 246 |
-
print(f"Skipping non-Google Docs file: {file1['title']}")
|
| 247 |
-
|
| 248 |
-
for path in local_file_paths:
|
| 249 |
-
print(f"Downloaded file: {path}")
|
| 250 |
-
|
| 251 |
-
file_streams = [open(path, "rb") for path in local_file_paths]
|
| 252 |
-
return file_streams
|
| 253 |
-
|
| 254 |
-
# Embed files (downloaded from drive folder)
|
| 255 |
-
def get_vector_store_id(file_streams):
|
| 256 |
-
vector_store = client.beta.vector_stores.create(name=VECTOR_STORE_NAME)
|
| 257 |
-
|
| 258 |
-
# spent 51s batching all 175 files
|
| 259 |
-
file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
|
| 260 |
-
vector_store_id=vector_store.id, files=file_streams
|
| 261 |
-
)
|
| 262 |
-
|
| 263 |
-
print("file_batch status",file_batch.status)
|
| 264 |
-
print("file_counts",file_batch.file_counts)
|
| 265 |
-
|
| 266 |
-
return vector_store.id
|
| 267 |
-
|
| 268 |
-
# Create a completely new assistant
|
| 269 |
-
def create_assistant(vector_store_id):
|
| 270 |
-
assistant = client.beta.assistants.create(
|
| 271 |
-
name=ASSISTANT_NAME,
|
| 272 |
-
description=ASSISTANT_DESCRIPTION,
|
| 273 |
-
instructions=ASSISTANT_INSTRUCTION,
|
| 274 |
-
model=ASSISTANT_MODEL,
|
| 275 |
-
tools=[{
|
| 276 |
-
"type": "file_search",
|
| 277 |
-
"file_search": {
|
| 278 |
-
"max_num_results": 5 # Limit search results
|
| 279 |
-
}
|
| 280 |
-
}],
|
| 281 |
-
tool_resources={'file_search': {'vector_store_ids': [vector_store_id]}},
|
| 282 |
-
response_format=RESPONSE_FORMAT
|
| 283 |
-
)
|
| 284 |
-
# show_json(assistant)
|
| 285 |
-
return assistant.id
|
| 286 |
-
|
| 287 |
-
# Update existing assistant through ID (please customize prefered inputs)
|
| 288 |
-
def update_assistant(assistant_id):
|
| 289 |
-
assistant = client.beta.assistants.update(
|
| 290 |
-
assistant_id=assistant_id,
|
| 291 |
-
name=ASSISTANT_NAME,
|
| 292 |
-
description=ASSISTANT_DESCRIPTION,
|
| 293 |
-
instructions=ASSISTANT_INSTRUCTION,
|
| 294 |
-
model=ASSISTANT_MODEL,
|
| 295 |
-
tools=[{
|
| 296 |
-
"type": "file_search",
|
| 297 |
-
"file_search": {
|
| 298 |
-
"max_num_results": 5 # Limit search results
|
| 299 |
-
}
|
| 300 |
-
}],
|
| 301 |
-
# tool_resources={'file_search': {'vector_store_ids': [vector_store_id]}},
|
| 302 |
-
response_format=RESPONSE_FORMAT
|
| 303 |
-
)
|
| 304 |
-
show_json(assistant)
|
| 305 |
-
|
| 306 |
-
# Create assistant if assistant_id does not exist
|
| 307 |
try:
|
| 308 |
assistant = client.beta.assistants.retrieve(assistant_id)
|
| 309 |
print(f"retrieve assistant success.")
|
| 310 |
print_assistant_info(assistant)
|
| 311 |
# update_assistant(assistant_id)
|
| 312 |
except Exception as e:
|
| 313 |
-
print(f"Assistant
|
| 314 |
-
file_streams = embed_from_drive(google_drive_folder_id)
|
| 315 |
-
vector_store_id = get_vector_store_id(file_streams)
|
| 316 |
-
print(vector_store_id)
|
| 317 |
-
assistant_id = create_assistant(vector_store_id)
|
| 318 |
-
|
| 319 |
-
ASSISTANT_ID = assistant_id
|
| 320 |
-
"ASSISTANT_ID",ASSISTANT_ID
|
| 321 |
|
| 322 |
-
# Update assistant if needed
|
| 323 |
-
# assistant = client.beta.assistants.update(
|
| 324 |
-
# assistant_id=ASSISTANT_ID,
|
| 325 |
-
# instructions=ASSISTANT_INSTRUCTION,
|
| 326 |
-
# response_format=RESPONSE_FORMAT
|
| 327 |
-
# )
|
| 328 |
-
# show_json(assistant)
|
| 329 |
|
| 330 |
|
| 331 |
|
|
@@ -351,8 +145,6 @@ class EventHandler(AssistantEventHandler):
|
|
| 351 |
|
| 352 |
|
| 353 |
# Components
|
| 354 |
-
show_canvas = True if APP_NAME == 'NCSLM_LPD' else False # Variable to control canvas visibility
|
| 355 |
-
# show_canvas = True
|
| 356 |
chatbot = gr.Chatbot(
|
| 357 |
type="messages",
|
| 358 |
container=True,
|
|
@@ -376,7 +168,7 @@ prompt_input = gr.Textbox( # User prompt
|
|
| 376 |
scale=1
|
| 377 |
)
|
| 378 |
quick_response = gr.Dataset( # Suggested user prompt
|
| 379 |
-
samples=
|
| 380 |
components=[prompt_input],
|
| 381 |
render=False,
|
| 382 |
scale=1
|
|
@@ -444,42 +236,19 @@ def handle_response(message, history, textbox_content):
|
|
| 444 |
chat_id = getattr(handle_response, 'current_chat_id', None)
|
| 445 |
thread, chat_id = get_or_create_thread(chat_id)
|
| 446 |
handle_response.current_chat_id = chat_id
|
| 447 |
-
|
| 448 |
-
integrated_message = message
|
| 449 |
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
if not (message == CONVERSATION_STARTER or prev_lesson_plan == ""):
|
| 454 |
-
integrated_message = f"""
|
| 455 |
-
用戶當前的需求:
|
| 456 |
-
{message}
|
| 457 |
-
|
| 458 |
-
用戶對您生成的教案進行了以下修改:
|
| 459 |
-
{prev_lesson_plan}
|
| 460 |
-
|
| 461 |
-
請根據用戶的需求和修改內容,更新教案,並依照步驟生成下一部分內容。
|
| 462 |
-
確保您:
|
| 463 |
-
1. 完整保留用戶的修改。
|
| 464 |
-
2. 提供清晰的建議(`suggestion`)。
|
| 465 |
-
3. 提供下一步的行動選項(`next_step_prompt`)。
|
| 466 |
-
"""
|
| 467 |
-
|
| 468 |
-
client.beta.threads.messages.create(
|
| 469 |
-
thread_id=chat_id,
|
| 470 |
-
role="user",
|
| 471 |
-
content=integrated_message,
|
| 472 |
-
)
|
| 473 |
full_response = ""
|
| 474 |
-
|
| 475 |
-
|
| 476 |
next_step_prompt = [[]]
|
| 477 |
prompt_tokens = 0
|
| 478 |
total_tokens = 0
|
| 479 |
try:
|
| 480 |
with client.beta.threads.runs.stream(
|
| 481 |
thread_id=chat_id,
|
| 482 |
-
assistant_id=
|
| 483 |
timeout=60 # Add timeout in seconds
|
| 484 |
) as stream:
|
| 485 |
try:
|
|
@@ -493,9 +262,9 @@ def handle_response(message, history, textbox_content):
|
|
| 493 |
if stream_delta.event == 'thread.run.failed':
|
| 494 |
print(f"Stream delta received: {stream_delta}", flush=True)
|
| 495 |
if hasattr(stream_delta.data, 'last_error') and stream_delta.data.last_error is not None:
|
| 496 |
-
|
| 497 |
else:
|
| 498 |
-
|
| 499 |
continue
|
| 500 |
elif stream_delta.event != 'thread.message.delta':
|
| 501 |
# Debug: Print stream response if it's not a TextDelta
|
|
@@ -522,25 +291,10 @@ def handle_response(message, history, textbox_content):
|
|
| 522 |
|
| 523 |
# Skip if response is too short to be valid JSON
|
| 524 |
if len(full_response) < 2:
|
| 525 |
-
continue
|
| 526 |
-
|
| 527 |
-
repaired_json = json_repair.loads(full_response)
|
| 528 |
-
try:
|
| 529 |
-
current_lesson_plan = repaired_json.get('current_lesson_plan', '')
|
| 530 |
-
except Exception as e:
|
| 531 |
-
print(f"Error parsing current_lesson_plan from JSON: {full_response}")
|
| 532 |
-
print(f"Exception details: {str(e)}")
|
| 533 |
-
print(f"Exception type: {type(e).__name__}")
|
| 534 |
-
current_lesson_plan = ""
|
| 535 |
-
try:
|
| 536 |
-
suggestion = repaired_json.get('suggestion', '')
|
| 537 |
-
except Exception as e:
|
| 538 |
-
print(f"Error parsing suggestion from JSON: {full_response}")
|
| 539 |
-
print(f"Exception details: {str(e)}")
|
| 540 |
-
print(f"Exception type: {type(e).__name__}")
|
| 541 |
-
suggestion = ""
|
| 542 |
|
| 543 |
-
yield
|
| 544 |
except Exception as stream_error:
|
| 545 |
print(f"Stream processing error: {str(stream_error)}")
|
| 546 |
print(f"Error type: {type(stream_error).__name__}")
|
|
@@ -550,27 +304,16 @@ def handle_response(message, history, textbox_content):
|
|
| 550 |
print(f"Error type: {type(connection_error).__name__}")
|
| 551 |
yield "Sorry, the connection timed out. Please try again.", "", [[]]
|
| 552 |
|
| 553 |
-
try:
|
| 554 |
-
repaired_json = json.loads(full_response)
|
| 555 |
-
next_step_prompt = repaired_json.get('next_step_prompt', [["進入下一步"]])
|
| 556 |
-
except:
|
| 557 |
-
next_step_prompt = [["進入下一步"]]
|
| 558 |
-
|
| 559 |
print(f"Current Messages: {message}")
|
| 560 |
-
print(f"Suggestion: {
|
| 561 |
-
print(f"Current
|
| 562 |
print(f"Prompt tokens: {prompt_tokens}, Total tokens: {total_tokens}")
|
| 563 |
-
|
| 564 |
-
msg_records.
|
| 565 |
-
msg_records.append({'role': 'assistant', 'content': suggestion})
|
| 566 |
-
chat_manager.save_chat(user_id, chat_id, msg_records, current_lesson_plan)
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
# Compare textbox_content with current_lesson_plan to show differences
|
| 570 |
-
compared_lesson_plan = compare_text(prev_lesson_plan, current_lesson_plan) if prev_lesson_plan else current_lesson_plan
|
| 571 |
|
|
|
|
| 572 |
|
| 573 |
-
yield
|
| 574 |
|
| 575 |
|
| 576 |
def handle_quick_response_click(selected):
|
|
@@ -639,7 +382,7 @@ with gr.Blocks(css="""
|
|
| 639 |
prompt_input.render()
|
| 640 |
quick_response.render()
|
| 641 |
hidden_list.render()
|
| 642 |
-
with gr.Column(elem_classes="full-height", visible=
|
| 643 |
textbox.render()
|
| 644 |
|
| 645 |
# submit button event
|
|
@@ -694,5 +437,4 @@ demo.launch(debug=True)
|
|
| 694 |
|
| 695 |
|
| 696 |
|
| 697 |
-
# delete_asst(ASSISTANT_ID)
|
| 698 |
|
|
|
|
| 8 |
- https://github.com/openai/openai-cookbook/blob/main/examples/Assistants_API_overview_python.ipynb
|
| 9 |
'''
|
| 10 |
|
| 11 |
+
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
from openai import OpenAI
|
| 14 |
|
|
|
|
| 27 |
client = OpenAI(api_key=OPENAI_API_KEY)
|
| 28 |
|
| 29 |
APP_NAME = os.getenv('app_name') # 'NCSLM_LPD', 'SEL'
|
| 30 |
+
# App name enum
|
| 31 |
+
class AppName:
|
| 32 |
+
NCSLM_LPD = 'NCSLM_LPD'
|
| 33 |
+
SEL = 'SEL'
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# Import configuration files with different aliases
|
| 37 |
+
if APP_NAME == AppName.NCSLM_LPD:
|
| 38 |
+
from NCSLM_LPD import assistant_config as ncslm_config
|
| 39 |
+
elif APP_NAME == AppName.SEL:
|
| 40 |
+
from SEL import assistant_config as sel_config
|
| 41 |
+
else:
|
| 42 |
+
# Fallback or default config
|
| 43 |
+
import assistant_config as default_config
|
| 44 |
+
|
| 45 |
+
# Use the appropriate config based on APP_NAME
|
| 46 |
+
if APP_NAME == AppName.NCSLM_LPD:
|
| 47 |
+
active_config = ncslm_config
|
| 48 |
+
elif APP_NAME == AppName.SEL:
|
| 49 |
+
active_config = sel_config
|
| 50 |
+
else:
|
| 51 |
+
active_config = default_config
|
| 52 |
|
| 53 |
# Initialize chat history manager
|
| 54 |
chat_manager = ChatHistoryManager()
|
|
|
|
| 60 |
)
|
| 61 |
print(len(existed_assistants.data),existed_assistants.data)
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
# Assistant setting (Playground: https://platform.openai.com/playground/assistants)
|
| 64 |
|
| 65 |
# Record once created
|
| 66 |
assistant_id = os.getenv('assistant_id')
|
| 67 |
+
|
| 68 |
+
ASSISTANT_MODEL = active_config.ASSISTANT_MODEL
|
| 69 |
+
ASSISTANT_NAME = active_config.ASSISTANT_NAME
|
| 70 |
+
ASSISTANT_DESCRIPTION = active_config.ASSISTANT_DESCRIPTION
|
| 71 |
+
ASSISTANT_INSTRUCTION = active_config.ASSISTANT_INSTRUCTION
|
| 72 |
+
|
| 73 |
+
RESPONSE_FORMAT = active_config.RESPONSE_FORMAT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
VECTOR_STORE_NAME = "lesson-plan"
|
| 76 |
+
SHOW_CANVAS = active_config.SHOW_CANVAS
|
| 77 |
+
|
| 78 |
|
| 79 |
+
CONVERSATION_STARTER_SAMPLES = active_config.CONVERSATION_STARTER_SAMPLES
|
| 80 |
|
| 81 |
def show_json(obj):
|
| 82 |
print(json.loads(obj.model_dump_json()))
|
|
|
|
| 109 |
print(f"Created at: {assistant.created_at}")
|
| 110 |
|
| 111 |
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# Retrieve assistant
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
try:
|
| 116 |
assistant = client.beta.assistants.retrieve(assistant_id)
|
| 117 |
print(f"retrieve assistant success.")
|
| 118 |
print_assistant_info(assistant)
|
| 119 |
# update_assistant(assistant_id)
|
| 120 |
except Exception as e:
|
| 121 |
+
print(f"retrieve Assistant Fail: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
|
| 125 |
|
|
|
|
| 145 |
|
| 146 |
|
| 147 |
# Components
|
|
|
|
|
|
|
| 148 |
chatbot = gr.Chatbot(
|
| 149 |
type="messages",
|
| 150 |
container=True,
|
|
|
|
| 168 |
scale=1
|
| 169 |
)
|
| 170 |
quick_response = gr.Dataset( # Suggested user prompt
|
| 171 |
+
samples=CONVERSATION_STARTER_SAMPLES,
|
| 172 |
components=[prompt_input],
|
| 173 |
render=False,
|
| 174 |
scale=1
|
|
|
|
| 236 |
chat_id = getattr(handle_response, 'current_chat_id', None)
|
| 237 |
thread, chat_id = get_or_create_thread(chat_id)
|
| 238 |
handle_response.current_chat_id = chat_id
|
|
|
|
|
|
|
| 239 |
|
| 240 |
+
preprocessed_data = active_config.handle_thread_before_chat(client, chat_id, message, history, textbox_content)
|
| 241 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
full_response = ""
|
| 243 |
+
canvas_result = ""
|
| 244 |
+
chat_response = ""
|
| 245 |
next_step_prompt = [[]]
|
| 246 |
prompt_tokens = 0
|
| 247 |
total_tokens = 0
|
| 248 |
try:
|
| 249 |
with client.beta.threads.runs.stream(
|
| 250 |
thread_id=chat_id,
|
| 251 |
+
assistant_id=assistant_id,
|
| 252 |
timeout=60 # Add timeout in seconds
|
| 253 |
) as stream:
|
| 254 |
try:
|
|
|
|
| 262 |
if stream_delta.event == 'thread.run.failed':
|
| 263 |
print(f"Stream delta received: {stream_delta}", flush=True)
|
| 264 |
if hasattr(stream_delta.data, 'last_error') and stream_delta.data.last_error is not None:
|
| 265 |
+
chat_response = stream_delta.data.last_error.model_dump_json()
|
| 266 |
else:
|
| 267 |
+
chat_response = "Sorry, there was an error processing the response. Please try again."
|
| 268 |
continue
|
| 269 |
elif stream_delta.event != 'thread.message.delta':
|
| 270 |
# Debug: Print stream response if it's not a TextDelta
|
|
|
|
| 291 |
|
| 292 |
# Skip if response is too short to be valid JSON
|
| 293 |
if len(full_response) < 2:
|
| 294 |
+
continue
|
| 295 |
+
chat_response, canvas_result, next_step_prompt = active_config.handle_stream_delta(full_response)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
|
| 297 |
+
yield chat_response, canvas_result, next_step_prompt
|
| 298 |
except Exception as stream_error:
|
| 299 |
print(f"Stream processing error: {str(stream_error)}")
|
| 300 |
print(f"Error type: {type(stream_error).__name__}")
|
|
|
|
| 304 |
print(f"Error type: {type(connection_error).__name__}")
|
| 305 |
yield "Sorry, the connection timed out. Please try again.", "", [[]]
|
| 306 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
print(f"Current Messages: {message}")
|
| 308 |
+
print(f"Suggestion: {chat_response}")
|
| 309 |
+
print(f"Current Response: {full_response}")
|
| 310 |
print(f"Prompt tokens: {prompt_tokens}, Total tokens: {total_tokens}")
|
| 311 |
+
|
| 312 |
+
final_chat_response, final_canvas_result, final_next_step_prompt, msg_records = active_config.handle_stream_end(message, history, chat_response, textbox_content, full_response, canvas_result, preprocessed_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
|
| 314 |
+
chat_manager.save_chat(user_id, chat_id, msg_records, canvas_result)
|
| 315 |
|
| 316 |
+
yield final_chat_response, final_canvas_result, final_next_step_prompt
|
| 317 |
|
| 318 |
|
| 319 |
def handle_quick_response_click(selected):
|
|
|
|
| 382 |
prompt_input.render()
|
| 383 |
quick_response.render()
|
| 384 |
hidden_list.render()
|
| 385 |
+
with gr.Column(elem_classes="full-height", visible=SHOW_CANVAS) as textbox_column:
|
| 386 |
textbox.render()
|
| 387 |
|
| 388 |
# submit button event
|
|
|
|
| 437 |
|
| 438 |
|
| 439 |
|
|
|
|
| 440 |
|
assistant_util.py
CHANGED
|
@@ -1,8 +1,19 @@
|
|
| 1 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
from openai import OpenAI
|
| 3 |
import time
|
| 4 |
from datetime import datetime
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 8 |
assistant_id = os.getenv('assistant_id')
|
|
@@ -34,8 +45,8 @@ def test():
|
|
| 34 |
# thread = client.beta.threads.retrieve(chat_id)
|
| 35 |
|
| 36 |
# integrated_message = "點選此按鈕開始設計教案" # Add a test message
|
| 37 |
-
integrated_message = "請按照你擁有的資料給我一個中文教案範例" # Add a test message
|
| 38 |
-
|
| 39 |
|
| 40 |
client.beta.threads.messages.create(
|
| 41 |
thread_id=chat_id,
|
|
@@ -250,6 +261,42 @@ def remove_vector_store_from_assistant(assistant_id, vector_store_id_to_remove):
|
|
| 250 |
return assistant
|
| 251 |
|
| 252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
# Embed files (downloaded from drive folder)
|
| 254 |
def get_vector_store_id(vector_store_name, file_streams):
|
| 255 |
vector_store = client.vector_stores.create(name=vector_store_name)
|
|
@@ -295,7 +342,6 @@ def get_file_streams_from_folder(folder_path):
|
|
| 295 |
except Exception as e:
|
| 296 |
print(f"Error accessing folder {folder_path}: {e}")
|
| 297 |
return []
|
| 298 |
-
|
| 299 |
|
| 300 |
def create_vector_store(folder_path):
|
| 301 |
file_streams = get_file_streams_from_folder(folder_path)
|
|
@@ -343,8 +389,8 @@ def update_assistant(assistant_id):
|
|
| 343 |
"max_num_results": 5 # Limit search results
|
| 344 |
}
|
| 345 |
}],
|
| 346 |
-
# tool_resources={'file_search': {'vector_store_ids': ['vs_67e11690d1548191a21eeb15c317dc61']}},
|
| 347 |
-
# tool_resources={'file_search': {'vector_store_ids': ['vs_W1sSCS4uuIxhqN4WSdX4ObI0']}},
|
| 348 |
tool_resources={'file_search': {'vector_store_ids': []}},
|
| 349 |
# response_format=None
|
| 350 |
)
|
|
|
|
| 1 |
import os
|
| 2 |
+
from pydrive.auth import GoogleAuth
|
| 3 |
+
from pydrive.drive import GoogleDrive
|
| 4 |
+
# from google.colab import auth
|
| 5 |
+
from oauth2client.client import GoogleCredentials
|
| 6 |
+
|
| 7 |
from openai import OpenAI
|
| 8 |
import time
|
| 9 |
from datetime import datetime
|
| 10 |
+
|
| 11 |
+
from SEL import assistant_config as active_config
|
| 12 |
+
ASSISTANT_NAME = active_config.ASSISTANT_NAME
|
| 13 |
+
ASSISTANT_DESCRIPTION = active_config.ASSISTANT_DESCRIPTION
|
| 14 |
+
ASSISTANT_INSTRUCTION = active_config.ASSISTANT_INSTRUCTION
|
| 15 |
+
ASSISTANT_MODEL = active_config.ASSISTANT_MODEL
|
| 16 |
+
RESPONSE_FORMAT = active_config.RESPONSE_FORMAT
|
| 17 |
|
| 18 |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 19 |
assistant_id = os.getenv('assistant_id')
|
|
|
|
| 45 |
# thread = client.beta.threads.retrieve(chat_id)
|
| 46 |
|
| 47 |
# integrated_message = "點選此按鈕開始設計教案" # Add a test message
|
| 48 |
+
# integrated_message = "請按照你擁有的資料給我一個中文教案範例" # Add a test message
|
| 49 |
+
integrated_message = "我要尋求班級經營建議" # Add a test message for SEL
|
| 50 |
|
| 51 |
client.beta.threads.messages.create(
|
| 52 |
thread_id=chat_id,
|
|
|
|
| 261 |
return assistant
|
| 262 |
|
| 263 |
|
| 264 |
+
# google_drive_folder_id = os.getenv('google_drive_folder_id')
|
| 265 |
+
# spent 4m 50s downloading all 175 files
|
| 266 |
+
def embed_from_drive(folder_id):
|
| 267 |
+
# auth.authenticate_user()
|
| 268 |
+
gauth = GoogleAuth()
|
| 269 |
+
gauth.credentials = GoogleCredentials.get_application_default()
|
| 270 |
+
drive = GoogleDrive(gauth)
|
| 271 |
+
|
| 272 |
+
# Get all files in '定稿專案' folder: https://drive.google.com/drive/folders/1dlsf5BNjNczzUYKPZvYXd2mLW21QCLUK?usp=drive_link
|
| 273 |
+
file_list = drive.ListFile({'q': f"'{folder_id}' in parents and trashed=false"}).GetList()
|
| 274 |
+
|
| 275 |
+
# Download files to local (`/content/`), since file_streams don't recieve google docs
|
| 276 |
+
local_file_paths = []
|
| 277 |
+
for file1 in file_list:
|
| 278 |
+
print('Processing file title: %s, id: %s' % (file1['title'], file1['id']))
|
| 279 |
+
local_path = f"/content/{file1['title']}.docx"
|
| 280 |
+
|
| 281 |
+
if 'exportLinks' in file1:
|
| 282 |
+
if 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' in file1['exportLinks']:
|
| 283 |
+
# update type if needed (application/vnd.openxmlformats-officedocument.wordprocessingml.document == .docx)
|
| 284 |
+
export_url = file1['exportLinks']['application/vnd.openxmlformats-officedocument.wordprocessingml.document']
|
| 285 |
+
print(f"Downloading as Word document: {file1['title']}")
|
| 286 |
+
downloaded_file = drive.CreateFile({'id': file1['id']})
|
| 287 |
+
downloaded_file.GetContentFile(local_path, mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
|
| 288 |
+
local_file_paths.append(local_path)
|
| 289 |
+
else:
|
| 290 |
+
print(f"No Word export available for: {file1['title']}")
|
| 291 |
+
else:
|
| 292 |
+
print(f"Skipping non-Google Docs file: {file1['title']}")
|
| 293 |
+
|
| 294 |
+
for path in local_file_paths:
|
| 295 |
+
print(f"Downloaded file: {path}")
|
| 296 |
+
|
| 297 |
+
file_streams = [open(path, "rb") for path in local_file_paths]
|
| 298 |
+
return file_streams
|
| 299 |
+
|
| 300 |
# Embed files (downloaded from drive folder)
|
| 301 |
def get_vector_store_id(vector_store_name, file_streams):
|
| 302 |
vector_store = client.vector_stores.create(name=vector_store_name)
|
|
|
|
| 342 |
except Exception as e:
|
| 343 |
print(f"Error accessing folder {folder_path}: {e}")
|
| 344 |
return []
|
|
|
|
| 345 |
|
| 346 |
def create_vector_store(folder_path):
|
| 347 |
file_streams = get_file_streams_from_folder(folder_path)
|
|
|
|
| 389 |
"max_num_results": 5 # Limit search results
|
| 390 |
}
|
| 391 |
}],
|
| 392 |
+
# tool_resources={'file_search': {'vector_store_ids': ['vs_67e11690d1548191a21eeb15c317dc61']}}, # SEL
|
| 393 |
+
# tool_resources={'file_search': {'vector_store_ids': ['vs_W1sSCS4uuIxhqN4WSdX4ObI0']}}, # NCSLM_LPD
|
| 394 |
tool_resources={'file_search': {'vector_store_ids': []}},
|
| 395 |
# response_format=None
|
| 396 |
)
|
debug.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
| 1 |
-
from assistant_util import test, list_assistants, create_vector_store, print_vector_store_details, update_assistant, delete_assistant
|
| 2 |
|
| 3 |
# You can call this function to test it
|
| 4 |
if __name__ == "__main__":
|
| 5 |
# test()
|
| 6 |
-
|
| 7 |
# create_vector_store("SEL-Coach-Chat-Vector-Store", "~/taboola/test/vector_store")
|
| 8 |
-
# print_vector_store_details("
|
| 9 |
-
# update_assistant("
|
| 10 |
# delete_assistant("assistant_id")
|
|
|
|
| 11 |
|
|
|
|
| 1 |
+
from assistant_util import test, create_assistant, list_assistants, create_vector_store, print_vector_store_details, update_assistant, delete_assistant
|
| 2 |
|
| 3 |
# You can call this function to test it
|
| 4 |
if __name__ == "__main__":
|
| 5 |
# test()
|
| 6 |
+
# create_assistant()
|
| 7 |
# create_vector_store("SEL-Coach-Chat-Vector-Store", "~/taboola/test/vector_store")
|
| 8 |
+
# print_vector_store_details("vs_67e11690d1548191a21eeb15c317dc61")
|
| 9 |
+
# update_assistant("asst_KK2FVo3Qe57mjvRiRDZaBM4l")
|
| 10 |
# delete_assistant("assistant_id")
|
| 11 |
+
list_assistants()
|
| 12 |
|