igel-qe-core 1.0.0
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.
- package/dist/cli/index.js +38 -0
- package/dist/mcp/server.js +104 -0
- package/knowledge_base/__init__.py +3 -0
- package/knowledge_base/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/__pycache__/confidence.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/config.cpython-38.pyc +0 -0
- package/knowledge_base/__pycache__/context_fusion.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/context_fusion.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_analytics.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_applier.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_cli.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_curator.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/feedback_handler.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/generate.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/generate_qcapps134.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/input_classifier.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/input_classifier.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/kg_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/knowledge_graph.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/knowledge_graph.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/manual_tc_parser.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/manual_tc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/precedence.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/prompts.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/prompts.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/reranker.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/reranker.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/retrieval_debug.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/retrieval_debug.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/retriever.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/retriever.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/server.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/tc_transformer.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/tc_transformer.cpython-37.pyc +0 -0
- package/knowledge_base/__pycache__/test_generator.cpython-314.pyc +0 -0
- package/knowledge_base/__pycache__/test_generator.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__init__.py +6 -0
- package/knowledge_base/agents/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/fusion_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/fusion_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/graph.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/graph.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/healing_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/intent_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/intent_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/kg_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/kg_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/memory_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/memory_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/rca_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/reflection_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/reflection_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/regression_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/retrieval_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/retrieval_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/script_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/script_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/state.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/state.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/temporal_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/temporal_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/__pycache__/validation_agent.cpython-37.pyc +0 -0
- package/knowledge_base/agents/__pycache__/validation_agent.cpython-38.pyc +0 -0
- package/knowledge_base/agents/automation_design_agent.py +123 -0
- package/knowledge_base/agents/code_intelligence_agent.py +147 -0
- package/knowledge_base/agents/confidence_agent.py +94 -0
- package/knowledge_base/agents/execution_validation_agent.py +129 -0
- package/knowledge_base/agents/feedback_agent.py +56 -0
- package/knowledge_base/agents/fusion_agent.py +113 -0
- package/knowledge_base/agents/graph.py +152 -0
- package/knowledge_base/agents/healing_agent.py +62 -0
- package/knowledge_base/agents/intent_agent.py +76 -0
- package/knowledge_base/agents/kg_agent.py +91 -0
- package/knowledge_base/agents/memory_agent.py +62 -0
- package/knowledge_base/agents/rca_agent.py +53 -0
- package/knowledge_base/agents/reflection_agent.py +62 -0
- package/knowledge_base/agents/regression_agent.py +81 -0
- package/knowledge_base/agents/requirement_agent.py +71 -0
- package/knowledge_base/agents/retrieval_agent.py +66 -0
- package/knowledge_base/agents/scenario_agent.py +81 -0
- package/knowledge_base/agents/script_agent.py +121 -0
- package/knowledge_base/agents/script_generator_agent.py +77 -0
- package/knowledge_base/agents/state.py +53 -0
- package/knowledge_base/agents/temporal_agent.py +48 -0
- package/knowledge_base/agents/testcase_agent.py +111 -0
- package/knowledge_base/agents/validation_agent.py +49 -0
- package/knowledge_base/agents/workflow_engine.py +87 -0
- package/knowledge_base/alembic/README.md +104 -0
- package/knowledge_base/alembic/__pycache__/env.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/__pycache__/env.cpython-38.pyc +0 -0
- package/knowledge_base/alembic/env.py +76 -0
- package/knowledge_base/alembic/script.py.mako +5 -0
- package/knowledge_base/alembic/versions/.gitkeep +26 -0
- package/knowledge_base/alembic/versions/001_phase0_feedback.py +122 -0
- package/knowledge_base/alembic/versions/002_feedback_promotions.py +60 -0
- package/knowledge_base/alembic/versions/003_enterprise_hardening.py +74 -0
- package/knowledge_base/alembic/versions/__pycache__/001_phase0_feedback.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/001_phase0_feedback.cpython-38.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/002_feedback_promotions.cpython-37.pyc +0 -0
- package/knowledge_base/alembic/versions/__pycache__/002_feedback_promotions.cpython-38.pyc +0 -0
- package/knowledge_base/api/__init__.py +1 -0
- package/knowledge_base/api/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/api/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/api/__pycache__/middleware.cpython-38.pyc +0 -0
- package/knowledge_base/api/__pycache__/server.cpython-37.pyc +0 -0
- package/knowledge_base/api/__pycache__/server.cpython-38.pyc +0 -0
- package/knowledge_base/api/middleware.py +78 -0
- package/knowledge_base/api/server.py +778 -0
- package/knowledge_base/chunking/__init__.py +0 -0
- package/knowledge_base/chunking/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/chunker.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/chunker.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/validators.cpython-37.pyc +0 -0
- package/knowledge_base/chunking/__pycache__/validators.cpython-38.pyc +0 -0
- package/knowledge_base/chunking/chunker.py +402 -0
- package/knowledge_base/chunking/validators.py +144 -0
- package/knowledge_base/cli/__init__.py +1 -0
- package/knowledge_base/cli/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/feedback_cli.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/feedback_cli.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate.cpython-37.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate.cpython-38.pyc +0 -0
- package/knowledge_base/cli/__pycache__/generate_qcapps134.cpython-37.pyc +0 -0
- package/knowledge_base/cli/feedback_cli.py +121 -0
- package/knowledge_base/cli/generate.py +308 -0
- package/knowledge_base/cli/generate_qcapps134.py +391 -0
- package/knowledge_base/config/.env +100 -0
- package/knowledge_base/config/.env.example +75 -0
- package/knowledge_base/config/__init__.py +5 -0
- package/knowledge_base/config/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/config/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/config/__pycache__/settings.cpython-37.pyc +0 -0
- package/knowledge_base/config/__pycache__/settings.cpython-38.pyc +0 -0
- package/knowledge_base/config/settings.py +280 -0
- package/knowledge_base/connectors/__init__.py +5 -0
- package/knowledge_base/connectors/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/base.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/base.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/bitbucket_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/bitbucket_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/community_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/confluence_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/confluence_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/jira_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/jira_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/kb_igel_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/playwright_fetcher.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/query_bridge.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/search_backends.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/serviceNow_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/serviceNow_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/sync_scheduler.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/sync_scheduler.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/teamcity_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/teamcity_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/testRail_connector.cpython-37.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/testRail_connector.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/__pycache__/web_fetcher.cpython-38.pyc +0 -0
- package/knowledge_base/connectors/base.py +44 -0
- package/knowledge_base/connectors/bitbucket_connector.py +25 -0
- package/knowledge_base/connectors/community_connector.py +112 -0
- package/knowledge_base/connectors/confluence_connector.py +165 -0
- package/knowledge_base/connectors/jira_connector.py +174 -0
- package/knowledge_base/connectors/kb_igel_connector.py +145 -0
- package/knowledge_base/connectors/playwright_fetcher.py +50 -0
- package/knowledge_base/connectors/query_bridge.py +170 -0
- package/knowledge_base/connectors/search_backends.py +368 -0
- package/knowledge_base/connectors/serviceNow_connector.py +25 -0
- package/knowledge_base/connectors/sync_scheduler.py +111 -0
- package/knowledge_base/connectors/teamcity_connector.py +25 -0
- package/knowledge_base/connectors/testRail_connector.py +25 -0
- package/knowledge_base/connectors/web_fetcher.py +280 -0
- package/knowledge_base/core/__init__.py +8 -0
- package/knowledge_base/core/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/cache.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/circuit_breaker.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/confidence.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/confidence.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/logging_setup.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/metrics.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/precedence.cpython-37.pyc +0 -0
- package/knowledge_base/core/__pycache__/precedence.cpython-38.pyc +0 -0
- package/knowledge_base/core/__pycache__/request_context.cpython-38.pyc +0 -0
- package/knowledge_base/core/cache.py +98 -0
- package/knowledge_base/core/circuit_breaker.py +33 -0
- package/knowledge_base/core/confidence.py +254 -0
- package/knowledge_base/core/logging_setup.py +39 -0
- package/knowledge_base/core/metrics.py +63 -0
- package/knowledge_base/core/precedence.py +354 -0
- package/knowledge_base/core/request_context.py +54 -0
- package/knowledge_base/db/__init__.py +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/client.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/connector_sync.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/feedback_schema.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/feedback_schema.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-314.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/kg_introspect.cpython-38.pyc +0 -0
- package/knowledge_base/db/__pycache__/schema.cpython-37.pyc +0 -0
- package/knowledge_base/db/__pycache__/schema.cpython-38.pyc +0 -0
- package/knowledge_base/db/client.py +100 -0
- package/knowledge_base/db/connector_sync.py +43 -0
- package/knowledge_base/db/feedback_schema.py +548 -0
- package/knowledge_base/db/igel_schema.py +150 -0
- package/knowledge_base/db/kg_introspect.py +116 -0
- package/knowledge_base/db/migrations.py +22 -0
- package/knowledge_base/db/schema.py +649 -0
- package/knowledge_base/deploy/Dockerfile +23 -0
- package/knowledge_base/deploy/feedback_automation.sh +18 -0
- package/knowledge_base/deploy/firecrawl-docker.sh +50 -0
- package/knowledge_base/deploy/igel-testgen.service +26 -0
- package/knowledge_base/deploy/install_reranker.sh +92 -0
- package/knowledge_base/deploy/requirements.txt +68 -0
- package/knowledge_base/deploy/run_server.sh +35 -0
- package/knowledge_base/docs/TEST_GENERATION_GUIDE.md +174 -0
- package/knowledge_base/embeddings/__init__.py +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-314.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-37.pyc +0 -0
- package/knowledge_base/embeddings/__pycache__/azure_embedder.cpython-38.pyc +0 -0
- package/knowledge_base/embeddings/azure_embedder.py +99 -0
- package/knowledge_base/eval/__init__.py +33 -0
- package/knowledge_base/eval/__main__.py +172 -0
- package/knowledge_base/eval/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/__main__.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/baseline.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/baseline.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/harness.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/harness.cpython-38.pyc +0 -0
- package/knowledge_base/eval/__pycache__/scorers.cpython-37.pyc +0 -0
- package/knowledge_base/eval/__pycache__/scorers.cpython-38.pyc +0 -0
- package/knowledge_base/eval/baseline.py +213 -0
- package/knowledge_base/eval/harness.py +400 -0
- package/knowledge_base/eval/queries_50.json +302 -0
- package/knowledge_base/eval/scorers.py +494 -0
- package/knowledge_base/exemplars/README.md +7 -0
- package/knowledge_base/exemplars/__pycache__/pytest_reference_snippet.cpython-37.pyc +0 -0
- package/knowledge_base/exemplars/gold_manual_concise_snippet.md +8 -0
- package/knowledge_base/exemplars/gold_manual_detailed_snippet.md +7 -0
- package/knowledge_base/exemplars/pytest_reference_snippet.py +37 -0
- package/knowledge_base/feedback/__init__.py +10 -0
- package/knowledge_base/feedback/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/analytics.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/analytics.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/applier.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/applier.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/curator.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/curator.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/handler.cpython-37.pyc +0 -0
- package/knowledge_base/feedback/__pycache__/handler.cpython-38.pyc +0 -0
- package/knowledge_base/feedback/analytics.py +72 -0
- package/knowledge_base/feedback/applier.py +93 -0
- package/knowledge_base/feedback/curator.py +49 -0
- package/knowledge_base/feedback/handler.py +151 -0
- package/knowledge_base/generation/__init__.py +5 -0
- package/knowledge_base/generation/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/input_classifier.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/input_classifier.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/manual_tc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/manual_tc_parser.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/prompts.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/prompts.cpython-38.pyc +0 -0
- package/knowledge_base/generation/__pycache__/tc_transformer.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/test_generator.cpython-37.pyc +0 -0
- package/knowledge_base/generation/__pycache__/test_generator.cpython-38.pyc +0 -0
- package/knowledge_base/generation/input_classifier.py +148 -0
- package/knowledge_base/generation/manual_tc_parser.py +180 -0
- package/knowledge_base/generation/prompts.py +755 -0
- package/knowledge_base/generation/tc_transformer.py +368 -0
- package/knowledge_base/generation/test_generator.py +553 -0
- package/knowledge_base/graph_db/__init__.py +5 -0
- package/knowledge_base/graph_db/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/graphiti_client.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/kg_traversal.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/migrate_kg.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/neo4j_client.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/neo4j_client.cpython-38.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/schema.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/__pycache__/temporal_ingest.cpython-37.pyc +0 -0
- package/knowledge_base/graph_db/graphiti_client.py +127 -0
- package/knowledge_base/graph_db/kg_traversal.py +192 -0
- package/knowledge_base/graph_db/migrate_kg.py +93 -0
- package/knowledge_base/graph_db/neo4j_client.py +116 -0
- package/knowledge_base/graph_db/schema.py +22 -0
- package/knowledge_base/graph_db/temporal_ingest.py +59 -0
- package/knowledge_base/ingestion/__init__.py +1 -0
- package/knowledge_base/ingestion/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest_images.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/ingest_images.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/kg_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/kg_extractor.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/__pycache__/web_ingest.cpython-38.pyc +0 -0
- package/knowledge_base/ingestion/ingest.py +346 -0
- package/knowledge_base/ingestion/ingest_images.py +330 -0
- package/knowledge_base/ingestion/kg_extractor.py +358 -0
- package/knowledge_base/ingestion/web_ingest.py +83 -0
- package/knowledge_base/intelligence/__init__.py +1 -0
- package/knowledge_base/intelligence/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/execution_ingest.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/predictive_engine.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/__pycache__/risk_scorer.cpython-37.pyc +0 -0
- package/knowledge_base/intelligence/execution_ingest.py +34 -0
- package/knowledge_base/intelligence/predictive_engine.py +7 -0
- package/knowledge_base/intelligence/risk_scorer.py +8 -0
- package/knowledge_base/memory/__init__.py +6 -0
- package/knowledge_base/memory/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/memory/__pycache__/cognee_client.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/cognee_client.cpython-38.pyc +0 -0
- package/knowledge_base/memory/__pycache__/ingest_memory.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/memory_types.cpython-37.pyc +0 -0
- package/knowledge_base/memory/__pycache__/memory_types.cpython-38.pyc +0 -0
- package/knowledge_base/memory/cognee_client.py +164 -0
- package/knowledge_base/memory/ingest_memory.py +60 -0
- package/knowledge_base/memory/memory_types.py +23 -0
- package/knowledge_base/models/test_requirement.py +84 -0
- package/knowledge_base/parsers/__init__.py +0 -0
- package/knowledge_base/parsers/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/csv_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/csv_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/doc_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/doc_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/html_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/image_extractor.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/image_extractor.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/markdown_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/markdown_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/pdf_parser.cpython-37.pyc +0 -0
- package/knowledge_base/parsers/__pycache__/pdf_parser.cpython-38.pyc +0 -0
- package/knowledge_base/parsers/csv_parser.py +126 -0
- package/knowledge_base/parsers/doc_parser.py +176 -0
- package/knowledge_base/parsers/html_parser.py +151 -0
- package/knowledge_base/parsers/image_extractor.py +370 -0
- package/knowledge_base/parsers/markdown_parser.py +116 -0
- package/knowledge_base/parsers/pdf_parser.py +178 -0
- package/knowledge_base/retrieval/__init__.py +1 -0
- package/knowledge_base/retrieval/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/context_fusion.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/context_fusion.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/knowledge_graph.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/knowledge_graph.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/reranker.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/reranker.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retrieval_debug.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retrieval_debug.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retriever.cpython-37.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/retriever.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/unified_query.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/__pycache__/web_retriever.cpython-38.pyc +0 -0
- package/knowledge_base/retrieval/context_fusion.py +264 -0
- package/knowledge_base/retrieval/knowledge_graph.py +267 -0
- package/knowledge_base/retrieval/reranker.py +308 -0
- package/knowledge_base/retrieval/retrieval_debug.py +69 -0
- package/knowledge_base/retrieval/retriever.py +885 -0
- package/knowledge_base/retrieval/unified_query.py +189 -0
- package/knowledge_base/retrieval/web_retriever.py +337 -0
- package/knowledge_base/validators/__init__.py +1 -0
- package/knowledge_base/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/knowledge_base/validators/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/validators/__pycache__/step_fidelity.cpython-314.pyc +0 -0
- package/knowledge_base/validators/__pycache__/step_fidelity.cpython-37.pyc +0 -0
- package/knowledge_base/validators/step_fidelity.py +88 -0
- package/knowledge_base/vision/__init__.py +0 -0
- package/knowledge_base/vision/__pycache__/__init__.cpython-37.pyc +0 -0
- package/knowledge_base/vision/__pycache__/__init__.cpython-38.pyc +0 -0
- package/knowledge_base/vision/__pycache__/image_describer.cpython-37.pyc +0 -0
- package/knowledge_base/vision/__pycache__/image_describer.cpython-38.pyc +0 -0
- package/knowledge_base/vision/image_describer.py +202 -0
- package/package.json +31 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Creates and manages the PostgreSQL schema for the IGEL Knowledge Base.
|
|
3
|
+
Tables:
|
|
4
|
+
kb_documents - one row per source file
|
|
5
|
+
kb_parent_chunks - large sections (800-1200 tokens), returned as context
|
|
6
|
+
kb_chunks - small indexed units (150-300 tokens) with vector embeddings
|
|
7
|
+
feedback_events - user feedback for continuous learning (Phase 2)
|
|
8
|
+
eval_runs - evaluation run summaries (Phase 0)
|
|
9
|
+
eval_results - per-query evaluation results (Phase 0)
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
from knowledge_base.db.client import get_conn
|
|
13
|
+
from knowledge_base.config import cfg
|
|
14
|
+
|
|
15
|
+
_SCHEMA_SQL = f"""
|
|
16
|
+
-- Enable required extensions
|
|
17
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
18
|
+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
19
|
+
|
|
20
|
+
-- Source documents registry
|
|
21
|
+
CREATE TABLE IF NOT EXISTS kb_documents (
|
|
22
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
23
|
+
file_name TEXT NOT NULL,
|
|
24
|
+
file_path TEXT NOT NULL,
|
|
25
|
+
file_type TEXT NOT NULL,
|
|
26
|
+
file_hash TEXT UNIQUE NOT NULL,
|
|
27
|
+
product TEXT,
|
|
28
|
+
total_parent_chunks INT DEFAULT 0,
|
|
29
|
+
total_chunks INT DEFAULT 0,
|
|
30
|
+
ingested_at TIMESTAMP DEFAULT NOW(),
|
|
31
|
+
metadata JSONB DEFAULT '{{}}'::jsonb
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
-- Parent chunks: full sections returned during retrieval for full context
|
|
35
|
+
CREATE TABLE IF NOT EXISTS kb_parent_chunks (
|
|
36
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
37
|
+
document_id UUID NOT NULL REFERENCES kb_documents(id) ON DELETE CASCADE,
|
|
38
|
+
chunk_index INT NOT NULL,
|
|
39
|
+
content TEXT NOT NULL,
|
|
40
|
+
section_title TEXT,
|
|
41
|
+
chunk_type TEXT,
|
|
42
|
+
page_number INT,
|
|
43
|
+
metadata JSONB DEFAULT '{{}}'::jsonb,
|
|
44
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
-- Child chunks: indexed for vector + full-text search
|
|
48
|
+
CREATE TABLE IF NOT EXISTS kb_chunks (
|
|
49
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
50
|
+
parent_chunk_id UUID NOT NULL REFERENCES kb_parent_chunks(id) ON DELETE CASCADE,
|
|
51
|
+
document_id UUID NOT NULL REFERENCES kb_documents(id) ON DELETE CASCADE,
|
|
52
|
+
chunk_index INT NOT NULL,
|
|
53
|
+
content TEXT NOT NULL,
|
|
54
|
+
embedding VECTOR({cfg.EMBEDDING_DIM}),
|
|
55
|
+
token_count INT,
|
|
56
|
+
contains_steps BOOLEAN DEFAULT FALSE,
|
|
57
|
+
has_table BOOLEAN DEFAULT FALSE,
|
|
58
|
+
chunk_type TEXT,
|
|
59
|
+
metadata JSONB DEFAULT '{{}}'::jsonb,
|
|
60
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
-- Note: no ANN index on `embedding` — text-embedding-3-large is 3072-dim,
|
|
64
|
+
-- which exceeds pgvector's 2000-dim cap for IVFFlat/HNSW with vector_cosine_ops.
|
|
65
|
+
-- For this corpus size (~100 docs, a few thousand chunks) sequential scan
|
|
66
|
+
-- via vector_cosine_ops operator class is fast enough. If we ever exceed
|
|
67
|
+
-- ~50k chunks, switch to halfvec(3072) + HNSW (4000-dim cap).
|
|
68
|
+
|
|
69
|
+
-- Full-text search index (BM25-style fallback)
|
|
70
|
+
CREATE INDEX IF NOT EXISTS kb_chunks_fts_idx
|
|
71
|
+
ON kb_chunks USING gin(to_tsvector('english', content));
|
|
72
|
+
|
|
73
|
+
-- Lookup indexes
|
|
74
|
+
CREATE INDEX IF NOT EXISTS kb_chunks_doc_idx ON kb_chunks(document_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS kb_chunks_parent_idx ON kb_chunks(parent_chunk_id);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS kb_chunks_type_idx ON kb_chunks(chunk_type);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS kb_parent_doc_idx ON kb_parent_chunks(document_id);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS kb_docs_hash_idx ON kb_documents(file_hash);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS kb_docs_product_idx ON kb_documents(product);
|
|
80
|
+
|
|
81
|
+
-- ─────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
-- Images table: every image extracted from any source document.
|
|
83
|
+
-- Hard FK to kb_documents (cascades on doc delete) and soft FK to nearest section.
|
|
84
|
+
-- Stores binary + multiple text representations (OCR-grade verbatim + semantic).
|
|
85
|
+
-- ─────────────────────────────────────────────────────────────────────────────
|
|
86
|
+
CREATE TABLE IF NOT EXISTS kb_images (
|
|
87
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
88
|
+
document_id UUID NOT NULL REFERENCES kb_documents(id) ON DELETE CASCADE,
|
|
89
|
+
parent_chunk_id UUID REFERENCES kb_parent_chunks(id) ON DELETE SET NULL,
|
|
90
|
+
|
|
91
|
+
-- Position / identity
|
|
92
|
+
page_number INT,
|
|
93
|
+
sequence_index INT NOT NULL, -- order across the whole document
|
|
94
|
+
bbox JSONB, -- {{x0,y0,x1,y1}} on page (PDFs)
|
|
95
|
+
image_hash TEXT NOT NULL, -- sha256 of bytes (per-document, not globally unique)
|
|
96
|
+
image_format TEXT NOT NULL, -- png, jpeg, etc.
|
|
97
|
+
width INT,
|
|
98
|
+
height INT,
|
|
99
|
+
image_bytes BYTEA NOT NULL, -- raw image preserved
|
|
100
|
+
|
|
101
|
+
-- Captured text representations (no context loss)
|
|
102
|
+
image_type TEXT, -- ui_screenshot, diagram, photo, icon, ...
|
|
103
|
+
verbatim_text TEXT, -- every visible label/button/value
|
|
104
|
+
ui_elements JSONB, -- structured controls + state
|
|
105
|
+
semantic_description TEXT, -- 2-4 sentence narrative
|
|
106
|
+
test_relevance TEXT, -- what test cases this illustrates
|
|
107
|
+
surrounding_text TEXT, -- paragraph above/below in source doc
|
|
108
|
+
caption TEXT, -- explicit caption if any
|
|
109
|
+
|
|
110
|
+
-- Vector embedding of the combined description (for similarity search)
|
|
111
|
+
description_embedding VECTOR({cfg.EMBEDDING_DIM}),
|
|
112
|
+
|
|
113
|
+
metadata JSONB DEFAULT '{{}}'::jsonb,
|
|
114
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
115
|
+
|
|
116
|
+
UNIQUE (document_id, sequence_index) -- per-doc dedup; same image in different docs ok
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
CREATE INDEX IF NOT EXISTS kb_images_doc_idx ON kb_images(document_id);
|
|
120
|
+
CREATE INDEX IF NOT EXISTS kb_images_parent_idx ON kb_images(parent_chunk_id);
|
|
121
|
+
CREATE INDEX IF NOT EXISTS kb_images_page_idx ON kb_images(document_id, page_number);
|
|
122
|
+
CREATE INDEX IF NOT EXISTS kb_images_hash_idx ON kb_images(image_hash);
|
|
123
|
+
CREATE INDEX IF NOT EXISTS kb_images_fts_idx
|
|
124
|
+
ON kb_images USING gin(to_tsvector('english',
|
|
125
|
+
coalesce(verbatim_text,'') || ' ' ||
|
|
126
|
+
coalesce(semantic_description,'') || ' ' ||
|
|
127
|
+
coalesce(surrounding_text,'')));
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
_KG_TABLES_SQL = """
|
|
131
|
+
CREATE TABLE IF NOT EXISTS knowledge_graph_nodes (
|
|
132
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
133
|
+
node_type TEXT NOT NULL,
|
|
134
|
+
value TEXT NOT NULL,
|
|
135
|
+
normalized TEXT NOT NULL DEFAULT '',
|
|
136
|
+
metadata JSONB DEFAULT '{}'::jsonb,
|
|
137
|
+
parent_chunk_id UUID REFERENCES kb_parent_chunks(id) ON DELETE SET NULL,
|
|
138
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
139
|
+
UNIQUE (node_type, normalized)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
CREATE TABLE IF NOT EXISTS knowledge_graph_edges (
|
|
143
|
+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
144
|
+
source_node_id UUID NOT NULL REFERENCES knowledge_graph_nodes(id) ON DELETE CASCADE,
|
|
145
|
+
target_node_id UUID NOT NULL REFERENCES knowledge_graph_nodes(id) ON DELETE CASCADE,
|
|
146
|
+
relation TEXT NOT NULL DEFAULT 'related_to',
|
|
147
|
+
weight DOUBLE PRECISION DEFAULT 1.0,
|
|
148
|
+
metadata JSONB DEFAULT '{}'::jsonb,
|
|
149
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
150
|
+
UNIQUE (source_node_id, target_node_id, relation)
|
|
151
|
+
);
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
_KG_INDEX_SQL = """
|
|
155
|
+
CREATE INDEX IF NOT EXISTS ix_kgn_chunk ON knowledge_graph_nodes(parent_chunk_id);
|
|
156
|
+
CREATE INDEX IF NOT EXISTS ix_kgn_type ON knowledge_graph_nodes(node_type);
|
|
157
|
+
CREATE INDEX IF NOT EXISTS ix_kgn_norm ON knowledge_graph_nodes(normalized);
|
|
158
|
+
CREATE INDEX IF NOT EXISTS ix_kge_src ON knowledge_graph_edges(source_node_id);
|
|
159
|
+
CREATE INDEX IF NOT EXISTS ix_kge_tgt ON knowledge_graph_edges(target_node_id);
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
# Backward compat alias
|
|
163
|
+
_KG_GRAPH_SQL = _KG_TABLES_SQL + _KG_INDEX_SQL
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def ensure_knowledge_graph_tables() -> None:
|
|
167
|
+
"""Create KG tables if absent; migrate legacy tables missing columns."""
|
|
168
|
+
with get_conn() as conn:
|
|
169
|
+
with conn.cursor() as cur:
|
|
170
|
+
cur.execute(_KG_TABLES_SQL)
|
|
171
|
+
cur.execute(
|
|
172
|
+
"""
|
|
173
|
+
ALTER TABLE knowledge_graph_nodes
|
|
174
|
+
ADD COLUMN IF NOT EXISTS parent_chunk_id UUID
|
|
175
|
+
REFERENCES kb_parent_chunks(id) ON DELETE SET NULL
|
|
176
|
+
"""
|
|
177
|
+
)
|
|
178
|
+
cur.execute(
|
|
179
|
+
"""
|
|
180
|
+
ALTER TABLE knowledge_graph_nodes
|
|
181
|
+
ADD COLUMN IF NOT EXISTS normalized TEXT NOT NULL DEFAULT ''
|
|
182
|
+
"""
|
|
183
|
+
)
|
|
184
|
+
cur.execute(
|
|
185
|
+
"""
|
|
186
|
+
ALTER TABLE knowledge_graph_nodes
|
|
187
|
+
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT NOW()
|
|
188
|
+
"""
|
|
189
|
+
)
|
|
190
|
+
cur.execute(_KG_INDEX_SQL)
|
|
191
|
+
try:
|
|
192
|
+
from knowledge_base.db.kg_introspect import clear_kg_layout_cache
|
|
193
|
+
clear_kg_layout_cache()
|
|
194
|
+
except Exception:
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def create_schema() -> None:
|
|
201
|
+
"""Ensure schema via Alembic migrations, with legacy DDL fallback."""
|
|
202
|
+
try:
|
|
203
|
+
from knowledge_base.db.migrations import run_migrations
|
|
204
|
+
run_migrations("head")
|
|
205
|
+
except Exception as exc:
|
|
206
|
+
import logging
|
|
207
|
+
logging.getLogger(__name__).warning(
|
|
208
|
+
"Alembic migration failed (%s) — applying legacy DDL fallback", exc,
|
|
209
|
+
)
|
|
210
|
+
with get_conn() as conn:
|
|
211
|
+
with conn.cursor() as cur:
|
|
212
|
+
cur.execute(_SCHEMA_SQL)
|
|
213
|
+
ensure_knowledge_graph_tables()
|
|
214
|
+
from knowledge_base.db.feedback_schema import ensure_feedback_tables
|
|
215
|
+
ensure_feedback_tables()
|
|
216
|
+
print(" Schema ready (Alembic + kb_documents, kb_parent_chunks, kb_chunks, knowledge_graph_*)")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def drop_schema() -> None:
|
|
220
|
+
"""Full reset — drops all KB tables. Use only for clean re-ingestion."""
|
|
221
|
+
sql = """
|
|
222
|
+
DROP TABLE IF EXISTS knowledge_graph_edges CASCADE;
|
|
223
|
+
DROP TABLE IF EXISTS knowledge_graph_nodes CASCADE;
|
|
224
|
+
DROP TABLE IF EXISTS kb_images CASCADE;
|
|
225
|
+
DROP TABLE IF EXISTS kb_chunks CASCADE;
|
|
226
|
+
DROP TABLE IF EXISTS kb_parent_chunks CASCADE;
|
|
227
|
+
DROP TABLE IF EXISTS kb_documents CASCADE;
|
|
228
|
+
"""
|
|
229
|
+
with get_conn() as conn:
|
|
230
|
+
with conn.cursor() as cur:
|
|
231
|
+
cur.execute(sql)
|
|
232
|
+
print(" Schema dropped.")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def document_exists(file_hash: str) -> str | None:
|
|
236
|
+
"""Return document id if already ingested, else None."""
|
|
237
|
+
with get_conn() as conn:
|
|
238
|
+
with conn.cursor() as cur:
|
|
239
|
+
cur.execute(
|
|
240
|
+
"SELECT id FROM kb_documents WHERE file_hash = %s",
|
|
241
|
+
(file_hash,)
|
|
242
|
+
)
|
|
243
|
+
row = cur.fetchone()
|
|
244
|
+
return str(row[0]) if row else None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def document_has_chunks(document_id: str) -> bool:
|
|
248
|
+
"""True if document has at least one indexed child chunk."""
|
|
249
|
+
with get_conn() as conn:
|
|
250
|
+
with conn.cursor() as cur:
|
|
251
|
+
cur.execute(
|
|
252
|
+
"SELECT COALESCE(total_chunks, 0) FROM kb_documents WHERE id = %s",
|
|
253
|
+
(document_id,),
|
|
254
|
+
)
|
|
255
|
+
row = cur.fetchone()
|
|
256
|
+
return bool(row and row[0] and row[0] > 0)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def insert_document(
|
|
260
|
+
file_name: str,
|
|
261
|
+
file_path: str,
|
|
262
|
+
file_type: str,
|
|
263
|
+
file_hash: str,
|
|
264
|
+
product: str,
|
|
265
|
+
metadata: dict,
|
|
266
|
+
*,
|
|
267
|
+
conn=None,
|
|
268
|
+
) -> str:
|
|
269
|
+
sql = """
|
|
270
|
+
INSERT INTO kb_documents (file_name, file_path, file_type, file_hash, product, metadata)
|
|
271
|
+
VALUES (%s, %s, %s, %s, %s, %s::jsonb)
|
|
272
|
+
RETURNING id
|
|
273
|
+
"""
|
|
274
|
+
import json
|
|
275
|
+
|
|
276
|
+
params = (file_name, file_path, file_type, file_hash, product, json.dumps(metadata))
|
|
277
|
+
|
|
278
|
+
def _exec(cur):
|
|
279
|
+
cur.execute(sql, params)
|
|
280
|
+
return str(cur.fetchone()[0])
|
|
281
|
+
|
|
282
|
+
if conn is not None:
|
|
283
|
+
with conn.cursor() as cur:
|
|
284
|
+
return _exec(cur)
|
|
285
|
+
with get_conn() as c:
|
|
286
|
+
with c.cursor() as cur:
|
|
287
|
+
return _exec(cur)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def insert_parent_chunk(
|
|
291
|
+
document_id: str,
|
|
292
|
+
chunk_index: int,
|
|
293
|
+
content: str,
|
|
294
|
+
section_title: str,
|
|
295
|
+
chunk_type: str,
|
|
296
|
+
page_number: int,
|
|
297
|
+
metadata: dict,
|
|
298
|
+
*,
|
|
299
|
+
conn=None,
|
|
300
|
+
) -> str:
|
|
301
|
+
sql = """
|
|
302
|
+
INSERT INTO kb_parent_chunks (document_id, chunk_index, content, section_title, chunk_type, page_number, metadata)
|
|
303
|
+
VALUES (%s, %s, %s, %s, %s, %s, %s::jsonb)
|
|
304
|
+
RETURNING id
|
|
305
|
+
"""
|
|
306
|
+
import json
|
|
307
|
+
|
|
308
|
+
params = (
|
|
309
|
+
document_id, chunk_index, content, section_title,
|
|
310
|
+
chunk_type, page_number, json.dumps(metadata),
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def _exec(cur):
|
|
314
|
+
cur.execute(sql, params)
|
|
315
|
+
return str(cur.fetchone()[0])
|
|
316
|
+
|
|
317
|
+
if conn is not None:
|
|
318
|
+
with conn.cursor() as cur:
|
|
319
|
+
return _exec(cur)
|
|
320
|
+
with get_conn() as c:
|
|
321
|
+
with c.cursor() as cur:
|
|
322
|
+
return _exec(cur)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def insert_chunks_batch(rows: list[dict], *, conn=None) -> None:
|
|
326
|
+
"""Batch insert child chunks with embeddings."""
|
|
327
|
+
if not rows:
|
|
328
|
+
return
|
|
329
|
+
import json
|
|
330
|
+
from psycopg2.extras import execute_values
|
|
331
|
+
|
|
332
|
+
sql = """
|
|
333
|
+
INSERT INTO kb_chunks
|
|
334
|
+
(parent_chunk_id, document_id, chunk_index, content, embedding,
|
|
335
|
+
token_count, contains_steps, has_table, chunk_type, metadata)
|
|
336
|
+
VALUES %s
|
|
337
|
+
"""
|
|
338
|
+
values = [
|
|
339
|
+
(
|
|
340
|
+
r["parent_chunk_id"],
|
|
341
|
+
r["document_id"],
|
|
342
|
+
r["chunk_index"],
|
|
343
|
+
r["content"],
|
|
344
|
+
r["embedding"],
|
|
345
|
+
r["token_count"],
|
|
346
|
+
r["contains_steps"],
|
|
347
|
+
r["has_table"],
|
|
348
|
+
r["chunk_type"],
|
|
349
|
+
json.dumps(r["metadata"]),
|
|
350
|
+
)
|
|
351
|
+
for r in rows
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
def _exec(cur):
|
|
355
|
+
execute_values(cur, sql, values, template=None, page_size=50)
|
|
356
|
+
|
|
357
|
+
if conn is not None:
|
|
358
|
+
with conn.cursor() as cur:
|
|
359
|
+
_exec(cur)
|
|
360
|
+
else:
|
|
361
|
+
with get_conn() as c:
|
|
362
|
+
with c.cursor() as cur:
|
|
363
|
+
_exec(cur)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def update_document_counts(document_id: str, parent_count: int, chunk_count: int, *, conn=None) -> None:
|
|
367
|
+
sql = "UPDATE kb_documents SET total_parent_chunks=%s, total_chunks=%s WHERE id=%s"
|
|
368
|
+
params = (parent_count, chunk_count, document_id)
|
|
369
|
+
|
|
370
|
+
def _exec(cur):
|
|
371
|
+
cur.execute(sql, params)
|
|
372
|
+
|
|
373
|
+
if conn is not None:
|
|
374
|
+
with conn.cursor() as cur:
|
|
375
|
+
_exec(cur)
|
|
376
|
+
else:
|
|
377
|
+
with get_conn() as c:
|
|
378
|
+
with c.cursor() as cur:
|
|
379
|
+
_exec(cur)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def clear_document_chunks(document_id: str, *, conn=None) -> None:
|
|
383
|
+
"""Remove all chunks for a document so it can be re-ingested safely."""
|
|
384
|
+
def _exec(cur):
|
|
385
|
+
cur.execute("DELETE FROM kb_chunks WHERE document_id = %s", (document_id,))
|
|
386
|
+
cur.execute("DELETE FROM kb_parent_chunks WHERE document_id = %s", (document_id,))
|
|
387
|
+
cur.execute(
|
|
388
|
+
"UPDATE kb_documents SET total_parent_chunks=0, total_chunks=0 WHERE id=%s",
|
|
389
|
+
(document_id,),
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
if conn is not None:
|
|
393
|
+
with conn.cursor() as cur:
|
|
394
|
+
_exec(cur)
|
|
395
|
+
else:
|
|
396
|
+
with get_conn() as c:
|
|
397
|
+
with c.cursor() as cur:
|
|
398
|
+
_exec(cur)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def ingest_document_atomic(
|
|
402
|
+
*,
|
|
403
|
+
file_name: str,
|
|
404
|
+
file_path: str,
|
|
405
|
+
file_type: str,
|
|
406
|
+
file_hash: str,
|
|
407
|
+
product: str,
|
|
408
|
+
doc_metadata: dict,
|
|
409
|
+
parents: list,
|
|
410
|
+
existing_id: str | None,
|
|
411
|
+
embed_fn,
|
|
412
|
+
format_fn,
|
|
413
|
+
batch_size: int,
|
|
414
|
+
) -> tuple[str, int, int, int]:
|
|
415
|
+
"""
|
|
416
|
+
Atomically insert document + parent + child chunks in one transaction.
|
|
417
|
+
Returns (doc_id, parent_count, chunk_count, validation_skipped).
|
|
418
|
+
"""
|
|
419
|
+
from knowledge_base.db.client import get_transaction
|
|
420
|
+
|
|
421
|
+
validation_skipped = 0
|
|
422
|
+
with get_transaction() as conn:
|
|
423
|
+
if existing_id:
|
|
424
|
+
doc_id = existing_id
|
|
425
|
+
clear_document_chunks(doc_id, conn=conn)
|
|
426
|
+
else:
|
|
427
|
+
doc_id = insert_document(
|
|
428
|
+
file_name=file_name,
|
|
429
|
+
file_path=file_path,
|
|
430
|
+
file_type=file_type,
|
|
431
|
+
file_hash=file_hash,
|
|
432
|
+
product=product,
|
|
433
|
+
metadata=doc_metadata,
|
|
434
|
+
conn=conn,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
total_children = 0
|
|
438
|
+
for p_idx, parent in enumerate(parents):
|
|
439
|
+
parent_id = insert_parent_chunk(
|
|
440
|
+
document_id=doc_id,
|
|
441
|
+
chunk_index=p_idx,
|
|
442
|
+
content=parent.content,
|
|
443
|
+
section_title=parent.section_title,
|
|
444
|
+
chunk_type=parent.chunk_type,
|
|
445
|
+
page_number=parent.page_number,
|
|
446
|
+
metadata=parent.metadata,
|
|
447
|
+
conn=conn,
|
|
448
|
+
)
|
|
449
|
+
if not parent.children:
|
|
450
|
+
continue
|
|
451
|
+
|
|
452
|
+
valid_children = []
|
|
453
|
+
for child in parent.children:
|
|
454
|
+
if getattr(child, "validation", None) and not child.validation.passed:
|
|
455
|
+
validation_skipped += 1
|
|
456
|
+
continue
|
|
457
|
+
valid_children.append(child)
|
|
458
|
+
if not valid_children:
|
|
459
|
+
continue
|
|
460
|
+
|
|
461
|
+
child_texts = [c.content for c in valid_children]
|
|
462
|
+
embeddings = embed_fn(child_texts, batch_size=batch_size)
|
|
463
|
+
rows = []
|
|
464
|
+
for c_idx, (child, embedding) in enumerate(zip(valid_children, embeddings)):
|
|
465
|
+
rows.append({
|
|
466
|
+
"parent_chunk_id": parent_id,
|
|
467
|
+
"document_id": doc_id,
|
|
468
|
+
"chunk_index": total_children + c_idx,
|
|
469
|
+
"content": child.content,
|
|
470
|
+
"embedding": format_fn(embedding),
|
|
471
|
+
"token_count": child.token_count,
|
|
472
|
+
"contains_steps": child.contains_steps,
|
|
473
|
+
"has_table": child.has_table,
|
|
474
|
+
"chunk_type": child.chunk_type,
|
|
475
|
+
"metadata": {**child.metadata, "parent_chunk_index": p_idx},
|
|
476
|
+
})
|
|
477
|
+
insert_chunks_batch(rows, conn=conn)
|
|
478
|
+
total_children += len(rows)
|
|
479
|
+
|
|
480
|
+
update_document_counts(doc_id, len(parents), total_children, conn=conn)
|
|
481
|
+
return doc_id, len(parents), total_children, validation_skipped
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def get_stats() -> dict:
|
|
485
|
+
with get_conn() as conn:
|
|
486
|
+
with conn.cursor() as cur:
|
|
487
|
+
cur.execute("SELECT COUNT(*) FROM kb_documents")
|
|
488
|
+
docs = cur.fetchone()[0]
|
|
489
|
+
cur.execute("SELECT COUNT(*) FROM kb_parent_chunks")
|
|
490
|
+
parents = cur.fetchone()[0]
|
|
491
|
+
cur.execute("SELECT COUNT(*) FROM kb_chunks")
|
|
492
|
+
chunks = cur.fetchone()[0]
|
|
493
|
+
cur.execute("SELECT COUNT(*) FROM kb_chunks WHERE embedding IS NULL")
|
|
494
|
+
missing_emb = cur.fetchone()[0]
|
|
495
|
+
try:
|
|
496
|
+
cur.execute("SELECT COUNT(*) FROM kb_images")
|
|
497
|
+
images = cur.fetchone()[0]
|
|
498
|
+
cur.execute("SELECT COUNT(*) FROM kb_images WHERE description_embedding IS NULL")
|
|
499
|
+
images_missing_emb = cur.fetchone()[0]
|
|
500
|
+
except Exception:
|
|
501
|
+
images, images_missing_emb = 0, 0
|
|
502
|
+
|
|
503
|
+
# Knowledge Graph stats
|
|
504
|
+
kg_nodes = kg_edges = kg_orphan_parents = 0
|
|
505
|
+
try:
|
|
506
|
+
cur.execute("SELECT COUNT(*) FROM knowledge_graph_nodes")
|
|
507
|
+
kg_nodes = cur.fetchone()[0]
|
|
508
|
+
cur.execute("SELECT COUNT(*) FROM knowledge_graph_edges")
|
|
509
|
+
kg_edges = cur.fetchone()[0]
|
|
510
|
+
cur.execute("""
|
|
511
|
+
SELECT COUNT(*) FROM kb_parent_chunks p
|
|
512
|
+
WHERE NOT EXISTS (
|
|
513
|
+
SELECT 1 FROM knowledge_graph_nodes n
|
|
514
|
+
WHERE n.parent_chunk_id = p.id
|
|
515
|
+
)
|
|
516
|
+
""")
|
|
517
|
+
kg_orphan_parents = cur.fetchone()[0]
|
|
518
|
+
except Exception:
|
|
519
|
+
pass
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
"documents": docs,
|
|
523
|
+
"parent_chunks": parents,
|
|
524
|
+
"chunks": chunks,
|
|
525
|
+
"missing_embeddings": missing_emb,
|
|
526
|
+
"images": images,
|
|
527
|
+
"images_missing_embeddings": images_missing_emb,
|
|
528
|
+
"kg_nodes": kg_nodes,
|
|
529
|
+
"kg_edges": kg_edges,
|
|
530
|
+
"kg_orphan_parents (no KG entity)": kg_orphan_parents,
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
# ── Image helpers ─────────────────────────────────────────────────────────────
|
|
535
|
+
|
|
536
|
+
def insert_image(
|
|
537
|
+
document_id: str,
|
|
538
|
+
parent_chunk_id: str | None,
|
|
539
|
+
sequence_index: int,
|
|
540
|
+
page_number: int | None,
|
|
541
|
+
bbox: dict | None,
|
|
542
|
+
image_hash: str,
|
|
543
|
+
image_format: str,
|
|
544
|
+
width: int | None,
|
|
545
|
+
height: int | None,
|
|
546
|
+
image_bytes: bytes,
|
|
547
|
+
image_type: str,
|
|
548
|
+
verbatim_text: str,
|
|
549
|
+
ui_elements: list | dict | None,
|
|
550
|
+
semantic_description: str,
|
|
551
|
+
test_relevance: str,
|
|
552
|
+
surrounding_text: str,
|
|
553
|
+
caption: str | None,
|
|
554
|
+
description_embedding: str,
|
|
555
|
+
metadata: dict,
|
|
556
|
+
) -> str:
|
|
557
|
+
import json
|
|
558
|
+
sql = """
|
|
559
|
+
INSERT INTO kb_images (
|
|
560
|
+
document_id, parent_chunk_id, sequence_index, page_number, bbox,
|
|
561
|
+
image_hash, image_format, width, height, image_bytes,
|
|
562
|
+
image_type, verbatim_text, ui_elements, semantic_description,
|
|
563
|
+
test_relevance, surrounding_text, caption,
|
|
564
|
+
description_embedding, metadata
|
|
565
|
+
) VALUES (
|
|
566
|
+
%s, %s, %s, %s, %s::jsonb,
|
|
567
|
+
%s, %s, %s, %s, %s,
|
|
568
|
+
%s, %s, %s::jsonb, %s,
|
|
569
|
+
%s, %s, %s,
|
|
570
|
+
%s, %s::jsonb
|
|
571
|
+
)
|
|
572
|
+
ON CONFLICT (document_id, sequence_index) DO UPDATE SET
|
|
573
|
+
parent_chunk_id = EXCLUDED.parent_chunk_id,
|
|
574
|
+
page_number = EXCLUDED.page_number,
|
|
575
|
+
bbox = EXCLUDED.bbox,
|
|
576
|
+
image_hash = EXCLUDED.image_hash,
|
|
577
|
+
image_format = EXCLUDED.image_format,
|
|
578
|
+
width = EXCLUDED.width,
|
|
579
|
+
height = EXCLUDED.height,
|
|
580
|
+
image_bytes = EXCLUDED.image_bytes,
|
|
581
|
+
image_type = EXCLUDED.image_type,
|
|
582
|
+
verbatim_text = EXCLUDED.verbatim_text,
|
|
583
|
+
ui_elements = EXCLUDED.ui_elements,
|
|
584
|
+
semantic_description = EXCLUDED.semantic_description,
|
|
585
|
+
test_relevance = EXCLUDED.test_relevance,
|
|
586
|
+
surrounding_text = EXCLUDED.surrounding_text,
|
|
587
|
+
caption = EXCLUDED.caption,
|
|
588
|
+
description_embedding = EXCLUDED.description_embedding,
|
|
589
|
+
metadata = EXCLUDED.metadata
|
|
590
|
+
RETURNING id
|
|
591
|
+
"""
|
|
592
|
+
with get_conn() as conn:
|
|
593
|
+
with conn.cursor() as cur:
|
|
594
|
+
cur.execute(sql, (
|
|
595
|
+
document_id, parent_chunk_id, sequence_index, page_number,
|
|
596
|
+
json.dumps(bbox) if bbox else None,
|
|
597
|
+
image_hash, image_format, width, height, image_bytes,
|
|
598
|
+
image_type, verbatim_text,
|
|
599
|
+
json.dumps(ui_elements) if ui_elements is not None else None,
|
|
600
|
+
semantic_description, test_relevance, surrounding_text, caption,
|
|
601
|
+
description_embedding,
|
|
602
|
+
json.dumps(metadata),
|
|
603
|
+
))
|
|
604
|
+
return str(cur.fetchone()[0])
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def find_nearest_parent_chunk(document_id: str, page_number: int | None) -> str | None:
|
|
608
|
+
"""Return the kb_parent_chunks.id whose page_number is closest to the given page,
|
|
609
|
+
so an image can be linked to the most relevant section."""
|
|
610
|
+
if page_number is None:
|
|
611
|
+
# Just pick the first parent chunk for this document
|
|
612
|
+
sql = "SELECT id FROM kb_parent_chunks WHERE document_id = %s ORDER BY chunk_index ASC LIMIT 1"
|
|
613
|
+
params = (document_id,)
|
|
614
|
+
else:
|
|
615
|
+
sql = """
|
|
616
|
+
SELECT id FROM kb_parent_chunks
|
|
617
|
+
WHERE document_id = %s
|
|
618
|
+
ORDER BY ABS(COALESCE(page_number, 0) - %s) ASC, chunk_index ASC
|
|
619
|
+
LIMIT 1
|
|
620
|
+
"""
|
|
621
|
+
params = (document_id, page_number)
|
|
622
|
+
with get_conn() as conn:
|
|
623
|
+
with conn.cursor() as cur:
|
|
624
|
+
cur.execute(sql, params)
|
|
625
|
+
row = cur.fetchone()
|
|
626
|
+
return str(row[0]) if row else None
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def list_documents_for_image_pass() -> list[dict]:
|
|
630
|
+
"""Documents already ingested as text — for the image pass to iterate over."""
|
|
631
|
+
sql = """
|
|
632
|
+
SELECT id, file_name, file_path, file_type
|
|
633
|
+
FROM kb_documents
|
|
634
|
+
ORDER BY ingested_at ASC
|
|
635
|
+
"""
|
|
636
|
+
with get_conn() as conn:
|
|
637
|
+
with conn.cursor() as cur:
|
|
638
|
+
cur.execute(sql)
|
|
639
|
+
return [
|
|
640
|
+
{"id": str(r[0]), "file_name": r[1], "file_path": r[2], "file_type": r[3]}
|
|
641
|
+
for r in cur.fetchall()
|
|
642
|
+
]
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def document_has_images(document_id: str) -> bool:
|
|
646
|
+
with get_conn() as conn:
|
|
647
|
+
with conn.cursor() as cur:
|
|
648
|
+
cur.execute("SELECT 1 FROM kb_images WHERE document_id = %s LIMIT 1", (document_id,))
|
|
649
|
+
return cur.fetchone() is not None
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
FROM python:3.10-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
RUN apt-get update && apt-get install -y --no-install-recommends curl \
|
|
6
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
7
|
+
|
|
8
|
+
COPY knowledge_base/ knowledge_base/
|
|
9
|
+
COPY alembic.ini alembic.ini
|
|
10
|
+
|
|
11
|
+
COPY knowledge_base/deploy/requirements.txt requirements.txt
|
|
12
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
13
|
+
|
|
14
|
+
ENV PYTHONPATH=/app
|
|
15
|
+
ENV TESTGEN_HOST=0.0.0.0
|
|
16
|
+
ENV TESTGEN_PORT=8000
|
|
17
|
+
|
|
18
|
+
EXPOSE 8000
|
|
19
|
+
|
|
20
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
|
|
21
|
+
CMD curl -f http://localhost:8000/health || exit 1
|
|
22
|
+
|
|
23
|
+
CMD ["uvicorn", "knowledge_base.api.server:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Apply pending feedback promotions and ingest to operational memory.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
cd "$(dirname "$0")/../.."
|
|
5
|
+
export PYTHONPATH="${PWD}:${PYTHONPATH:-}"
|
|
6
|
+
/usr/bin/python3.8 - <<'PY'
|
|
7
|
+
from knowledge_base.db.client import init_pool, close_pool
|
|
8
|
+
from knowledge_base.feedback.applier import apply_pending_promotions
|
|
9
|
+
from knowledge_base.memory.ingest_memory import ingest_curated_feedback
|
|
10
|
+
|
|
11
|
+
init_pool()
|
|
12
|
+
results = apply_pending_promotions(limit=50)
|
|
13
|
+
print(f"Applied {len(results)} feedback promotions")
|
|
14
|
+
if results:
|
|
15
|
+
stats = ingest_curated_feedback(limit=len(results))
|
|
16
|
+
print(f"Memory ingest: {stats}")
|
|
17
|
+
close_pool()
|
|
18
|
+
PY
|