aiecs 1.5.1__py3-none-any.whl
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.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Optional, List, AsyncGenerator
|
|
4
|
+
|
|
5
|
+
import google.generativeai as genai
|
|
6
|
+
from google.generativeai.types import (
|
|
7
|
+
GenerationConfig,
|
|
8
|
+
HarmCategory,
|
|
9
|
+
HarmBlockThreshold,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from aiecs.llm.clients.base_client import (
|
|
13
|
+
BaseLLMClient,
|
|
14
|
+
LLMMessage,
|
|
15
|
+
LLMResponse,
|
|
16
|
+
ProviderNotAvailableError,
|
|
17
|
+
RateLimitError,
|
|
18
|
+
)
|
|
19
|
+
from aiecs.config.config import get_settings
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GoogleAIClient(BaseLLMClient):
|
|
25
|
+
"""Google AI (Gemini) provider client"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("GoogleAI")
|
|
29
|
+
self.settings = get_settings()
|
|
30
|
+
self._initialized = False
|
|
31
|
+
self.client = None
|
|
32
|
+
|
|
33
|
+
def _init_google_ai(self):
|
|
34
|
+
"""Lazy initialization of Google AI SDK"""
|
|
35
|
+
if not self._initialized:
|
|
36
|
+
api_key = self.settings.googleai_api_key or os.environ.get("GOOGLEAI_API_KEY")
|
|
37
|
+
if not api_key:
|
|
38
|
+
raise ProviderNotAvailableError(
|
|
39
|
+
"Google AI API key not configured. Set GOOGLEAI_API_KEY."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
genai.configure(api_key=api_key)
|
|
44
|
+
self._initialized = True
|
|
45
|
+
self.logger.info("Google AI SDK initialized successfully.")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
raise ProviderNotAvailableError(f"Failed to initialize Google AI SDK: {str(e)}")
|
|
48
|
+
|
|
49
|
+
async def generate_text(
|
|
50
|
+
self,
|
|
51
|
+
messages: List[LLMMessage],
|
|
52
|
+
model: Optional[str] = None,
|
|
53
|
+
temperature: float = 0.7,
|
|
54
|
+
max_tokens: Optional[int] = None,
|
|
55
|
+
**kwargs,
|
|
56
|
+
) -> LLMResponse:
|
|
57
|
+
"""Generate text using Google AI"""
|
|
58
|
+
self._init_google_ai()
|
|
59
|
+
|
|
60
|
+
# Get model name from config if not provided
|
|
61
|
+
model_name = model or self._get_default_model() or "gemini-2.5-pro"
|
|
62
|
+
|
|
63
|
+
# Get model config for default parameters
|
|
64
|
+
model_config = self._get_model_config(model_name)
|
|
65
|
+
if model_config and max_tokens is None:
|
|
66
|
+
max_tokens = model_config.default_params.max_tokens
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
model_instance = genai.GenerativeModel(model_name)
|
|
70
|
+
|
|
71
|
+
# Convert messages to Google AI format
|
|
72
|
+
history = [{"role": msg.role, "parts": [msg.content]} for msg in messages]
|
|
73
|
+
|
|
74
|
+
# The last message is the prompt
|
|
75
|
+
prompt = history.pop()
|
|
76
|
+
|
|
77
|
+
# Create GenerationConfig
|
|
78
|
+
generation_config = GenerationConfig(
|
|
79
|
+
temperature=temperature,
|
|
80
|
+
max_output_tokens=max_tokens or 8192,
|
|
81
|
+
top_p=kwargs.get("top_p", 0.95),
|
|
82
|
+
top_k=kwargs.get("top_k", 40),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Safety settings to match vertex_client
|
|
86
|
+
safety_settings = {
|
|
87
|
+
HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
|
|
88
|
+
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
|
|
89
|
+
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
|
|
90
|
+
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
response = await model_instance.generate_content_async(
|
|
94
|
+
contents=prompt["parts"],
|
|
95
|
+
generation_config=generation_config,
|
|
96
|
+
safety_settings=safety_settings,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
content = response.text
|
|
100
|
+
prompt_tokens = response.usage_metadata.prompt_token_count
|
|
101
|
+
completion_tokens = response.usage_metadata.candidates_token_count
|
|
102
|
+
total_tokens = response.usage_metadata.total_token_count
|
|
103
|
+
|
|
104
|
+
# Use config-based cost estimation
|
|
105
|
+
cost = self._estimate_cost_from_config(model_name, prompt_tokens, completion_tokens)
|
|
106
|
+
|
|
107
|
+
return LLMResponse(
|
|
108
|
+
content=content,
|
|
109
|
+
provider=self.provider_name,
|
|
110
|
+
model=model_name,
|
|
111
|
+
tokens_used=total_tokens,
|
|
112
|
+
prompt_tokens=prompt_tokens,
|
|
113
|
+
completion_tokens=completion_tokens,
|
|
114
|
+
cost_estimate=cost,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
if "quota" in str(e).lower():
|
|
119
|
+
raise RateLimitError(f"Google AI quota exceeded: {str(e)}")
|
|
120
|
+
self.logger.error(f"Error generating text with Google AI: {e}")
|
|
121
|
+
raise
|
|
122
|
+
|
|
123
|
+
async def stream_text(
|
|
124
|
+
self,
|
|
125
|
+
messages: List[LLMMessage],
|
|
126
|
+
model: Optional[str] = None,
|
|
127
|
+
temperature: float = 0.7,
|
|
128
|
+
max_tokens: Optional[int] = None,
|
|
129
|
+
**kwargs,
|
|
130
|
+
) -> AsyncGenerator[str, None]:
|
|
131
|
+
"""Stream text generation using Google AI"""
|
|
132
|
+
self._init_google_ai()
|
|
133
|
+
|
|
134
|
+
# Get model name from config if not provided
|
|
135
|
+
model_name = model or self._get_default_model() or "gemini-2.5-pro"
|
|
136
|
+
|
|
137
|
+
# Get model config for default parameters
|
|
138
|
+
model_config = self._get_model_config(model_name)
|
|
139
|
+
if model_config and max_tokens is None:
|
|
140
|
+
max_tokens = model_config.default_params.max_tokens
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
model_instance = genai.GenerativeModel(model_name)
|
|
144
|
+
|
|
145
|
+
# Convert messages to Google AI format
|
|
146
|
+
history = [{"role": msg.role, "parts": [msg.content]} for msg in messages]
|
|
147
|
+
prompt = history.pop()
|
|
148
|
+
|
|
149
|
+
generation_config = GenerationConfig(
|
|
150
|
+
temperature=temperature,
|
|
151
|
+
max_output_tokens=max_tokens or 8192,
|
|
152
|
+
top_p=kwargs.get("top_p", 0.95),
|
|
153
|
+
top_k=kwargs.get("top_k", 40),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
safety_settings = {
|
|
157
|
+
HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
|
|
158
|
+
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
|
|
159
|
+
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
|
|
160
|
+
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
response_stream = await model_instance.generate_content_async(
|
|
164
|
+
contents=prompt["parts"],
|
|
165
|
+
generation_config=generation_config,
|
|
166
|
+
safety_settings=safety_settings,
|
|
167
|
+
stream=True,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
async for chunk in response_stream:
|
|
171
|
+
if chunk.text:
|
|
172
|
+
yield chunk.text
|
|
173
|
+
|
|
174
|
+
except Exception as e:
|
|
175
|
+
self.logger.error(f"Error streaming text with Google AI: {e}")
|
|
176
|
+
raise
|
|
177
|
+
|
|
178
|
+
async def close(self):
|
|
179
|
+
"""Clean up resources"""
|
|
180
|
+
# Google AI SDK does not require explicit closing of a client
|
|
181
|
+
self._initialized = False
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, List, AsyncGenerator
|
|
3
|
+
from openai import AsyncOpenAI
|
|
4
|
+
from tenacity import (
|
|
5
|
+
retry,
|
|
6
|
+
stop_after_attempt,
|
|
7
|
+
wait_exponential,
|
|
8
|
+
retry_if_exception_type,
|
|
9
|
+
)
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
from aiecs.llm.clients.base_client import (
|
|
13
|
+
BaseLLMClient,
|
|
14
|
+
LLMMessage,
|
|
15
|
+
LLMResponse,
|
|
16
|
+
ProviderNotAvailableError,
|
|
17
|
+
RateLimitError,
|
|
18
|
+
)
|
|
19
|
+
from aiecs.config.config import get_settings
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OpenAIClient(BaseLLMClient):
|
|
25
|
+
"""OpenAI provider client"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("OpenAI")
|
|
29
|
+
self.settings = get_settings()
|
|
30
|
+
self._client: Optional[AsyncOpenAI] = None
|
|
31
|
+
|
|
32
|
+
def _get_client(self) -> AsyncOpenAI:
|
|
33
|
+
"""Lazy initialization of OpenAI client"""
|
|
34
|
+
if not self._client:
|
|
35
|
+
if not self.settings.openai_api_key:
|
|
36
|
+
raise ProviderNotAvailableError("OpenAI API key not configured")
|
|
37
|
+
self._client = AsyncOpenAI(api_key=self.settings.openai_api_key)
|
|
38
|
+
return self._client
|
|
39
|
+
|
|
40
|
+
@retry(
|
|
41
|
+
stop=stop_after_attempt(3),
|
|
42
|
+
wait=wait_exponential(multiplier=1, min=4, max=10),
|
|
43
|
+
retry=retry_if_exception_type((httpx.RequestError, RateLimitError)),
|
|
44
|
+
)
|
|
45
|
+
async def generate_text(
|
|
46
|
+
self,
|
|
47
|
+
messages: List[LLMMessage],
|
|
48
|
+
model: Optional[str] = None,
|
|
49
|
+
temperature: float = 0.7,
|
|
50
|
+
max_tokens: Optional[int] = None,
|
|
51
|
+
**kwargs,
|
|
52
|
+
) -> LLMResponse:
|
|
53
|
+
"""Generate text using OpenAI API"""
|
|
54
|
+
client = self._get_client()
|
|
55
|
+
|
|
56
|
+
# Get model name from config if not provided
|
|
57
|
+
model = model or self._get_default_model() or "gpt-4-turbo"
|
|
58
|
+
|
|
59
|
+
# Convert to OpenAI message format
|
|
60
|
+
openai_messages = [{"role": msg.role, "content": msg.content} for msg in messages]
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
response = await client.chat.completions.create(
|
|
64
|
+
model=model,
|
|
65
|
+
messages=openai_messages,
|
|
66
|
+
temperature=temperature,
|
|
67
|
+
max_tokens=max_tokens,
|
|
68
|
+
**kwargs,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
content = response.choices[0].message.content
|
|
72
|
+
tokens_used = response.usage.total_tokens if response.usage else None
|
|
73
|
+
|
|
74
|
+
# Estimate cost using config
|
|
75
|
+
input_tokens = response.usage.prompt_tokens if response.usage else 0
|
|
76
|
+
output_tokens = response.usage.completion_tokens if response.usage else 0
|
|
77
|
+
cost = self._estimate_cost_from_config(model, input_tokens, output_tokens)
|
|
78
|
+
|
|
79
|
+
return LLMResponse(
|
|
80
|
+
content=content,
|
|
81
|
+
provider=self.provider_name,
|
|
82
|
+
model=model,
|
|
83
|
+
tokens_used=tokens_used,
|
|
84
|
+
cost_estimate=cost,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
except Exception as e:
|
|
88
|
+
if "rate_limit" in str(e).lower():
|
|
89
|
+
raise RateLimitError(f"OpenAI rate limit exceeded: {str(e)}")
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
async def stream_text(
|
|
93
|
+
self,
|
|
94
|
+
messages: List[LLMMessage],
|
|
95
|
+
model: Optional[str] = None,
|
|
96
|
+
temperature: float = 0.7,
|
|
97
|
+
max_tokens: Optional[int] = None,
|
|
98
|
+
**kwargs,
|
|
99
|
+
) -> AsyncGenerator[str, None]:
|
|
100
|
+
"""Stream text using OpenAI API"""
|
|
101
|
+
client = self._get_client()
|
|
102
|
+
|
|
103
|
+
# Get model name from config if not provided
|
|
104
|
+
model = model or self._get_default_model() or "gpt-4-turbo"
|
|
105
|
+
|
|
106
|
+
openai_messages = [{"role": msg.role, "content": msg.content} for msg in messages]
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
stream = await client.chat.completions.create(
|
|
110
|
+
model=model,
|
|
111
|
+
messages=openai_messages,
|
|
112
|
+
temperature=temperature,
|
|
113
|
+
max_tokens=max_tokens,
|
|
114
|
+
stream=True,
|
|
115
|
+
**kwargs,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
async for chunk in stream:
|
|
119
|
+
if chunk.choices[0].delta.content:
|
|
120
|
+
yield chunk.choices[0].delta.content
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
if "rate_limit" in str(e).lower():
|
|
124
|
+
raise RateLimitError(f"OpenAI rate limit exceeded: {str(e)}")
|
|
125
|
+
raise
|
|
126
|
+
|
|
127
|
+
async def close(self):
|
|
128
|
+
"""Clean up resources"""
|
|
129
|
+
if self._client:
|
|
130
|
+
await self._client.close()
|
|
131
|
+
self._client = None
|