sycommon-python-lib 0.2.1a18__tar.gz → 0.2.1a20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/pyproject.toml +1 -1
  3. sycommon_python_lib-0.2.1a20/src/sycommon/llm/token_usage_buffer.py +446 -0
  4. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/token_usage_mysql_service.py +283 -52
  5. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  6. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/SOURCES.txt +1 -0
  7. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/README.md +0 -0
  8. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/setup.cfg +0 -0
  9. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/__init__.py +0 -0
  10. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/cli.py +0 -0
  11. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/core/__init__.py +0 -0
  12. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/core/console.py +0 -0
  13. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/core/models.py +0 -0
  14. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/core/project.py +0 -0
  15. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/core/utils.py +0 -0
  16. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/templates/__init__.py +0 -0
  17. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/templates/agent/__init__.py +0 -0
  18. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/templates/base/__init__.py +0 -0
  19. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/command/templates/web/__init__.py +0 -0
  20. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/__init__.py +0 -0
  21. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/__init__.py +0 -0
  22. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/01_basic_agent.py +0 -0
  23. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/02_tool_agent.py +0 -0
  24. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/03_structured_output.py +0 -0
  25. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/04_memory_agent.py +0 -0
  26. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/05_streaming.py +0 -0
  27. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/06_multi_agent.py +0 -0
  28. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/07_skills_agent.py +0 -0
  29. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/08_middleware.py +0 -0
  30. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/09_interrupt.py +0 -0
  31. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/10_custom_llm.py +0 -0
  32. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/11_complex_workflow.py +0 -0
  33. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/12_batch_processing.py +0 -0
  34. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/__init__.py +0 -0
  35. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/01_basic_monitoring.py +0 -0
  36. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/02_permission_control.py +0 -0
  37. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/03_tool_skill_filter.py +0 -0
  38. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/04_caching_retry.py +0 -0
  39. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/05_sanitization.py +0 -0
  40. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/06_tracking.py +0 -0
  41. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/07_advanced.py +0 -0
  42. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/08_progressive_skills.py +0 -0
  43. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/__init__.py +0 -0
  44. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/middleware/override_examples.py +0 -0
  45. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/examples/virtual_employee_demo.py +0 -0
  46. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/exports.py +0 -0
  47. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/get_agent.py +0 -0
  48. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/sandbox/__init__.py +0 -0
  49. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/sandbox/file_ops.py +0 -0
  50. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/sandbox/http_sandbox_backend.py +0 -0
  51. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/sandbox/sandbox_pool.py +0 -0
  52. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/sandbox/session.py +0 -0
  53. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/skills/__init__.py +0 -0
  54. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/skills/examples/faq_handler/scripts/search.py +0 -0
  55. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/skills/exports.py +0 -0
  56. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/agent/virtual_employee.py +0 -0
  57. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/Config.py +0 -0
  58. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/DatabaseConfig.py +0 -0
  59. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/ElasticsearchConfig.py +0 -0
  60. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/EmbeddingConfig.py +0 -0
  61. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/LLMConfig.py +0 -0
  62. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/LangfuseConfig.py +0 -0
  63. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/MQConfig.py +0 -0
  64. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/RedisConfig.py +0 -0
  65. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/RerankerConfig.py +0 -0
  66. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/SentryConfig.py +0 -0
  67. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/config/__init__.py +0 -0
  68. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/async_base_db_service.py +0 -0
  69. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/async_database_service.py +0 -0
  70. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/base_db_service.py +0 -0
  71. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/database_service.py +0 -0
  72. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/elasticsearch_service.py +0 -0
  73. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/redis_service.py +0 -0
  74. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/database/token_usage_db_service.py +0 -0
  75. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/health/__init__.py +0 -0
  76. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/health/health_check.py +0 -0
  77. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/health/metrics.py +0 -0
  78. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/health/ping.py +0 -0
  79. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/heartbeat_process/__init__.py +0 -0
  80. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/heartbeat_process/heartbeat_config.py +0 -0
  81. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/heartbeat_process/heartbeat_process_manager.py +0 -0
  82. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/heartbeat_process/heartbeat_process_worker.py +0 -0
  83. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/__init__.py +0 -0
  84. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/embedding.py +0 -0
  85. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/get_llm.py +0 -0
  86. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/llm_logger.py +0 -0
  87. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/llm_tokens.py +0 -0
  88. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/llm_with_token_tracking.py +0 -0
  89. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/native_with_fallback_runnable.py +0 -0
  90. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/output_fixing_runnable.py +0 -0
  91. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/struct_token.py +0 -0
  92. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/sy_langfuse.py +0 -0
  93. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/token_usage_es_service.py +0 -0
  94. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/llm/usage_token.py +0 -0
  95. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/__init__.py +0 -0
  96. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/async_sql_logger.py +0 -0
  97. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/kafka_log.py +0 -0
  98. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/logger_levels.py +0 -0
  99. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/logger_wrapper.py +0 -0
  100. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/process_logger.py +0 -0
  101. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/logging/sql_logger.py +0 -0
  102. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/__init__.py +0 -0
  103. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/context.py +0 -0
  104. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/cors.py +0 -0
  105. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/docs.py +0 -0
  106. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/exception.py +0 -0
  107. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/middleware.py +0 -0
  108. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/monitor_memory.py +0 -0
  109. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/mq.py +0 -0
  110. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/sandbox.py +0 -0
  111. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/timeout.py +0 -0
  112. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/middleware/traceid.py +0 -0
  113. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/__init__.py +0 -0
  114. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/base_http.py +0 -0
  115. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/log.py +0 -0
  116. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/mqlistener_config.py +0 -0
  117. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/mqmsg_model.py +0 -0
  118. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/mqsend_config.py +0 -0
  119. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/sso_user.py +0 -0
  120. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/token_usage.py +0 -0
  121. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/models/token_usage_mysql.py +0 -0
  122. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/notice/__init__.py +0 -0
  123. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/notice/uvicorn_monitor.py +0 -0
  124. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/process_pool_consumer.py +0 -0
  125. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
  126. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
  127. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
  128. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
  129. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
  130. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
  131. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
  132. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
  133. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/sentry/__init__.py +0 -0
  134. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/sentry/sy_sentry.py +0 -0
  135. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/services.py +0 -0
  136. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/sse/__init__.py +0 -0
  137. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/sse/event.py +0 -0
  138. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/sse/sse.py +0 -0
  139. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/__init__.py +0 -0
  140. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/example.py +0 -0
  141. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/example2.py +0 -0
  142. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/feign.py +0 -0
  143. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/feign_client.py +0 -0
  144. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_client_base.py +0 -0
  145. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_config_manager.py +0 -0
  146. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_heartbeat_manager.py +0 -0
  147. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_service.py +0 -0
  148. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_service_discovery.py +0 -0
  149. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/nacos_service_registration.py +0 -0
  150. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/synacos/param.py +0 -0
  151. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tests/deep_agent_server.py +0 -0
  152. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tests/test_deep_agent.py +0 -0
  153. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tests/test_email.py +0 -0
  154. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tests/test_mq.py +0 -0
  155. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/__init__.py +0 -0
  156. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/async_utils.py +0 -0
  157. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/docs.py +0 -0
  158. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/env.py +0 -0
  159. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/merge_headers.py +0 -0
  160. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/snowflake.py +0 -0
  161. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/syemail.py +0 -0
  162. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon/tools/timing.py +0 -0
  163. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  164. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  165. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
  166. {sycommon_python_lib-0.2.1a18 → sycommon_python_lib-0.2.1a20}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.1a18
3
+ Version: 0.2.1a20
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.2.1a18"
3
+ version = "0.2.1a20"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,446 @@
1
+ """
2
+ Token 使用量本地缓冲管理器
3
+ 用于在高并发场景下聚合写入,减少数据库压力
4
+
5
+ 完全异步实现,不阻塞主服务
6
+ """
7
+ import asyncio
8
+ import logging
9
+ import time
10
+ from collections import defaultdict
11
+ from dataclasses import dataclass, field
12
+ from datetime import datetime, date
13
+ from typing import Optional, Dict, Any, List
14
+
15
+ from sycommon.config.Config import SingletonMeta
16
+ from sycommon.logging.kafka_log import SYLogger
17
+
18
+
19
+ @dataclass
20
+ class TokenUsageBufferItem:
21
+ """缓冲区中的 Token 使用记录"""
22
+ user_id: str
23
+ tenant_id: Optional[str]
24
+ service_name: str
25
+ system_env: str
26
+ input_tokens: int
27
+ output_tokens: int
28
+ model: Optional[str]
29
+ usage_date: date
30
+ created_at: datetime = field(default_factory=datetime.now)
31
+
32
+
33
+ class TokenUsageBuffer(metaclass=SingletonMeta):
34
+ """
35
+ Token 使用量本地缓冲管理器(完全异步实现)
36
+
37
+ 功能:
38
+ 1. 本地内存缓冲:将高频写入先存入内存
39
+ 2. 智能聚合:相同 key 的记录在内存中累加
40
+ 3. 定时刷新:按时间间隔批量写入数据库
41
+ 4. 阈值触发:缓冲区达到一定数量时立即刷新
42
+ 5. 优雅关闭:服务停止时确保数据不丢失
43
+
44
+ 特点:
45
+ - 完全异步,使用 asyncio.Lock 保证线程安全
46
+ - 不阻塞主事件循环
47
+ """
48
+
49
+ # 缓冲区
50
+ _buffer: Dict[str, TokenUsageBufferItem] = None
51
+ _buffer_lock: asyncio.Lock = None
52
+ _flush_task: Optional[asyncio.Task] = None
53
+ _running: bool = False
54
+ _loop: Optional[asyncio.AbstractEventLoop] = None
55
+
56
+ # 配置参数
57
+ _flush_interval: float = 15.0 # 刷新间隔(秒)
58
+ _max_buffer_size: int = 500 # 缓冲区最大条目数
59
+ _max_batch_size: int = 100 # 单次批量写入最大条目数
60
+
61
+ # 统计信息
62
+ _total_buffered: int = 0
63
+ _total_flushed: int = 0
64
+ _last_flush_time: Optional[datetime] = None
65
+
66
+ # 回调函数(用于实际写入数据库)
67
+ _flush_callback = None
68
+
69
+ def __init__(self):
70
+ pass
71
+
72
+ @classmethod
73
+ def _ensure_initialized(cls):
74
+ """确保缓冲区已初始化"""
75
+ if cls._buffer is None:
76
+ cls._buffer = {}
77
+ if cls._buffer_lock is None:
78
+ cls._buffer_lock = asyncio.Lock()
79
+
80
+ @classmethod
81
+ def configure(
82
+ cls,
83
+ flush_interval: float = 15.0,
84
+ max_buffer_size: int = 500,
85
+ max_batch_size: int = 100
86
+ ):
87
+ """
88
+ 配置缓冲区参数
89
+
90
+ Args:
91
+ flush_interval: 刷新间隔(秒),默认 15 秒
92
+ max_buffer_size: 缓冲区最大条目数,超过此数量立即刷新
93
+ max_batch_size: 单次批量写入最大条目数
94
+ """
95
+ cls._flush_interval = flush_interval
96
+ cls._max_buffer_size = max_buffer_size
97
+ cls._max_batch_size = max_batch_size
98
+ logging.info(
99
+ f"TokenUsageBuffer 配置: flush_interval={flush_interval}s, "
100
+ f"max_buffer_size={max_buffer_size}, max_batch_size={max_batch_size}"
101
+ )
102
+
103
+ @classmethod
104
+ def set_flush_callback(cls, callback):
105
+ """
106
+ 设置刷新回调函数
107
+
108
+ Args:
109
+ callback: 异步函数,接收 List[TokenUsageBufferItem] 参数
110
+ """
111
+ cls._flush_callback = callback
112
+
113
+ @classmethod
114
+ def _make_key(
115
+ cls,
116
+ user_id: str,
117
+ service_name: str,
118
+ system_env: str,
119
+ usage_date: date
120
+ ) -> str:
121
+ """生成缓冲区 key"""
122
+ return f"{user_id}|{service_name}|{system_env}|{usage_date.isoformat()}"
123
+
124
+ @classmethod
125
+ async def add(
126
+ cls,
127
+ user_id: Optional[str],
128
+ input_tokens: int,
129
+ output_tokens: int,
130
+ model: Optional[str] = None,
131
+ tenant_id: Optional[str] = None,
132
+ service_name: Optional[str] = None,
133
+ system_env: Optional[str] = None
134
+ ) -> bool:
135
+ """
136
+ 异步添加 Token 使用记录到缓冲区
137
+
138
+ 如果已存在相同 key 的记录,则累加 tokens
139
+
140
+ Args:
141
+ user_id: 用户ID
142
+ input_tokens: 输入 token 数量
143
+ output_tokens: 输出 token 数量
144
+ model: 模型名称
145
+ tenant_id: 租户ID
146
+ service_name: 服务名称
147
+ system_env: 系统环境
148
+
149
+ Returns:
150
+ bool: 是否成功添加到缓冲区
151
+ """
152
+ cls._ensure_initialized()
153
+
154
+ # 处理空值
155
+ user_id = user_id or ''
156
+ service_name = service_name or ''
157
+ system_env = system_env or ''
158
+ usage_date = date.today()
159
+
160
+ key = cls._make_key(user_id, service_name, system_env, usage_date)
161
+
162
+ should_flush = False
163
+
164
+ async with cls._buffer_lock:
165
+ if key in cls._buffer:
166
+ # 累加到已有记录
167
+ item = cls._buffer[key]
168
+ item.input_tokens += input_tokens
169
+ item.output_tokens += output_tokens
170
+ item.model = model # 更新为最新模型
171
+ else:
172
+ # 创建新记录
173
+ cls._buffer[key] = TokenUsageBufferItem(
174
+ user_id=user_id,
175
+ tenant_id=tenant_id,
176
+ service_name=service_name,
177
+ system_env=system_env,
178
+ input_tokens=input_tokens,
179
+ output_tokens=output_tokens,
180
+ model=model,
181
+ usage_date=usage_date
182
+ )
183
+ cls._total_buffered += 1
184
+
185
+ # 检查是否需要立即刷新
186
+ if len(cls._buffer) >= cls._max_buffer_size:
187
+ should_flush = True
188
+
189
+ # 在锁外触发刷新,避免阻塞
190
+ if should_flush:
191
+ logging.info(f"TokenUsageBuffer 缓冲区达到阈值 ({cls._max_buffer_size}),触发立即刷新")
192
+ asyncio.create_task(cls._do_flush())
193
+
194
+ return True
195
+
196
+ @classmethod
197
+ def add_sync(
198
+ cls,
199
+ user_id: Optional[str],
200
+ input_tokens: int,
201
+ output_tokens: int,
202
+ model: Optional[str] = None,
203
+ tenant_id: Optional[str] = None,
204
+ service_name: Optional[str] = None,
205
+ system_env: Optional[str] = None
206
+ ) -> bool:
207
+ """
208
+ 同步添加(非阻塞,fire-and-forget)
209
+
210
+ 通过 asyncio.to_thread 或 run_coroutine_threadsafe 调用异步方法
211
+ 不会阻塞调用线程
212
+
213
+ Args:
214
+ 同 add 方法
215
+
216
+ Returns:
217
+ bool: 是否成功提交
218
+ """
219
+ cls._ensure_initialized()
220
+
221
+ # 处理空值
222
+ user_id = user_id or ''
223
+ service_name = service_name or ''
224
+ system_env = system_env or ''
225
+ usage_date = date.today()
226
+
227
+ key = cls._make_key(user_id, service_name, system_env, usage_date)
228
+
229
+ # 使用简单的方式:直接操作缓冲区(最小化锁竞争)
230
+ # 这里的操作是原子的,不需要复杂的锁
231
+ if cls._buffer is None:
232
+ cls._buffer = {}
233
+
234
+ # 快速路径:更新或创建记录
235
+ if key in cls._buffer:
236
+ item = cls._buffer[key]
237
+ item.input_tokens += input_tokens
238
+ item.output_tokens += output_tokens
239
+ item.model = model
240
+ else:
241
+ cls._buffer[key] = TokenUsageBufferItem(
242
+ user_id=user_id,
243
+ tenant_id=tenant_id,
244
+ service_name=service_name,
245
+ system_env=system_env,
246
+ input_tokens=input_tokens,
247
+ output_tokens=output_tokens,
248
+ model=model,
249
+ usage_date=usage_date
250
+ )
251
+ cls._total_buffered += 1
252
+
253
+ # 检查是否需要刷新
254
+ if len(cls._buffer) >= cls._max_buffer_size:
255
+ cls._trigger_async_flush()
256
+
257
+ return True
258
+
259
+ @classmethod
260
+ def _trigger_async_flush(cls):
261
+ """触发异步刷新(从同步上下文调用)"""
262
+ try:
263
+ loop = asyncio.get_running_loop()
264
+ loop.create_task(cls._do_flush())
265
+ except RuntimeError:
266
+ # 没有运行中的事件循环,忽略
267
+ pass
268
+
269
+ @classmethod
270
+ async def start(cls):
271
+ """
272
+ 启动缓冲区刷新任务
273
+
274
+ 应该在应用启动时调用
275
+ """
276
+ if cls._running:
277
+ return
278
+
279
+ cls._ensure_initialized()
280
+ cls._running = True
281
+ cls._loop = asyncio.get_running_loop()
282
+
283
+ # 启动定时刷新任务
284
+ cls._flush_task = asyncio.create_task(cls._flush_loop())
285
+ logging.info(f"TokenUsageBuffer 已启动,刷新间隔: {cls._flush_interval}s")
286
+
287
+ # 注册关闭钩子
288
+ import atexit
289
+ atexit.register(cls.shutdown_sync)
290
+
291
+ @classmethod
292
+ async def stop(cls):
293
+ """
294
+ 停止缓冲区并刷新剩余数据
295
+
296
+ 应该在应用关闭时调用
297
+ """
298
+ if not cls._running:
299
+ return
300
+
301
+ cls._running = False
302
+
303
+ # 取消定时任务
304
+ if cls._flush_task:
305
+ cls._flush_task.cancel()
306
+ try:
307
+ await cls._flush_task
308
+ except asyncio.CancelledError:
309
+ pass
310
+
311
+ # 最后一次刷新
312
+ await cls._do_flush()
313
+ logging.info("TokenUsageBuffer 已停止")
314
+
315
+ @classmethod
316
+ def shutdown_sync(cls):
317
+ """同步关闭方法(用于 atexit)"""
318
+ if not cls._running:
319
+ return
320
+
321
+ cls._running = False
322
+
323
+ # 同步刷新剩余数据
324
+ if cls._buffer:
325
+ try:
326
+ # 尝试在已有事件循环中执行
327
+ if cls._loop and cls._loop.is_running():
328
+ future = asyncio.run_coroutine_threadsafe(cls._do_flush(), cls._loop)
329
+ future.result(timeout=10) # 最多等待 10 秒
330
+ else:
331
+ # 创建新的事件循环
332
+ loop = asyncio.new_event_loop()
333
+ asyncio.set_event_loop(loop)
334
+ try:
335
+ loop.run_until_complete(cls._do_flush())
336
+ finally:
337
+ loop.close()
338
+ except Exception as e:
339
+ logging.error(f"TokenUsageBuffer 关闭时刷新失败: {e}", exc_info=True)
340
+
341
+ logging.info("TokenUsageBuffer 已同步关闭")
342
+
343
+ @classmethod
344
+ async def _flush_loop(cls):
345
+ """定时刷新循环"""
346
+ while cls._running:
347
+ try:
348
+ await asyncio.sleep(cls._flush_interval)
349
+ await cls._do_flush()
350
+ except asyncio.CancelledError:
351
+ break
352
+ except Exception as e:
353
+ logging.error(f"TokenUsageBuffer 刷新循环异常: {e}", exc_info=True)
354
+ await asyncio.sleep(1) # 出错后等待 1 秒再继续
355
+
356
+ @classmethod
357
+ async def _do_flush(cls):
358
+ """执行批量刷新到数据库"""
359
+ if not cls._buffer:
360
+ return
361
+
362
+ if not cls._flush_callback:
363
+ logging.warning("TokenUsageBuffer 未设置 flush_callback,无法刷新数据")
364
+ return
365
+
366
+ # 获取要刷新的数据
367
+ items_to_flush = []
368
+ async with cls._buffer_lock:
369
+ if cls._buffer:
370
+ items_to_flush = list(cls._buffer.values())
371
+ cls._buffer = {} # 清空缓冲区
372
+
373
+ if not items_to_flush:
374
+ return
375
+
376
+ # 分批刷新
377
+ total_items = len(items_to_flush)
378
+ success_count = 0
379
+ failed_items = []
380
+
381
+ for i in range(0, total_items, cls._max_batch_size):
382
+ batch = items_to_flush[i:i + cls._max_batch_size]
383
+ try:
384
+ await cls._flush_callback(batch)
385
+ success_count += len(batch)
386
+ except Exception as e:
387
+ logging.error(f"TokenUsageBuffer 批量刷新失败: {e}", exc_info=True)
388
+ failed_items.extend(batch)
389
+
390
+ # 失败的记录重新放回缓冲区
391
+ if failed_items:
392
+ async with cls._buffer_lock:
393
+ for item in failed_items:
394
+ key = cls._make_key(
395
+ item.user_id, item.service_name,
396
+ item.system_env, item.usage_date
397
+ )
398
+ if key in cls._buffer:
399
+ cls._buffer[key].input_tokens += item.input_tokens
400
+ cls._buffer[key].output_tokens += item.output_tokens
401
+ else:
402
+ cls._buffer[key] = item
403
+
404
+ cls._total_flushed += success_count
405
+ cls._last_flush_time = datetime.now()
406
+
407
+ if success_count > 0:
408
+ logging.info(
409
+ f"TokenUsageBuffer 刷新完成: 成功 {success_count} 条, "
410
+ f"失败 {len(failed_items)} 条"
411
+ )
412
+
413
+ @classmethod
414
+ async def flush_now(cls):
415
+ """手动触发立即刷新"""
416
+ await cls._do_flush()
417
+
418
+ @classmethod
419
+ def get_stats(cls) -> Dict[str, Any]:
420
+ """获取缓冲区统计信息"""
421
+ buffer_size = len(cls._buffer) if cls._buffer else 0
422
+ total_tokens = 0
423
+ if cls._buffer:
424
+ total_tokens = sum(
425
+ item.input_tokens + item.output_tokens
426
+ for item in cls._buffer.values()
427
+ )
428
+
429
+ return {
430
+ "running": cls._running,
431
+ "buffer_size": buffer_size,
432
+ "total_tokens_in_buffer": total_tokens,
433
+ "total_buffered": cls._total_buffered,
434
+ "total_flushed": cls._total_flushed,
435
+ "last_flush_time": cls._last_flush_time.isoformat() if cls._last_flush_time else None,
436
+ "config": {
437
+ "flush_interval": cls._flush_interval,
438
+ "max_buffer_size": cls._max_buffer_size,
439
+ "max_batch_size": cls._max_batch_size
440
+ }
441
+ }
442
+
443
+ @classmethod
444
+ def is_running(cls) -> bool:
445
+ """检查缓冲区是否正在运行"""
446
+ return cls._running