import os import gradio as gr from openai import OpenAI from typing import Optional # 如需使用 Claude,請先安裝 "anthropic" 套件: pip install anthropic try: from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT except ImportError: Anthropic = None HUMAN_PROMPT = "" AI_PROMPT = "" # 取得金鑰 gpt_key = os.environ.get("gptkey", "") claude_api_key = os.environ.get("claudekey", "") # 建立 OpenAI Client (新版) client = OpenAI( api_key=gpt_key, ) # 定義每個類型的句子 achievement_statements = [ "比起把事情做到完美,我更傾向優先準時完成任務", "我總是在與他人比較", "我在派對中是屬於帶動氣氛的靈魂人物", "在社交場合中,我是比較活潑的類型", "我的工作成就必須被他人看見", ] emotion_statements = [ "對我而言,團隊合作在工作上是不可或缺的要素", "在朋友眼中,我是最適合傾訴心事的對象", "對我而言,樂在生活是最重要的", "我不太擅長批評他人", "我常需要「被別人需要」的感覺", ] information_statements = [ "很多事情,我傾向自己去找尋事實與資訊", "我喜歡與他人分享我所知道的事情", ] possession_statements = [ "我總是在尋找接下來想買的東西", "我認為從零開始是發揮創意的大好機會,並不是挑戰", "若家中環境不夠整潔,我無法放鬆", "我捨不得丟棄目前用不到的物品", ] power_statements = [ "當我有想要的東西時,我會排除任何阻礙", "我喜歡依照自己的方式做事,並自己做決定", "當事物成為大眾主流時,我就會對它失去興趣", "我總是能讓他人聽從我的要求做事", "我喜歡向他人展現自己比他們更為優越", ] status_statements = [ "我從不談論自己的缺點", "我不會去挑戰我認為會失敗的新事物", "我會用盡所有方法維護我的名聲", "比起和他人待在一起,我更喜歡獨處", ] ############################################ # 產生 Prompt ############################################ def generate_prompt(achievement: str, emotion: str, information: str, possession: str, power: str, status: str, extra_prompt: str) -> str: category_map = { '成就型': achievement_statements, '情感型': emotion_statements, '資訊型': information_statements, '佔有型': possession_statements, '權力型': power_statements, '地位型': status_statements } user_choices = { '成就型': achievement, '情感型': emotion, '資訊型': information, '佔有型': possession, '權力型': power, '地位型': status, } ''' tendencies = "你的六大動機傾向分別是:" + "、".join([ f"{key}的{'正面' if val == '正' else '負面'}傾向" for key, val in user_choices.items() ]) + "。\n\n" ''' tendencies = "" if extra_prompt.strip(): tendencies += extra_prompt.strip() + "\n\n" prompt = "以下是你的性格特徵,請嚴格的基於這些句子塑造你的角色:\n\n" + tendencies for category, choice in user_choices.items(): label = "我同意" if choice == "正" else "我不同意" prompt += f"{label}以下觀點\n" for statement in category_map[category]: prompt += f"- {statement}\n" prompt += "\n" prompt += "請以這些特徵為基礎,建構你的角色思考與表達方式,創造一個完整人設(包含姓名、性別、年齡、職業...等),完成指定任務。\n你生活在台灣,一律使用繁體中文。" return prompt ############################################ # 模型呼叫與回答整合 ############################################ def call_openai_api_4o(prompt: str) -> str: if not client.api_key: return "[OpenAI API Key 未設定,無法呼叫 API]" try: chat_completion = client.chat.completions.create( messages=[{"role": "user", "content": prompt}], model="gpt-4o", temperature=0.7, max_tokens=2048, ) return chat_completion.choices[0].message.content except Exception as e: return f"[OpenAI API 呼叫失敗]: {str(e)}" def call_openai_api_o1(prompt: str) -> str: if not client.api_key: return "[OpenAI API Key 未設定,無法呼叫 API]" try: chat_completion = client.chat.completions.create( messages=[{"role": "user", "content": prompt}], model="o1", temperature=0.7, max_tokens=2048, ) return chat_completion.choices[0].message.content except Exception as e: return f"[OpenAI API 呼叫失敗]: {str(e)}" def call_claude_api(prompt: str) -> str: if not claude_api_key or not Anthropic: return "[Claude API Key 未設定或未安裝 anthropic 套件,無法呼叫 API]" try: client_claude = Anthropic(api_key=claude_api_key) response = client_claude.messages.create( model="claude-3-5-sonnet-20241022", system="You are a helpful assistant.", messages=[{"role": "user", "content": prompt}], max_tokens=2048, temperature=0.7, ) text = response.content if isinstance(text, list): text = ' '.join(str(item) for item in text) return text.strip() except Exception as e: return f"[Claude API 呼叫失敗]: {str(e)}" def get_model_answer(model_choice: str, final_prompt: str, question: str) -> str: content_to_send = final_prompt + "\n\n" + question if model_choice == "ChatGPT 4o": return call_openai_api_4o(content_to_send) elif model_choice == "ChatGPT o1": return call_openai_api_o1(content_to_send) elif model_choice == "Claude 3.5 Sonnet": return call_claude_api(content_to_send) else: return "[錯誤] 未知的模型選擇" ############################################ # Gradio 介面 ############################################ def main(): questions = { "請介紹你自己": "請介紹你自己,讓我們了解你是什麼樣的人。你可以分享你的經歷、興趣、價值觀,以及未來規劃。特別說明一下,當你遇到挑戰時,你通常會如何面對?", "如何分配意外收入": "如果你突然收到一筆意外收入,你會如何分配這筆錢來購物?請列出前三項想購買的東西,並說明購買原因。", "新專案團隊問題": "假設你被指派帶領一個新專案,但發現團隊成員能力參差不齊,預算有限,且截止日期緊迫,你會如何處理?", "自訂提問": "" } with gr.Blocks() as demo: gr.Markdown("## AI Persona 模擬") with gr.Row(): achievement = gr.Radio(["正", "負"], label="成就型", value="正") emotion = gr.Radio(["正", "負"], label="情感型", value="正") information = gr.Radio(["正", "負"], label="資訊型", value="正") possession = gr.Radio(["正", "負"], label="佔有型", value="正") power = gr.Radio(["正", "負"], label="權力型", value="正") status = gr.Radio(["正", "負"], label="地位型", value="正") extra = gr.Textbox(label="Prompt 補充", lines=10, value="""我是一位知識導向、前瞻思維且重視資訊透明的人。他相信專業評論與產業標準,勝於人際口耳。他在消費行為上極為理性與審慎,偏好研究比較所有選項後再做決定。他對科技與金融趨勢具高度敏感,樂於探索 AI、Web3、虛擬貨幣等創新應用,並具備實際使用經驗。此人同時具藝術與文化素養,樂於學習並追求生活多樣性,例如旅行、跨文化交流與健康飲食。他重視品牌倫理與產品溯源,也樂於與他人分享觀點,常是朋友圈中的資訊來源。他對未來保持樂觀,並積極追求個人成長與財務自由。 我高度重視品牌形象與道德價值,偏好具專業推薦、知名度高且有社會責任感的品牌。他/她/他們在美妝與穿著上極具自我風格,追求時尚同時也重視舒適與個人健康。外表對這個人來說是一種自我表達的語言,願意投入高額預算在造型與個人形象上,並在意他人對自身外貌與品味的看法。 我對於國家認同感強,具正向形象,但可能會壓抑內心情緒。生活態度審慎,會因宏觀經濟情勢調整重大消費決策。在休閒選擇上偏好安靜、私密的空間,並有意識地選擇支持環保與社會責任的企業,甚至會因品牌的政治立場而停止使用。此人對時尚敏感,重視設計師品牌與象徵個人風格的物品(如汽車),但也有現實考量與內在拉扯。""") generate = gr.Button("生成 Prompt") prompt_box = gr.Textbox(label="生成的 Prompt", lines=10) generate.click(fn=generate_prompt, inputs=[achievement, emotion, information, possession, power, status, extra], outputs=prompt_box) model_select = gr.Radio(["ChatGPT 4o", "ChatGPT o1", "Claude 3.5 Sonnet"], label="選擇模型", value="ChatGPT 4o") q_select = gr.Radio(list(questions.keys()), label="選擇一個提問", value="請介紹你自己") q_text = gr.Markdown(value=questions["請介紹你自己"]) q_input = gr.Textbox(label="自訂提問 (若選擇 '自訂提問' 時才使用)", lines=2) answer = gr.Textbox(label="模型回應", lines=10) ask = gr.Button("送出問題並取得回答") ask.click( fn=lambda a, e, i, p, pow_, s, extra, m_choice, q_choice, c_question: get_model_answer( m_choice, generate_prompt(a, e, i, p, pow_, s, extra), c_question.strip() if q_choice == "自訂提問" and c_question.strip() else questions[q_choice] ) if not (q_choice == "自訂提問" and not c_question.strip()) else "[錯誤] 你選擇了自訂提問,但沒有輸入內容", inputs=[achievement, emotion, information, possession, power, status, extra, model_select, q_select, q_input], outputs=answer ) def update_q_text(choice): return questions[choice] q_select.change(fn=update_q_text, inputs=q_select, outputs=q_text) demo.launch() if __name__ == "__main__": main()