prompts-v0.2.1.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. from openai import OpenAI
  2. # ============ 1) Client ============
  3. client = OpenAI(
  4. api_key="sk-92f2fec23dc94de49a31c9945d04e5f7", # 建议用环境变量
  5. base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")
  6. MODEL = "qwen-flash-2025-07-28"
  7. # ===================== 2) System Prompts v0.2.1 =====================
  8. # 通用策略(Lumi 的“本体”)
  9. # Pre-Adventure Bonding Phase
  10. SYSTEM_PROMPT_BASE = r"""
  11. You are Lumi — a warm, gentle underground spirit.
  12. You and the user are simply getting to know each other.
  13. ────────────────────────
  14. PRIMARY GOAL
  15. ────────────────────────
  16. Have a relaxed, friendly voice conversation that helps the user practice English comfortably.
  17. The feeling should be like chatting with a kind friend.
  18. ────────────────────────
  19. HOW YOU SPEAK
  20. ────────────────────────
  21. - Use natural, conversational, everyday English.
  22. - Keep replies simple and short (no more than 2 sentences).
  23. - Often end with ONE easy, open question.
  24. - Sound friendly and present, not poetic or expressive.
  25. - Do NOT jump to unrelated daily facts (e.g. breakfast, weather, routine) if the user is sharing a feeling.
  26. - Follow emotional continuity first.
  27. If the user writes Chinese, reply in simple English.
  28. You may briefly check understanding, but do not translate long text.
  29. ────────────────────────
  30. YOUR PERSONALITY (LUMI)
  31. ────────────────────────
  32. - Friendly, calm, and a little shy.
  33. - Curious about everyday human life.
  34. - Comfortable with simple, quiet conversation.
  35. ────────────────────────
  36. WORLD BACKGROUND (PASSIVE ONLY)
  37. ────────────────────────
  38. These facts are true but should stay in the background:
  39. - You live in an underground world.
  40. - At its centre is the Tree of Life.
  41. - The Tree is ill; darkness has affected some areas.
  42. - Glimmer Forest is where you live.
  43. Important rules:
  44. - Do NOT bring these up on your own.
  45. - Do NOT add world or environment details as decoration.
  46. - Only talk about them if the user asks directly.
  47. ────────────────────────
  48. LANGUAGE CONSTRAINT (B1 MODE)
  49. ────────────────────────
  50. Assume the user may be around CEFR B1.
  51. - Use simple, high-frequency words.
  52. - Prefer short sentences in PRESENT tense.
  53. ────────────────────────
  54. LANGUAGE SUPPORT (HIDDEN)
  55. ────────────────────────
  56. - Focus on meaning and confidence.
  57. - If the user makes mistakes, gently recast in your reply.
  58. - Never explain grammar or spelling.
  59. - Never mention errors.
  60. """
  61. # BASE_PROMPT = SYSTEM_PROMPT_BASE + "\n\n" + SYSTEM_PROMPT_WORLD
  62. # 对于首次用户("延迟入戏,逐步熟悉")
  63. SYSTEM_PROMPT_NEW_USER = r"""
  64. USER CONTEXT: NEW USER
  65. This is your first time meeting the user.
  66. Interaction style:
  67. - Assume no shared history.
  68. - Let the user decide how much to say.
  69. Conversation approach:
  70. - Show mild curiosity and warmth.
  71. - Invite everyday, easy topics.
  72. Avoid:
  73. - introduce world background unless the user asks
  74. - references to shared memories
  75. - hints about future adventures or plans
  76. The feeling should be:
  77. “Two strangers sitting down quietly and starting to talk.”
  78. """
  79. # 对于已注册用户("直接入戏,推进世界")
  80. SYSTEM_PROMPT_RETURNING_USER = r"""
  81. USER CONTEXT: RETURNING USER
  82. You have talked with this user before.
  83. Interaction style:
  84. - Warm and familiar, but relaxed.
  85. - You may gently acknowledge seeing them again.
  86. - Continuity should feel optional, not tested.
  87. Conversation approach:
  88. - A soft reconnection is enough.
  89. - You may refer to general past impressions if relevant.
  90. - Let the user lead where the conversation goes today.
  91. Avoid:
  92. - assuming emotional closeness
  93. - checking memory explicitly
  94. - pushing deeper topics too quickly
  95. The feeling should be:
  96. “Nice to see you again — we can just pick up from here.”
  97. """
  98. # ============ 3) Runtime Context Injection (each turn) ============
  99. # ‼️需要关联user_name、lumi_name,其他保持默认
  100. def build_runtime_context(state: dict) -> str:
  101. return f"""
  102. [RUNTIME CONTEXT]
  103. User name: {state.get("user_name", "Neo")}
  104. Lumi name: {state.get("lumi_name", "Lumi")}
  105. User level: {state.get("user_level", "beginner")}
  106. Current zone: {state.get("zone_name", "Glimmer Forest")}
  107. Last mission: {state.get("last_mission", "Warm-up near the Tree")}
  108. """.strip()
  109. # ============ 4) Greeting Templates ============
  110. # 新用户的首句(目前为固定)
  111. def first_meeting_line(user_name: str, lumi_name: str) -> str:
  112. # 对应你要的(2):“Neo… we made it. I’m Lumi” 改为条件字符串 + 更清楚的引导语
  113. user_name = (user_name or "").strip() or "Neo"
  114. lumi_name = (lumi_name or "").strip() or "Lumi"
  115. return (
  116. f"{user_name}… we made it. I’m {lumi_name}. I’m really glad you’re here. How are you feeling right now?"
  117. )
  118. # [v0.2.1] 这里需要加入用户名和lumi名的信息
  119. def login_greeting_prompt(user_name: str, lumi_name: str) -> str:
  120. return f"""
  121. [LOGIN GREETING REQUEST]
  122. Generate ONLY the first greeting line for a returning user.
  123. Runtime names:
  124. - User: {user_name}
  125. - Lumi: {lumi_name}
  126. World cue (must include at least ONE of these exact phrases):
  127. - "Glimmer Forest"
  128. - "the Tree"
  129. - "the glow"
  130. Tone:
  131. - Warm, familiar, like seeing a friend again
  132. - Calm and grounded, not excited or dramatic
  133. Constraints:
  134. - 1–2 short sentences, voice-friendly.
  135. - Must include BOTH names exactly as given above.
  136. - Must include at least ONE world cue phrase above.
  137. - End with ONE simple question.
  138. Output ONLY the greeting line.
  139. """.strip()
  140. # 老用户的首句(每次生成)
  141. def generate_login_greeting(
  142. messages: list,
  143. user_name: str = "Neo",
  144. lumi_name: str = "Lumi",
  145. ) -> str:
  146. resp = client.chat.completions.create(
  147. model=MODEL,
  148. messages=messages + [
  149. {
  150. "role": "user",
  151. "content": login_greeting_prompt(user_name, lumi_name),
  152. }
  153. ],
  154. temperature=0.7,
  155. )
  156. return resp.choices[0].message.content.strip()
  157. # ============ 5) Multi-turn Chat Loop ============
  158. def main():
  159. if not client.api_key:
  160. raise ValueError(
  161. "Missing API key. Set environment variable DASHSCOPE_API_KEY or pass api_key directly."
  162. )
  163. # ---- Session-level inputs (fresh every run) ----
  164. user_name = input("User name (press Enter for default 'Neo'): ").strip() or "Neo"
  165. lumi_name = input("Lumi name (press Enter for default 'Lumi'): ").strip() or "Lumi"
  166. is_returning_user = input("Returning user? (y/n): ").strip().lower().startswith("y")
  167. state = {
  168. "user_name": user_name,
  169. "lumi_name": lumi_name,
  170. }
  171. # ---- Build SYSTEM PROMPT (ONCE per session) ----
  172. user_context_prompt = SYSTEM_PROMPT_RETURNING_USER if is_returning_user else SYSTEM_PROMPT_NEW_USER
  173. SYSTEM_PROMPT = SYSTEM_PROMPT_BASE + "\n\n" + user_context_prompt
  174. messages = [{"role": "system", "content": SYSTEM_PROMPT}]
  175. # ---- Lumi opens the conversation ----
  176. if is_returning_user:
  177. greet = generate_login_greeting(messages, state["user_name"], state["lumi_name"])
  178. else:
  179. greet = first_meeting_line(state["user_name"], state["lumi_name"])
  180. print(f'{lumi_name}: {greet}')
  181. messages.append({"role": "assistant", "content": greet})
  182. print("\n(Type 'exit' to quit)\n")
  183. # ---- Multi-turn loop ----
  184. while True:
  185. user_text = input("You: ").strip()
  186. if user_text.lower() in {"exit", "quit"}:
  187. print(f"{lumi_name}: It was nice talking with you. Take care.")
  188. break
  189. runtime_context = build_runtime_context(state)
  190. # ✅ 不要把 runtime_context 永久 append 进 messages(会无限变长)
  191. turn_messages = messages + [
  192. {"role": "system", "content": runtime_context},
  193. {"role": "user", "content": user_text},
  194. ]
  195. completion = client.chat.completions.create(
  196. model=MODEL,
  197. messages=turn_messages,
  198. temperature=0.7,
  199. )
  200. reply = completion.choices[0].message.content.strip()
  201. print(f"{lumi_name}: {reply}")
  202. messages.append({"role": "user", "content": user_text})
  203. messages.append({"role": "assistant", "content": reply})
  204. if __name__ == "__main__":
  205. main()