HelenaXH commited on
Commit
49c7b41
·
verified ·
1 Parent(s): 1e37b6d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -213
app.py CHANGED
@@ -4,13 +4,13 @@ import os
4
 
5
  # ============================ 用户信息结构 ============================
6
  user_profile = {
7
- "mode": None,
8
- "specific_career": None,
9
- "bg_info": None,
10
- "work_value": None,
11
- "personality_summary": None,
12
- "dream_day": None,
13
- "forward_direction_choice": None
14
  }
15
 
16
  # ============================ 基础问题 ============================
@@ -20,20 +20,13 @@ base_questions = [
20
 
21
  # ============================ Forward 模式问题 ============================
22
  forward_additional_questions = [
23
- ("bg_info", """那么接下来我会需要你提供一些你的资料,并分享一些你的性格和喜好会分析然后给推荐定制可行方向
24
- 接下来,请你首先提供你的学术背景:你的学校、年级、专业,和主修课程是什么?如果能提供你的选课表或 resume 就最好啦。"""),
25
 
26
- ("work_value", """好!接下来我想更深入地了解
27
- 你认为“工作”的意义是什么?你觉得一份理想的工作,应该带来哪些价值或满足感?
28
- 你可以从以下几个角度思考,也可以自由表达:
29
- - 是可以帮助他人?实现社会影响力?
30
- - 还是可以赚大钱?获得物质回报?
31
- - 或者是自由时间?个人成长?创意空间?
32
- 举个例子更好哦~"""),
33
 
34
- ("personality_summary", "你能不能用几句话总结一下自己的性格比如外向喜欢挑战注重细节讨厌重复..."),
35
 
36
- ("dream_day", "你能描述一下你理想工作的一天是什么样的吗?你在哪工作?做什么?谁合作?忙还是闲?更自由还是更有秩序?")
37
  ]
38
 
39
  # ============================ Backward 模式问题 ============================
@@ -53,59 +46,168 @@ forward_done = False
53
  backward_done = False
54
  forward_recommendation_given = False
55
 
 
 
 
 
 
 
56
  # ============================ 模型设置 ============================
57
  model_default = "gpt-4o"
58
  token_default = 2000
59
  temp_default = 0.7
60
  top_p_default = 0.95
61
 
62
- # ============================ Prompt 生成函数 ============================
63
- def generate_system_prompt():
64
- mode = user_profile["mode"]
65
- specific_career = user_profile["specific_career"]
66
- bg_info = user_profile["bg_info"]
67
- work_value = user_profile["work_value"]
68
- personality_summary = user_profile["personality_summary"]
69
- dream_day = user_profile["dream_day"]
70
- forward_choice = user_profile.get("forward_direction_choice")
71
-
72
- if "是" in (mode or ""):
73
- return f"""
74
- 你是一位专业的职业规划顾问,使用Backward Design方法帮助学生达成他们的职业目标。
75
- 目标职业: {specific_career}
76
- 背景信息: {bg_info}
77
- 请提供
78
- 1. 该职业的简要分析
79
- 2. 排名前列的组织或公司
80
- 3. 所需技能和能力
81
- 4. 职业发展路径
82
- 5. 学术/课程建议、技能培养、资源使用、实习规划简历优化等
83
- 最后请用Markdown格式输出职路径图:
84
- 📍 现在 → 🎓 学习建议 → 💼 实践建议 → 📄 认证建议 → 🚀 求职建议
 
 
85
  """
86
- else:
87
- return f"""
88
- 你是一位专业的职业规划顾问,使用Forward Design方法帮助学生探索合适的职业路径。
89
- 学生背景:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  - 学术背景: {bg_info}
91
- - 工作意义: {work_value}
92
- - 性格总结: {personality_summary}
93
- - 理想一天: {dream_day}
94
- - 学生选择方向: {forward_choice}
95
- 请输出
96
- 1.生的优势、性格、价值观分析
97
- 2. 推荐3个具体职业,并说明日常工作内容、适配性、要求、准备路径
98
- 3. 最后输出职业路径图
99
- 📍 现在 → 🎓 学习建议 → 💼 实践建议 → 📄 认证建议 → 🚀 求职建议
 
 
 
100
  """
101
-
102
- # ============================ 主逻辑函数 ============================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  def predict(message, history):
104
  global current_q_index, questions
105
  global in_forward_flow, in_backward_flow
106
  global forward_index, backward_index
107
  global forward_done, backward_done
108
  global forward_recommendation_given
 
 
 
109
 
110
  # 第一次对话,重置
111
  if not history:
@@ -114,25 +216,26 @@ def predict(message, history):
114
  for key in user_profile:
115
  user_profile[key] = None
116
 
117
- in_forward_flow = False
118
- in_backward_flow = False
119
- forward_index = 0
120
- backward_index = 0
121
- forward_done = False
122
- backward_done = False
123
  forward_recommendation_given = False
 
 
 
 
124
 
125
- # ========== 存储 base_questions 回答 ==========
126
- # 如果还在问 base_questions(只有1题,就1个循环)
127
  if 0 < current_q_index <= len(questions):
128
  key = questions[current_q_index - 1][0]
129
  user_profile[key] = message.strip()
130
- # 如果回答了 mode 问题
131
  if key == "mode":
132
  if "是" in user_profile["mode"]:
 
133
  questions.insert(1, ("specific_career", "请具体描述你想要从事的职业方向。"))
134
  in_backward_flow = True
135
  elif "否" in user_profile["mode"]:
 
136
  in_forward_flow = True
137
 
138
  # 如果 base_questions 还没问完,就继续问
@@ -141,134 +244,129 @@ def predict(message, history):
141
  current_q_index += 1
142
  return nxt
143
 
144
- # ========== 进入 Forward / Backward 的额外问题 ==========
145
  mode = user_profile.get("mode") or ""
146
 
147
- # --- Backward 模式 ---
148
  if "是" in mode:
149
  if in_backward_flow and not backward_done:
150
- # 存储上一回答到 user_profile
151
- # backward_index > 0 才说明至少问过1个 backward问题
152
  if backward_index > 0 and backward_index <= len(backward_additional_questions):
153
  prev_key = backward_additional_questions[backward_index - 1][0]
154
  user_profile[prev_key] = message.strip()
155
 
156
- # 是否还有下一个问题
157
  if backward_index < len(backward_additional_questions):
158
  k, prompt_text = backward_additional_questions[backward_index]
159
  backward_index += 1
160
  return prompt_text
161
  else:
162
- # 问完了
163
  backward_done = True
164
 
165
- # --- Forward 模式 ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  else:
167
- if in_forward_flow and not forward_done:
168
- # 存储上一回答到 user_profile
169
- # forward_index > 0 才说明至少问过1个 forward问题
170
  if forward_index > 0 and forward_index <= len(forward_additional_questions):
171
  prev_key = forward_additional_questions[forward_index - 1][0]
172
  user_profile[prev_key] = message.strip()
173
 
174
- # 如果还有 Forward问题没问完
175
  if forward_index < len(forward_additional_questions):
176
  k, prompt_text = forward_additional_questions[forward_index]
177
  forward_index += 1
178
  return prompt_text
179
 
180
- # 如果 4 Forward问题都问完,还没推荐过方向
181
  elif not forward_recommendation_given:
182
  forward_recommendation_given = True
 
183
 
184
- print("===== Debug user_profile =====")
185
- print(user_profile)
186
-
187
- try:
188
- api_key = os.environ.get("API_TOKEN")
189
- if not api_key:
190
- return "错误:API_TOKEN 未设置,请在环境变量中添加。"
191
- client = OpenAI(api_key=api_key)
192
-
193
- recommendation_prompt = f"""
194
- 请根据以下信息,为这位学生撰写一份结构化、条理清晰的“人物画像分析”:
195
- - 学术背景: {user_profile['bg_info']}
196
- - 工作意义: {user_profile['work_value']}
197
- - 性格总结: {user_profile['personality_summary']}
198
- - 理想工作状态: {user_profile['dream_day']}
199
-
200
- 请分为两个主要部分:
201
-
202
- 一、人物画像分析:
203
- 1) 学校/专业背景与可能的优势
204
- 2) 职业价值观与工作偏好
205
- 3) 性格特点
206
- 4) 理想工作状态
207
-
208
- 二、推荐3个“大方向”:
209
- (A) 典型岗位或行业示例
210
- (B) 主要特点
211
- (C) 建议行动
212
-
213
- 在最后列出3个方向让学生从中选一个深入:
214
- 1. XXX方向
215
- 2. XXX方向
216
- 3. XXX方向
217
-
218
- 如果信息不足,请基于通用逻辑合理推断。请使用中文分段写作,字数不少于500字。
219
- """
220
-
221
- print("===== Debug recommendation_prompt =====")
222
- print(recommendation_prompt)
223
-
224
- msgs = [
225
- {"role": "system", "content": "你是一位专业的职业生涯顾问,善于总结用户信息并给出大方向建议。"},
226
- {"role": "user", "content": recommendation_prompt}
227
- ]
228
- resp = client.chat.completions.create(
229
- model=model_default,
230
- messages=msgs,
231
- max_tokens=token_default,
232
- temperature=temp_default,
233
- top_p=top_p_default,
234
- stream=False
235
- )
236
- return resp.choices[0].message.content
237
-
238
- except Exception as e:
239
- return f"生成推荐方向时出错: {str(e)}"
240
-
241
  else:
242
- # 已推荐过方向,现在用户输入了方向选择
243
- user_profile["forward_direction_choice"] = message.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  forward_done = True
245
-
246
- # 如果走到这里,说明 Backward_done / Forward_done
247
- if ("是" in mode and backward_done) or ("否" in mode and forward_done):
248
- try:
249
- api_key = os.environ.get("API_TOKEN")
250
- if not api_key:
251
- return "错误:API密钥未设置,请在环境变量中添加。"
252
-
253
- client = OpenAI(api_key=api_key)
254
- system_prompt = generate_system_prompt()
255
-
256
- msgs = [
257
- {"role": "system", "content": system_prompt},
258
- {"role": "user", "content": f"请根据我提供的信息,给我职业规划建议: {user_profile}. {message}"}
259
- ]
260
- resp = client.chat.completions.create(
261
- model=model_default,
262
- messages=msgs,
263
- max_tokens=token_default,
264
- temperature=temp_default,
265
- top_p=top_p_default,
266
- stream=False
267
- )
268
- return resp.choices[0].message.content
269
-
270
- except Exception as e:
271
- return f"发生错误: {str(e)}"
 
 
 
 
272
 
273
  return "信息收集完毕,若尚未得到最终回复,请输入任意文字以继续。"
274
 
@@ -330,32 +428,24 @@ footer {
330
  <div style='display: flex; align-items: center; justify-content: center; gap: 20px; margin-bottom: 10px;'>
331
  <img src='https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExMmFucGwxbmNsd3J5NXV0Y282NXNtMzNsZW5jMm4wNWh6c2dqbXIwdiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l41m18LjqpzxUr2WA/giphy.gif' width='200' style='border-radius: 12px; box-shadow: 0 0 10px #ec4899;'>
332
  <div style='text-align: left;'>
333
- <h1 style='color:white; font-size: 36px; margin-bottom: 6px;'>🎓 AI职业规划助手(修正版)</h1>
334
- <p style='font-size: 18px; font-weight:bold; color:#ec4899; margin-top: 0;margin-left: 150px'>让梦想照进现实 💖</p>
335
  </div>
336
  </div>
337
  """)
338
 
339
  gr.Markdown("""
340
- **📝 修正版:确保Forward / Backward问题回答也存入 user_profile**
341
- - 逐题逐答,不要一次性粘贴所有回答
342
- - 这样每个回答都会写进 user_profile,再进行下一题
 
343
  """)
344
 
345
- chatbot = gr.Chatbot(
346
- height=500,
347
- show_label=False,
348
- show_copy_button=True,
349
- type="messages"
350
- )
351
 
352
  with gr.Row():
353
  with gr.Column(scale=8):
354
- msg = gr.Textbox(
355
- placeholder="请在这里输入你的回答...",
356
- show_label=False,
357
- container=False
358
- )
359
  with gr.Column(scale=1):
360
  submit_btn = gr.Button("🚀 发送", elem_id="custom-send")
361
 
@@ -374,57 +464,42 @@ footer {
374
  history.append({"role": "assistant", "content": bot_message})
375
  return history
376
 
377
- submit_btn.click(
378
- fn=add_message,
379
- inputs=[msg, chatbot],
380
- outputs=[msg, chatbot]
381
- ).then(
382
- fn=bot_response,
383
- inputs=[chatbot],
384
- outputs=[chatbot]
385
- )
386
-
387
- msg.submit(
388
- fn=add_message,
389
- inputs=[msg, chatbot],
390
- outputs=[msg, chatbot]
391
- ).then(
392
- fn=bot_response,
393
- inputs=[chatbot],
394
- outputs=[chatbot]
395
- )
396
-
397
- def reset_conversation():
398
  global current_q_index, questions
399
  global in_forward_flow, in_backward_flow
400
  global forward_index, backward_index
401
  global forward_done, backward_done
402
  global forward_recommendation_given
 
 
 
403
 
404
  current_q_index = 0
405
  questions = base_questions[:]
406
  for key in user_profile:
407
  user_profile[key] = None
408
 
409
- in_forward_flow = False
410
- in_backward_flow = False
411
- forward_index = 0
412
- backward_index = 0
413
- forward_done = False
414
- backward_done = False
415
  forward_recommendation_given = False
 
 
 
 
 
416
  return []
417
 
418
- reset_btn.click(
419
- fn=reset_conversation,
420
- inputs=None,
421
- outputs=chatbot,
422
- queue=False
423
- )
424
 
425
  def auto_first_question():
426
  return [{"role": "assistant", "content": questions[0][1]}]
427
 
428
  demo.load(auto_first_question, inputs=None, outputs=chatbot)
429
  demo.launch()
430
-
 
4
 
5
  # ============================ 用户信息结构 ============================
6
  user_profile = {
7
+ "mode": None, # 是 / 否 (Backward / Forward)
8
+ "specific_career": None, # Backward 目标职业
9
+ "bg_info": None, # 学术背景
10
+ "work_value": None, # 工作意义
11
+ "personality_summary": None, # 性格总结
12
+ "dream_day": None, # 理想工作一天
13
+ "forward_direction_choice": None # 选的大方向
14
  }
15
 
16
  # ============================ 基础问题 ============================
 
20
 
21
  # ============================ Forward 模式问题 ============================
22
  forward_additional_questions = [
23
+ ("bg_info", """那么接下来我会需要你提供一些你的资料,并分享一些你的性格和喜好。请先告诉你的学校、年级、专业,和主修课程是什么?如果能提供你的选课表或resume就更好啦"""),
 
24
 
25
+ ("work_value", """非常好!认为“工作”的意义是什么?你觉得一份理想的工作,应该带来哪些价值或满足感?(例如:帮助他人、赚大钱、自由时间、个人成长、创意空间等)"""),
 
 
 
 
 
 
26
 
27
+ ("personality_summary", "用几句话总结你的性格比如外向/内向?喜欢挑战注重细节讨厌重复吗?"),
28
 
29
+ ("dream_day", "描述一下你理想工作的一天是什么样在哪工作?做什么?谁合作?忙还是闲?更自由还是更有秩序?")
30
  ]
31
 
32
  # ============================ Backward 模式问题 ============================
 
46
  backward_done = False
47
  forward_recommendation_given = False
48
 
49
+ # 新增:多次换方向、深度分析、路线图
50
+ recommendation_round = 0
51
+ forward_deep_dive_done = False
52
+ roadmap_offered = False
53
+ roadmap_done = False
54
+
55
  # ============================ 模型设置 ============================
56
  model_default = "gpt-4o"
57
  token_default = 2000
58
  temp_default = 0.7
59
  top_p_default = 0.95
60
 
61
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 路线图生成函数 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62
+ def do_time_roadmap():
63
+ direction = user_profile["forward_direction_choice"] or user_profile["specific_career"]
64
+ bg_info = user_profile["bg_info"] or "未知专业"
65
+ wv = user_profile["work_value"] or "暂无"
66
+ ps = user_profile["personality_summary"] or "暂无"
67
+ dd = user_profile["dream_day"] or "暂无"
68
+
69
+ # 生成路线图的prompt
70
+ prompt_roadmap = f"""
71
+ 学生信息:
72
+ - 学术背景:{bg_info}
73
+ - 职业方向:{direction}
74
+ - 工作价值:{wv}
75
+ - 性格:{ps}
76
+ - 理想工作{dd}
77
+
78
+ 请你使用时间轴方式,给出一个职业路线图,如:
79
+ 📍 Now: [当前阶段做什么]
80
+ 🎓 Year X: [需要选的课/要做的项目]
81
+ 💼 下个暑假: [申请什么实习、参加什么活动]
82
+ 📄 毕前: [考什么证书、准备材料]
83
+ 🚀 毕业后: [目标岗位、如何申请]
84
+
85
+ 请用Markdown分段写作,结合学生当前背景合理推断要点,写得具体些。
86
  """
87
+ try:
88
+ api_key = os.environ.get("API_TOKEN")
89
+ if not api_key:
90
+ return "错误:API_TOKEN 未设置"
91
+ client = OpenAI(api_key=api_key)
92
+
93
+ msgs = [
94
+ {"role":"system","content":"你是一位专业的职业规划顾问,会生成时间轴式路线图"},
95
+ {"role":"user","content": prompt_roadmap}
96
+ ]
97
+ resp = client.chat.completions.create(
98
+ model=model_default,
99
+ messages=msgs,
100
+ max_tokens=token_default,
101
+ temperature=temp_default,
102
+ top_p=top_p_default,
103
+ stream=False
104
+ )
105
+ return resp.choices[0].message.content
106
+ except Exception as e:
107
+ return f"生成路线图时出错: {str(e)}"
108
+
109
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 深度分析函数(3个具体职业) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110
+ def do_deep_analysis():
111
+ # 读取 user_profile
112
+ direction = user_profile["forward_direction_choice"] or "尚未选择"
113
+ bg_info = user_profile["bg_info"] or "未知背景"
114
+ wv = user_profile["work_value"] or "无"
115
+ ps = user_profile["personality_summary"] or "不详"
116
+ dd = user_profile["dream_day"] or "不详"
117
+
118
+ deep_prompt = f"""
119
+ 学生的最终方向: {direction}
120
+ 学生背景: {bg_info}
121
+ 价值观: {wv}
122
+ 性格: {ps}
123
+ 理想工作: {dd}
124
+
125
+ 请你再深入分析,为学生推荐3个更具体的职业,并说明:
126
+ 1. 这些职业对学生背景的契合度(机械工程/心理学/商科等都可)
127
+ 2. 日常工作内容
128
+ 3. 需要哪些课程或考试
129
+ 4. 本校资源如何利用
130
+ 5. 实习 & 经验积累建议
131
+ 6. 简历优化思路
132
+
133
+ 用中文分段写作,字数500+。
134
+ """
135
+ try:
136
+ api_key = os.environ.get("API_TOKEN")
137
+ if not api_key:
138
+ return "错误:API_TOKEN 未设置"
139
+ client = OpenAI(api_key=api_key)
140
+ msgs = [
141
+ {"role":"system","content": "你是一位专业职业顾问,会深度分析并列出3个具体职业。"},
142
+ {"role":"user","content": deep_prompt}
143
+ ]
144
+ resp = client.chat.completions.create(
145
+ model=model_default,
146
+ messages=msgs,
147
+ max_tokens=token_default,
148
+ temperature=temp_default,
149
+ top_p=top_p_default,
150
+ stream=False
151
+ )
152
+ return resp.choices[0].message.content
153
+ except Exception as e:
154
+ return f"深度分析出错: {str(e)}"
155
+
156
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 推荐大方向函数 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
+ def recommend_3directions():
158
+ # 读取 user_profile
159
+ bg_info = user_profile["bg_info"] or "未知"
160
+ wv = user_profile["work_value"] or "无"
161
+ ps = user_profile["personality_summary"] or "不详"
162
+ dd = user_profile["dream_day"] or "无"
163
+
164
+ rec_prompt = f"""
165
+ 请根据以下信息,写一份条理清晰的人物画像+3个大方向,并结尾让学生选1~3或‘换’:
166
  - 学术背景: {bg_info}
167
+ - 工作价值: {wv}
168
+ - 性格: {ps}
169
+ - 理想工作: {dd}
170
+
171
+ 分两部分
172
+ [一、人物画像]:1)术背景 2) 价值观 3) 性格 4) 理想工作
173
+ [二、推荐3个大方向]:每个方向(1~2段文字)
174
+ 最后用如下结尾
175
+ 1. XXX方向
176
+ 2. XXX方向
177
+ 3. XXX方向
178
+ 如都不满意,可输入'换'。
179
  """
180
+ try:
181
+ api_key = os.environ.get("API_TOKEN")
182
+ if not api_key:
183
+ return "错误:API_TOKEN 未设置"
184
+ client = OpenAI(api_key=api_key)
185
+ msgs = [
186
+ {"role":"system","content":"你是一位职业顾问,擅长根据用户资料推荐3大方向"},
187
+ {"role":"user","content":rec_prompt}
188
+ ]
189
+ resp = client.chat.completions.create(
190
+ model=model_default,
191
+ messages=msgs,
192
+ max_tokens=token_default,
193
+ temperature=temp_default,
194
+ top_p=top_p_default,
195
+ stream=False
196
+ )
197
+ return resp.choices[0].message.content
198
+ except Exception as e:
199
+ return f"多方向推荐出错: {str(e)}"
200
+
201
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ predict ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
202
  def predict(message, history):
203
  global current_q_index, questions
204
  global in_forward_flow, in_backward_flow
205
  global forward_index, backward_index
206
  global forward_done, backward_done
207
  global forward_recommendation_given
208
+ global recommendation_round
209
+ global forward_deep_dive_done
210
+ global roadmap_offered, roadmap_done
211
 
212
  # 第一次对话,重置
213
  if not history:
 
216
  for key in user_profile:
217
  user_profile[key] = None
218
 
219
+ in_forward_flow = in_backward_flow = False
220
+ forward_index = backward_index = 0
221
+ forward_done = backward_done = False
 
 
 
222
  forward_recommendation_given = False
223
+ recommendation_round = 0
224
+ forward_deep_dive_done = False
225
+ roadmap_offered = False
226
+ roadmap_done = False
227
 
228
+ # ~~~~~~~~~~ 存储 base_questions 回答 ~~~~~~~~~~
 
229
  if 0 < current_q_index <= len(questions):
230
  key = questions[current_q_index - 1][0]
231
  user_profile[key] = message.strip()
 
232
  if key == "mode":
233
  if "是" in user_profile["mode"]:
234
+ # Backward
235
  questions.insert(1, ("specific_career", "请具体描述你想要从事的职业方向。"))
236
  in_backward_flow = True
237
  elif "否" in user_profile["mode"]:
238
+ # Forward
239
  in_forward_flow = True
240
 
241
  # 如果 base_questions 还没问完,就继续问
 
244
  current_q_index += 1
245
  return nxt
246
 
 
247
  mode = user_profile.get("mode") or ""
248
 
249
+ # ======== Backward 流程 ========
250
  if "是" in mode:
251
  if in_backward_flow and not backward_done:
252
+ # 存储上一回答
 
253
  if backward_index > 0 and backward_index <= len(backward_additional_questions):
254
  prev_key = backward_additional_questions[backward_index - 1][0]
255
  user_profile[prev_key] = message.strip()
256
 
257
+ # 下一个问题
258
  if backward_index < len(backward_additional_questions):
259
  k, prompt_text = backward_additional_questions[backward_index]
260
  backward_index += 1
261
  return prompt_text
262
  else:
 
263
  backward_done = True
264
 
265
+ # 如果 backward_done
266
+ if backward_done:
267
+ # 直接进入最终
268
+ try:
269
+ api_key = os.environ.get("API_TOKEN")
270
+ if not api_key:
271
+ return "错误:API密钥未设置"
272
+ client = OpenAI(api_key=api_key)
273
+ system_prompt = generate_system_prompt()
274
+
275
+ msgs = [
276
+ {"role":"system","content": system_prompt},
277
+ {"role":"user","content": f"请根据信息{user_profile}给出完整规划"}
278
+ ]
279
+ resp = client.chat.completions.create(
280
+ model=model_default,
281
+ messages=msgs,
282
+ max_tokens=token_default,
283
+ temperature=temp_default,
284
+ top_p=top_p_default,
285
+ stream=False
286
+ )
287
+ return resp.choices[0].message.content
288
+ except Exception as e:
289
+ return f"发生错误: {str(e)}"
290
+
291
+ # ======== Forward 流程 ========
292
  else:
293
+ if in_forward_flow and not forward_done and not forward_deep_dive_done and not roadmap_done:
294
+ # 存储上一回答
 
295
  if forward_index > 0 and forward_index <= len(forward_additional_questions):
296
  prev_key = forward_additional_questions[forward_index - 1][0]
297
  user_profile[prev_key] = message.strip()
298
 
299
+ # 还有 Forward问题
300
  if forward_index < len(forward_additional_questions):
301
  k, prompt_text = forward_additional_questions[forward_index]
302
  forward_index += 1
303
  return prompt_text
304
 
305
+ # 如果4个Forward问完,还没推荐
306
  elif not forward_recommendation_given:
307
  forward_recommendation_given = True
308
+ return recommend_3directions()
309
 
310
+ # 已推荐过方向,等待学生选1/2/3 or '换'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  else:
312
+ choice = message.strip().lower()
313
+ # 如果是1/2/3 => 深度分析
314
+ if choice in ["1","2","3"]:
315
+ user_profile["forward_direction_choice"] = choice
316
+ # 进入深度分析
317
+ forward_deep_dive_done = True
318
+ return do_deep_analysis()
319
+ elif "换" in choice:
320
+ recommendation_round += 1
321
+ if recommendation_round > 2: # 最多换2次
322
+ forward_done = True
323
+ return "已多次换方向,先进入下个阶段吧。"
324
+ # 再次推荐
325
+ return recommend_3directions()
326
+ else:
327
+ return "请回复1/2/3选择方向,或输入'换'来请求新的推荐"
328
+
329
+ # 当深度分析完,才问路线图
330
+ elif forward_deep_dive_done and not roadmap_offered:
331
+ roadmap_offered = True
332
+ return "需要一个时间轴式的职业路线图吗?如果需要,请回复“是”,否则回复“否”。"
333
+
334
+ elif roadmap_offered and not roadmap_done:
335
+ ans = message.strip().lower()
336
+ if ans == "是":
337
+ roadmap_done = True
338
  forward_done = True
339
+ return do_time_roadmap()
340
+ else:
341
+ roadmap_done = True
342
+ forward_done = True
343
+ return "好的,不��成路线图,本次规划到此结束。"
344
+
345
+ # 如果 forward_done
346
+ if forward_done:
347
+ # 最终生成 or 就结束
348
+ try:
349
+ api_key = os.environ.get("API_TOKEN")
350
+ if not api_key:
351
+ return "错误:API密钥未设置"
352
+ client = OpenAI(api_key=api_key)
353
+ system_prompt = generate_system_prompt()
354
+
355
+ msgs = [
356
+ {"role":"system","content": system_prompt},
357
+ {"role":"user","content": f"以下是学生资料: {user_profile}. 如需更详细方案可再次输入问题"}
358
+ ]
359
+ resp = client.chat.completions.create(
360
+ model=model_default,
361
+ messages=msgs,
362
+ max_tokens=token_default,
363
+ temperature=temp_default,
364
+ top_p=top_p_default,
365
+ stream=False
366
+ )
367
+ return resp.choices[0].message.content
368
+ except Exception as e:
369
+ return f"发生错误: {str(e)}"
370
 
371
  return "信息收集完毕,若尚未得到最终回复,请输入任意文字以继续。"
372
 
 
428
  <div style='display: flex; align-items: center; justify-content: center; gap: 20px; margin-bottom: 10px;'>
429
  <img src='https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExMmFucGwxbmNsd3J5NXV0Y282NXNtMzNsZW5jMm4wNWh6c2dqbXIwdiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/l41m18LjqpzxUr2WA/giphy.gif' width='200' style='border-radius: 12px; box-shadow: 0 0 10px #ec4899;'>
430
  <div style='text-align: left;'>
431
+ <h1 style='color:white; font-size: 36px; margin-bottom: 6px;'>🎓 多步职业规划助手</h1>
432
+ <p style='font-size: 18px; font-weight:bold; color:#ec4899; margin-top: 0;'>Forward三步:推荐大方向→深度分析→可选时间轴路线图</p>
433
  </div>
434
  </div>
435
  """)
436
 
437
  gr.Markdown("""
438
+ **📝 Forward / Backward 多轮交互,附带换方向、深度分析、以及可选时间轴路线图**
439
+ 1. 如果你已明确职业目标 => 回答“是”(Backward)
440
+ 2. 如果还在探索 => 回答“否”(Forward)
441
+ 3. Forward模式下:先问4个问题→推荐3大方向→可换→选定后深度分析→询问是否要路线图
442
  """)
443
 
444
+ chatbot = gr.Chatbot(height=500, show_label=False, show_copy_button=True, type="messages")
 
 
 
 
 
445
 
446
  with gr.Row():
447
  with gr.Column(scale=8):
448
+ msg = gr.Textbox(placeholder="请在这里输入你的回答...", show_label=False, container=False)
 
 
 
 
449
  with gr.Column(scale=1):
450
  submit_btn = gr.Button("🚀 发送", elem_id="custom-send")
451
 
 
464
  history.append({"role": "assistant", "content": bot_message})
465
  return history
466
 
467
+ submit_btn.click(fn=add_message, inputs=[msg, chatbot], outputs=[msg, chatbot]) \
468
+ .then(fn=bot_response, inputs=[chatbot], outputs=[chatbot])
469
+
470
+ msg.submit(fn=add_message, inputs=[msg, chatbot], outputs=[msg, chatbot]) \
471
+ .then(fn=bot_response, inputs=[chatbot], outputs=[chatbot])
472
+
473
+ def reset_state():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
  global current_q_index, questions
475
  global in_forward_flow, in_backward_flow
476
  global forward_index, backward_index
477
  global forward_done, backward_done
478
  global forward_recommendation_given
479
+ global recommendation_round
480
+ global forward_deep_dive_done
481
+ global roadmap_offered, roadmap_done
482
 
483
  current_q_index = 0
484
  questions = base_questions[:]
485
  for key in user_profile:
486
  user_profile[key] = None
487
 
488
+ in_forward_flow = in_backward_flow = False
489
+ forward_index = backward_index = 0
490
+ forward_done = backward_done = False
 
 
 
491
  forward_recommendation_given = False
492
+ recommendation_round = 0
493
+ forward_deep_dive_done = False
494
+ roadmap_offered = False
495
+ roadmap_done = False
496
+
497
  return []
498
 
499
+ reset_btn.click(fn=reset_state, inputs=None, outputs=chatbot, queue=False)
 
 
 
 
 
500
 
501
  def auto_first_question():
502
  return [{"role": "assistant", "content": questions[0][1]}]
503
 
504
  demo.load(auto_first_question, inputs=None, outputs=chatbot)
505
  demo.launch()