Amity123 commited on
Commit
6a4fcaf
·
verified ·
1 Parent(s): 54d9979

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -37
app.py CHANGED
@@ -2,6 +2,7 @@ from openai import OpenAI
2
  import gradio as gr
3
  import numpy as np
4
 
 
5
  client = OpenAI(api_key="你的OPENAI_API_KEY")
6
 
7
  # ============ 1. 定義主要專業領域 ============ #
@@ -14,42 +15,60 @@ PROFESSIONS = {
14
  "設計": "你是一位設計師,回答必須專業、詳細,提供設計步驟與案例。"
15
  }
16
 
17
- # ============ 2. 預先建立職業向量庫 ============ #
18
  def get_embedding(text, model="text-embedding-3-small"):
 
 
 
19
  emb = client.embeddings.create(input=text, model=model)
20
  return np.array(emb.data[0].embedding)
21
 
22
- profession_embeddings = {field: get_embedding(field) for field in PROFESSIONS.keys()}
 
 
 
 
 
23
 
24
  # ============ 3. NLP 判斷最接近職業 ============ #
25
  def detect_profession(detail: str) -> str:
 
26
  if not detail.strip():
27
  return "你是一個專業顧問,回答必須專業、詳細、可操作。"
28
 
29
  detail_emb = get_embedding(detail)
30
-
31
- scores = {}
32
- for field, emb in profession_embeddings.items():
33
- scores[field] = np.dot(detail_emb, emb) / (np.linalg.norm(detail_emb) * np.linalg.norm(emb))
34
-
35
  best_field = max(scores, key=scores.get)
36
  return PROFESSIONS[best_field]
37
 
38
- # ============ 4. AI Agent 回答 ============ #
39
- def professional_agent(user_input, main_field, detail, chat_history=[]):
40
- if main_field:
41
- system_prompt = PROFESSIONS.get(main_field, "你是一個專業顧問,回答必須專業、詳細、可操作。")
42
- else:
43
- system_prompt = detect_profession(detail)
44
-
45
- messages = [{"role": "system", "content": system_prompt}]
46
-
47
- for h in chat_history:
 
 
 
 
 
 
 
 
 
 
 
48
  messages.append({"role": "user", "content": h[0]})
49
  messages.append({"role": "assistant", "content": h[1]})
50
-
51
  messages.append({"role": "user", "content": user_input})
52
-
53
  try:
54
  response = client.chat.completions.create(
55
  model="gpt-4o-mini",
@@ -59,28 +78,25 @@ def professional_agent(user_input, main_field, detail, chat_history=[]):
59
  answer = response.choices[0].message.content
60
  except Exception as e:
61
  answer = f"發生錯誤: {str(e)}"
62
-
63
- chat_history.append((user_input, answer))
64
- if len(chat_history) > 10:
65
- chat_history = chat_history[-10:]
66
-
67
- return answer, chat_history
68
 
69
  # ============ 5. Gradio 介面 ============ #
70
  with gr.Blocks() as demo:
71
  gr.Markdown("## 🧑‍💼 全職業專業 AI 顧問 (NLP 智能判斷)")
72
-
73
- with gr.Row():
74
- main_field = gr.Dropdown(["", *list(PROFESSIONS.keys())], label="主要領域 (可選)", value="")
75
- detail = gr.Textbox(label="細部說明 (例如: 會計師、骨科醫師、前端工程師)")
76
-
77
  chatbot = gr.Chatbot()
78
- msg = gr.Textbox(label="輸入你的問題")
79
- state = gr.State([])
80
-
81
- def chat(user_input, main_field, detail, chat_history):
82
- return professional_agent(user_input, main_field, detail, chat_history)
83
-
84
- msg.submit(chat, [msg, main_field, detail, state], [chatbot, state])
85
 
86
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
2
  import gradio as gr
3
  import numpy as np
4
 
5
+ # 初始化 OpenAI 客戶端
6
  client = OpenAI(api_key="你的OPENAI_API_KEY")
7
 
8
  # ============ 1. 定義主要專業領域 ============ #
 
15
  "設計": "你是一位設計師,回答必須專業、詳細,提供設計步驟與案例。"
16
  }
17
 
18
+ # ============ 2. Embedding 工具 (UTF-8 安全) ============ #
19
  def get_embedding(text, model="text-embedding-3-small"):
20
+ if not isinstance(text, str):
21
+ text = str(text)
22
+ text = text.encode("utf-8", "ignore").decode("utf-8")
23
  emb = client.embeddings.create(input=text, model=model)
24
  return np.array(emb.data[0].embedding)
25
 
26
+ profession_embeddings = {} # 延遲初始化
27
+
28
+ def ensure_embeddings():
29
+ global profession_embeddings
30
+ if not profession_embeddings:
31
+ profession_embeddings = {field: get_embedding(field) for field in PROFESSIONS.keys()}
32
 
33
  # ============ 3. NLP 判斷最接近職業 ============ #
34
  def detect_profession(detail: str) -> str:
35
+ ensure_embeddings()
36
  if not detail.strip():
37
  return "你是一個專業顧問,回答必須專業、詳細、可操作。"
38
 
39
  detail_emb = get_embedding(detail)
40
+ scores = {
41
+ field: np.dot(detail_emb, emb) / (np.linalg.norm(detail_emb) * np.linalg.norm(emb))
42
+ for field, emb in profession_embeddings.items()
43
+ }
 
44
  best_field = max(scores, key=scores.get)
45
  return PROFESSIONS[best_field]
46
 
47
+ # ============ 4. AI Agent 回答邏輯 ============ #
48
+ def professional_agent(user_input, state):
49
+ """
50
+ state 結構:
51
+ {
52
+ "chat_history": [(user, assistant), ...],
53
+ "profession_prompt": None or str
54
+ }
55
+ """
56
+
57
+ # 如果尚未設定專業 → 第一輪一定是輸入職業
58
+ if state.get("profession_prompt") is None:
59
+ profession_prompt = detect_profession(user_input)
60
+ state["profession_prompt"] = profession_prompt
61
+ answer = f"✅ 已設定你的專業領域。接下來請提出問題。"
62
+ state["chat_history"].append((user_input, answer))
63
+ return answer, state["chat_history"], state
64
+
65
+ # 正常對話
66
+ messages = [{"role": "system", "content": state["profession_prompt"]}]
67
+ for h in state["chat_history"]:
68
  messages.append({"role": "user", "content": h[0]})
69
  messages.append({"role": "assistant", "content": h[1]})
 
70
  messages.append({"role": "user", "content": user_input})
71
+
72
  try:
73
  response = client.chat.completions.create(
74
  model="gpt-4o-mini",
 
78
  answer = response.choices[0].message.content
79
  except Exception as e:
80
  answer = f"發生錯誤: {str(e)}"
81
+
82
+ state["chat_history"].append((user_input, answer))
83
+ if len(state["chat_history"]) > 10:
84
+ state["chat_history"] = state["chat_history"][-10:]
85
+
86
+ return answer, state["chat_history"], state
87
 
88
  # ============ 5. Gradio 介面 ============ #
89
  with gr.Blocks() as demo:
90
  gr.Markdown("## 🧑‍💼 全職業專業 AI 顧問 (NLP 智能判斷)")
91
+ gr.Markdown("👉 第一次請先輸入你的職業,例如:`會計師`、`骨科醫師`、`前端工程師`")
92
+
 
 
 
93
  chatbot = gr.Chatbot()
94
+ msg = gr.Textbox(label="輸入訊息")
95
+ state = gr.State({"chat_history": [], "profession_prompt": None})
96
+
97
+ def chat(user_input, state):
98
+ return professional_agent(user_input, state)
99
+
100
+ msg.submit(chat, [msg, state], [chatbot, state, state])
101
 
102
  demo.launch(server_name="0.0.0.0", server_port=7860)