您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. from contextlib import contextmanager
  2. from datetime import datetime
  3. from typing import Optional, Union
  4. from urllib.parse import urlparse
  5. from extensions.ext_database import db
  6. from models.model import Message
  7. def filter_none_values(data: dict):
  8. new_data = {}
  9. for key, value in data.items():
  10. if value is None:
  11. continue
  12. if isinstance(value, datetime):
  13. new_data[key] = value.isoformat()
  14. else:
  15. new_data[key] = value
  16. return new_data
  17. def get_message_data(message_id: str):
  18. return db.session.query(Message).filter(Message.id == message_id).first()
  19. @contextmanager
  20. def measure_time():
  21. timing_info = {"start": datetime.now(), "end": None}
  22. try:
  23. yield timing_info
  24. finally:
  25. timing_info["end"] = datetime.now()
  26. def replace_text_with_content(data):
  27. if isinstance(data, dict):
  28. new_data = {}
  29. for key, value in data.items():
  30. if key == "text":
  31. new_data["content"] = value
  32. else:
  33. new_data[key] = replace_text_with_content(value)
  34. return new_data
  35. elif isinstance(data, list):
  36. return [replace_text_with_content(item) for item in data]
  37. else:
  38. return data
  39. def generate_dotted_order(
  40. run_id: str, start_time: Union[str, datetime], parent_dotted_order: Optional[str] = None
  41. ) -> str:
  42. """
  43. generate dotted_order for langsmith
  44. """
  45. start_time = datetime.fromisoformat(start_time) if isinstance(start_time, str) else start_time
  46. timestamp = start_time.strftime("%Y%m%dT%H%M%S%f")[:-3] + "Z"
  47. current_segment = f"{timestamp}{run_id}"
  48. if parent_dotted_order is None:
  49. return current_segment
  50. return f"{parent_dotted_order}.{current_segment}"
  51. def validate_url(url: str, default_url: str, allowed_schemes: tuple = ("https", "http")) -> str:
  52. """
  53. Validate and normalize URL with proper error handling
  54. Args:
  55. url: The URL to validate
  56. default_url: Default URL to use if input is None or empty
  57. allowed_schemes: Tuple of allowed URL schemes (default: https, http)
  58. Returns:
  59. Normalized URL string
  60. Raises:
  61. ValueError: If URL format is invalid or scheme not allowed
  62. """
  63. if not url or url.strip() == "":
  64. return default_url
  65. # Parse URL to validate format
  66. parsed = urlparse(url)
  67. # Check if scheme is allowed
  68. if parsed.scheme not in allowed_schemes:
  69. raise ValueError(f"URL scheme must be one of: {', '.join(allowed_schemes)}")
  70. # Reconstruct URL with only scheme, netloc (removing path, query, fragment)
  71. normalized_url = f"{parsed.scheme}://{parsed.netloc}"
  72. return normalized_url
  73. def validate_url_with_path(url: str, default_url: str, required_suffix: str | None = None) -> str:
  74. """
  75. Validate URL that may include path components
  76. Args:
  77. url: The URL to validate
  78. default_url: Default URL to use if input is None or empty
  79. required_suffix: Optional suffix that URL must end with
  80. Returns:
  81. Validated URL string
  82. Raises:
  83. ValueError: If URL format is invalid or doesn't match required suffix
  84. """
  85. if not url or url.strip() == "":
  86. return default_url
  87. # Parse URL to validate format
  88. parsed = urlparse(url)
  89. # Check if scheme is allowed
  90. if parsed.scheme not in ("https", "http"):
  91. raise ValueError("URL must start with https:// or http://")
  92. # Check required suffix if specified
  93. if required_suffix and not url.endswith(required_suffix):
  94. raise ValueError(f"URL should end with {required_suffix}")
  95. return url
  96. def validate_project_name(project: str, default_name: str) -> str:
  97. """
  98. Validate and normalize project name
  99. Args:
  100. project: Project name to validate
  101. default_name: Default name to use if input is None or empty
  102. Returns:
  103. Normalized project name
  104. """
  105. if not project or project.strip() == "":
  106. return default_name
  107. return project.strip()