Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import os | |
| import openai | |
| from openai import OpenAI | |
| import logging | |
| from concurrent.futures import ThreadPoolExecutor | |
| logging.basicConfig(level=logging.DEBUG) | |
| os.environ["OPENAI_API_KEY"] = os.environ["gptkey"] | |
| ### | |
| chat_history = [] | |
| client = OpenAI( | |
| api_key= os.environ["gptkey"] | |
| ) | |
| import json | |
| chat_question_index = 0 | |
| chat_history = [[None,"你好,我是訪談小助手,我將透過陪你聊天的方式,了解你的基本資料!首先,可以告訴我你任職的品牌嗎?像是Amplifi/Carat/dentsu MB/dentsu One/dentsu X/dentsu Consult/HQ/iProspect/isobar/Merkle/dentsu Solution Center,這裡面的哪一個呢?"]] | |
| chat_history_message = [] | |
| # 問題清單 | |
| questions = [ | |
| {"id": 0, "content": "受訪者的任職的品牌", "keywords": ["品牌"], "answered": False}, | |
| {"id": 1, "content": "受訪者在集團服務的總年資(不同單位年資可合併計算)", "keywords": ["年資"], "answered": False}, | |
| {"id": 2, "content": "受訪者服務的客戶產業(如交通工具類/零售通路類/美妝與美容美髮類/醫療保健類/民生消費品類/電商與網路服務類/財務金融保險類/煙酒類/時尚精品類/家電類/電信通訊類/電腦與周邊設備類/休閒娛樂類/遊戲&APP類/其他)", "keywords": ["產業"], "answered": False}, | |
| {"id": 3, "content": "受訪者使用dentsu pro的頻率(如每周幾次、每月幾次、每季幾次或每半年幾次)", "keywords": ["使用頻率"], "answered": False}, | |
| {"id": 4, "content": "受訪者最常進入dentsu pro的起點(選項為桌面捷徑,電子報通知,My Apps連結,自行儲存網址(如我的最愛))", "keywords": ["入口方式"], "answered": False} | |
| ] | |
| check_json_schema = { | |
| "name": "CheckSchema", # 添加 name 字段 | |
| "description": "檢查使用者是否有回答問題", | |
| "strict": True, | |
| "schema": { # 修正,將之前的 Schema 放入 schema 字段 | |
| "type": "object", | |
| "properties":{ | |
| "question_0": { | |
| "type": "boolean", | |
| "description": "第一題「受訪者的任職的品牌」是否有被充分回答?(答案需要是Amplifi/Carat,凱絡/dentsu MB/dentsu One/dentsu X,貝立德/dentsu Consult/HQ/iProspect/isobar/Merkle/dentsu Solution Center,DSC其一)" | |
| }, | |
| "question_1": { | |
| "type": "boolean", | |
| "description": "第二題「受訪者在集團服務的總年資」是否有被充分回答?" | |
| }, | |
| "question_2": { | |
| "type": "boolean", | |
| "description": "第三題「受訪者服務的客戶產業」是否有被充分回答?" | |
| }, | |
| "question_3": { | |
| "type": "boolean", | |
| "description": "第四題「受訪者使用dentsu pro的頻率」是否有被充分回答?充分的定義:答案能被區分在每周幾次、每月幾次、每季幾次或每半年幾次。" | |
| }, | |
| "question_4": { | |
| "type": "boolean", | |
| "description": "第五題「受訪者最常進入dentsu pro的起點」是否有被充分回答?充分的定義:答案限制在(桌面捷徑,電子報通知,My Apps連結,自行儲存網址(如我的最愛))。" | |
| } | |
| } | |
| ,"required": [ | |
| "question_0", | |
| "question_1", | |
| "question_2", | |
| "question_3", | |
| "question_4" | |
| ], | |
| "additionalProperties": False | |
| } | |
| } | |
| analyze_json_schema = { | |
| "name": "AnalyzeSchema", # 添加 name 字段 | |
| "description": "紀錄使用者回答的結果", | |
| "strict": True, | |
| "schema": { # 修正,將之前的 Schema 放入 schema 字段 | |
| "type": "object", | |
| "properties": { | |
| "brand": { | |
| "type": "string", | |
| "description": "受訪者的任職的品牌" | |
| }, | |
| "seniority": { | |
| "type": "string", | |
| "description": "受訪者在集團服務的總年資" | |
| }, | |
| "service_industry": { | |
| "type": "string", | |
| "description": "受訪者服務的客戶產業" | |
| }, | |
| "frequency": { | |
| "type": "string", | |
| "description": "受訪者使用dentsu pro的頻率" | |
| }, | |
| "portal": { | |
| "type": "string", | |
| "description": "受訪者最常進入dentsu pro的起點" | |
| }, | |
| "interviewee_traits": { | |
| "type": "string", | |
| "description": "根據以上受訪者與AI的對話過程,分析出三個受訪者的性格特質" | |
| } | |
| } | |
| ,"required": [ | |
| "brand", | |
| "seniority", | |
| "service_industry", | |
| "frequency", | |
| "portal", | |
| "interviewee_traits" | |
| ], | |
| "additionalProperties": False | |
| } | |
| } | |
| def clear(): | |
| print("CLEEEEEEEEEEEEEEEER") | |
| def chatbot_system(user_input): | |
| with ThreadPoolExecutor(max_workers=3) as executor: | |
| fun_1 = executor.submit(analyze_user_input, user_input) | |
| isAnswered = fun_1.result() | |
| #會有一個true/fales | |
| fun_2 = executor.submit(generate_question, isAnswered ) | |
| assistant_output = fun_2.result() | |
| chat_history.append([user_input, assistant_output]) | |
| chat_history_message.extend([{"role": "user", "content": user_input},{"role": "assistant", "content": assistant_output}]) | |
| demand = "" | |
| if chat_question_index is None: | |
| print("ERROR:Noneeeeeeeeeeeee") | |
| dialogue = format_chat_history(chat_history) | |
| fun_3 = executor.submit(analyze_dialogue, dialogue ) | |
| demand = fun_3.result() | |
| return chat_history,demand | |
| def format_chat_history(chat_history): | |
| formatted_chat = "" | |
| for user_speech, ai_speech in chat_history: | |
| if user_speech is not None: | |
| formatted_chat += f"使用者: \"{user_speech}\"\n" | |
| formatted_chat += f"AI助手: \"{ai_speech}\"\n" | |
| return formatted_chat | |
| def generate_question(now_question_isAnswered): | |
| messages_base = [ | |
| {"role": "system", "content": "你是一個訪談助手,專門協助問卷訪談。其角色是透過輕鬆的對話一步一步引導受訪者了解他們的資訊,就像一位真實的訪談者。"} | |
| ] | |
| messages_base.extend(chat_history_message) | |
| completed_text = "" | |
| if(now_question_isAnswered): | |
| #檢查是否全部都回答完 | |
| chat_question = find_next_unanswered_question() | |
| global chat_question_index | |
| #if回答完:結束 | |
| if chat_question is None: | |
| chat_question_index = None | |
| print("所有問題均已回答。") | |
| completed_text = "我已經釐清你的基本資訊了,感謝你這次的作答。" | |
| #沒回答完,跳到下一題未回答問題 | |
| #請根據目前的聊天內容,生成後續的對話,這段對話的主旨在於了解「」 | |
| else: | |
| # print("next_q") | |
| # print(chat_question) | |
| chat_question_content = chat_question['content'] | |
| chat_question_index = chat_question['id'] | |
| # print(f"下一個未回答的問題主指是:{chat_question_content}") | |
| messages_base.extend([{"role": "user", "content": f"""請你延續先前的對話與使用者回答的內容,根據我現在想要了解使用者的問題:{chat_question_content},生成一句 | |
| 生動的提問,必須使用繁體中文。只要給我那個問題的內容就好,不要附加其他文字。"""}]) | |
| response = client.chat.completions.create( | |
| model='gpt-4o', | |
| max_tokens=4096, | |
| temperature=0.5, | |
| messages= messages_base) | |
| completed_text = response.choices[0].message.content | |
| else: | |
| completed_text = "抱歉,你好像沒有回答到我的問題呢,要不要多補充一點內容呢?" | |
| return completed_text | |
| def find_next_unanswered_question(): | |
| for question in questions: | |
| if not question['answered']: | |
| return question | |
| return None | |
| def analyze_user_input(user_input): | |
| print("analyze_user_input") | |
| messages_base = [ | |
| {"role": "system", "content": "你是一個回覆檢查員,你會根據收到的回覆,進行回覆檢核。"}, | |
| {"role": "user", "content": f"使用者輸入的內容如下:{user_input}"} | |
| ] | |
| response = client.chat.completions.create( | |
| model='gpt-4o', | |
| messages= messages_base, | |
| temperature=0.5, | |
| response_format={ | |
| "type": "json_schema", | |
| "json_schema": check_json_schema | |
| } | |
| ) | |
| arguments_str = response.choices[0].message.content | |
| arguments = json.loads(arguments_str) | |
| update_questions(questions, arguments) | |
| #從json_schema中得到當前問題是否有被回答 | |
| question_key = f"question_{chat_question_index}" | |
| print("question_key:") | |
| print(question_key) | |
| isAnswered = arguments[question_key] | |
| return isAnswered | |
| def analyze_dialogue(dialogue): | |
| messages_base = [ | |
| {"role": "system", "content": "你是一個對話檢查員,你會根據收到的對話紀錄,進行回覆分析。"}, | |
| {"role": "user", "content": f"整段對話如下:{dialogue}"} | |
| ] | |
| response = client.chat.completions.create( | |
| model='gpt-4o', | |
| messages= messages_base, | |
| temperature=0.5, | |
| response_format={ | |
| "type": "json_schema", | |
| "json_schema": analyze_json_schema | |
| } | |
| ) | |
| arguments_str = response.choices[0].message.content | |
| return arguments_str | |
| def update_questions(questions, validation_results): | |
| # 遍歷檢核結果的每一個項目 | |
| for key, value in validation_results.items(): | |
| # 從key中提取問題的id | |
| question_id = int(key.split('_')[1]) | |
| # 尋找對應id的問題 | |
| question = next((q for q in questions if q['id'] == question_id), None) | |
| if question: | |
| if value: | |
| # 如果檢核為True,更新答題狀態為True | |
| question['answered'] = True | |
| #------------------------------------------------------------ | |
| #歡迎句,問使用者可以開始了嗎? | |
| #開始 | |
| #從問題清單中,找一個還沒有回答的問題,生成問題(函式一),id=1 | |
| #接收使用者的輸入 | |
| #解析使用者的輸入(函式二) | |
| #1.是否有回答id=1的問題?答案是多少;是否有回答其他問題?答案是多少 | |
| #如果使用者有回答問題清單任一問題,填入答案,生成下一個問題,如果沒有 | |
| #如果使用者沒有回答題,繼續跟使用者進行互動,請使用者回答本題 | |
| demo = gr.Interface( | |
| fn=chatbot_system, | |
| inputs=[ | |
| gr.Textbox(label="對話") | |
| ], | |
| outputs=[ | |
| gr.Chatbot(label="Perosna",height=300,value=chat_history), | |
| gr.Textbox(label="對話陣列") | |
| ], | |
| title="訪談助手", | |
| description="透過與AI聊天,完成dentsu pro種子代表調查。", | |
| allow_flagging="never", ) | |
| demo.launch(share=True) | |