history_manager.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import json
  2. import os
  3. from typing import List, Dict
  4. from config.settings import HISTORY_DIR, TITLE_GENERATOR_PROMPT
  5. from core.agent_builder import model
  6. os.makedirs(HISTORY_DIR, exist_ok=True)
  7. def _session_file_path(session_id: str) -> str:
  8. return os.path.join(HISTORY_DIR, f"{session_id}.txt")
  9. def _generate_title(user_query: str) -> str:
  10. """Ask the LLM to produce a short title for a conversation."""
  11. prompt = f"{TITLE_GENERATOR_PROMPT}{user_query}"
  12. return model.invoke(prompt).content.strip()
  13. def get_or_create_title(session_id: str, user_message: str) -> str:
  14. """Return the existing title for *session_id*, or create one from *user_message*.
  15. New sessions get a title generated by the LLM and persisted as the first
  16. line of the history file. Existing sessions re-read that first line.
  17. """
  18. file_path = _session_file_path(session_id)
  19. if os.path.exists(file_path):
  20. with open(file_path, "r", encoding="utf-8") as file_handle:
  21. return file_handle.readline().strip()
  22. title = _generate_title(user_message)
  23. with open(file_path, "w", encoding="utf-8") as file_handle:
  24. file_handle.write(title + "\n")
  25. return title
  26. def append_line(session_id: str, event_type: str, content: str) -> None:
  27. """Append a single JSON log entry to the session history file."""
  28. file_path = _session_file_path(session_id)
  29. entry = json.dumps({"type": event_type, "content": content}, ensure_ascii=False) + "\n"
  30. # Touch the file first to ensure the title line exists
  31. with open(file_path, "a", encoding="utf-8"):
  32. pass
  33. with open(file_path, "a", encoding="utf-8") as file_handle:
  34. file_handle.write(entry)
  35. def fetch_all_sessions() -> List[Dict[str, str]]:
  36. """Return every session (id + title), sorted by last-modified time descending."""
  37. session_entries: List[Dict] = []
  38. for filename in os.listdir(HISTORY_DIR):
  39. if not filename.endswith(".txt"):
  40. continue
  41. session_id = filename[:-4]
  42. file_path = os.path.join(HISTORY_DIR, filename)
  43. try:
  44. modified_time = os.path.getmtime(file_path)
  45. except OSError:
  46. continue
  47. try:
  48. with open(file_path, "r", encoding="utf-8") as file_handle:
  49. title = file_handle.readline().strip()
  50. except Exception:
  51. title = "未知会话"
  52. session_entries.append({
  53. "session_id": session_id,
  54. "intent": title,
  55. "mtime": modified_time,
  56. })
  57. session_entries.sort(key=lambda entry: entry["mtime"], reverse=True)
  58. return [
  59. {"session_id": entry["session_id"], "intent": entry["intent"]}
  60. for entry in session_entries
  61. ]
  62. def fetch_session_detail(session_id: str) -> List[Dict]:
  63. """Return all log entries for *session_id*, excluding the title line."""
  64. file_path = _session_file_path(session_id)
  65. if not os.path.exists(file_path):
  66. return []
  67. entries: List[Dict] = []
  68. with open(file_path, "r", encoding="utf-8") as file_handle:
  69. lines = file_handle.readlines()
  70. for line in lines[1:]:
  71. stripped = line.strip()
  72. if not stripped:
  73. continue
  74. try:
  75. entries.append(json.loads(stripped))
  76. except json.JSONDecodeError:
  77. continue
  78. return entries
  79. def remove_session_file(session_id: str) -> bool:
  80. """Delete the history file for *session_id*. Returns True on success."""
  81. file_path = _session_file_path(session_id)
  82. if not os.path.exists(file_path):
  83. return False
  84. try:
  85. os.remove(file_path)
  86. return True
  87. except OSError as exc:
  88. print(f"删除会话失败: {exc}")
  89. return False