contextsynapse 1.0.0__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.
- contextsynapse/__init__.py +107 -0
- contextsynapse/__main__.py +9 -0
- contextsynapse/a2a/__init__.py +28 -0
- contextsynapse/a2a/client.py +120 -0
- contextsynapse/a2a/discovery.py +128 -0
- contextsynapse/a2a/handlers.py +164 -0
- contextsynapse/a2a/models.py +246 -0
- contextsynapse/a2a/streaming.py +92 -0
- contextsynapse/a2a/task_manager.py +275 -0
- contextsynapse/adapters/__init__.py +98 -0
- contextsynapse/adapters/_base.py +298 -0
- contextsynapse/adapters/autogen/__init__.py +4 -0
- contextsynapse/adapters/autogen/tools.py +34 -0
- contextsynapse/adapters/crewai/__init__.py +4 -0
- contextsynapse/adapters/crewai/tools.py +63 -0
- contextsynapse/adapters/langchain/__init__.py +19 -0
- contextsynapse/adapters/langchain/message_history.py +17 -0
- contextsynapse/adapters/langchain/retriever.py +158 -0
- contextsynapse/adapters/langchain/tools.py +43 -0
- contextsynapse/adapters/langgraph/__init__.py +21 -0
- contextsynapse/adapters/langgraph/checkpoint.py +223 -0
- contextsynapse/adapters/langgraph/context_tools.py +341 -0
- contextsynapse/adapters/langgraph/message_history.py +138 -0
- contextsynapse/adapters/langgraph/tools.py +43 -0
- contextsynapse/adapters/llamaindex/__init__.py +4 -0
- contextsynapse/adapters/llamaindex/tools.py +64 -0
- contextsynapse/adapters/openai/__init__.py +24 -0
- contextsynapse/adapters/openai/tools.py +206 -0
- contextsynapse/adapters/pydantic_ai/__init__.py +4 -0
- contextsynapse/adapters/pydantic_ai/tools.py +36 -0
- contextsynapse/adapters/swarm/__init__.py +4 -0
- contextsynapse/adapters/swarm/tools.py +44 -0
- contextsynapse/agents/__init__.py +6 -0
- contextsynapse/agents/auto_capture.py +80 -0
- contextsynapse/agents/dispatcher.py +299 -0
- contextsynapse/agents/notifications.py +112 -0
- contextsynapse/aiql/__init__.py +71 -0
- contextsynapse/aiql/cache.py +341 -0
- contextsynapse/aiql/compiler/__init__.py +62 -0
- contextsynapse/aiql/compiler/optimizer.py +126 -0
- contextsynapse/aiql/compiler/planner.py +366 -0
- contextsynapse/aiql/compiler/statistics.py +235 -0
- contextsynapse/aiql/compiler/validator.py +425 -0
- contextsynapse/aiql/engine/__init__.py +11 -0
- contextsynapse/aiql/engine/chunk_storage.py +2584 -0
- contextsynapse/aiql/engine/executor.py +7737 -0
- contextsynapse/aiql/engine/extraction_integration.py +442 -0
- contextsynapse/aiql/engine/graph_builder.py +405 -0
- contextsynapse/aiql/engine/node_creation_from_normalized.py +691 -0
- contextsynapse/aiql/engine/performance_monitor.py +289 -0
- contextsynapse/aiql/engine/postprocessing.py +365 -0
- contextsynapse/aiql/engine/ray_stage_executors.py +918 -0
- contextsynapse/aiql/engine/redis_cache.py +106 -0
- contextsynapse/aiql/engine/streaming_json.py +366 -0
- contextsynapse/aiql/engine/streaming_parquet.py +568 -0
- contextsynapse/aiql/engine/streaming_ray_chunking.py +419 -0
- contextsynapse/aiql/grammar/__init__.py +14 -0
- contextsynapse/aiql/grammar/aiql_grammar.py +1822 -0
- contextsynapse/aiql/grammar/base.py +71 -0
- contextsynapse/aiql/parser/__init__.py +46 -0
- contextsynapse/aiql/parser/aiql_parser.py +11330 -0
- contextsynapse/aiql/parser/base_parser.py +47 -0
- contextsynapse/api/__init__.py +5 -0
- contextsynapse/api/a2a_router.py +233 -0
- contextsynapse/api/admin_router.py +140 -0
- contextsynapse/api/agent_worker_router.py +978 -0
- contextsynapse/api/algorithms_router.py +317 -0
- contextsynapse/api/api.py +4144 -0
- contextsynapse/api/audit.py +204 -0
- contextsynapse/api/auth.py +441 -0
- contextsynapse/api/auth_router.py +537 -0
- contextsynapse/api/billing.py +261 -0
- contextsynapse/api/billing_router.py +275 -0
- contextsynapse/api/boundary_router.py +452 -0
- contextsynapse/api/cognition_router.py +116 -0
- contextsynapse/api/connector_router.py +237 -0
- contextsynapse/api/context_router.py +1619 -0
- contextsynapse/api/dashboard_router.py +11367 -0
- contextsynapse/api/errors.py +183 -0
- contextsynapse/api/events.py +88 -0
- contextsynapse/api/experiment_bootstrap.py +321 -0
- contextsynapse/api/experiment_orchestrator.py +1078 -0
- contextsynapse/api/experiment_router.py +2089 -0
- contextsynapse/api/feature_gate.py +89 -0
- contextsynapse/api/federation_router.py +108 -0
- contextsynapse/api/integrations.py +567 -0
- contextsynapse/api/integrations_router.py +461 -0
- contextsynapse/api/intelligence_router.py +1028 -0
- contextsynapse/api/metering.py +155 -0
- contextsynapse/api/metrics.py +112 -0
- contextsynapse/api/models.py +38 -0
- contextsynapse/api/monitoring_router.py +174 -0
- contextsynapse/api/pipeline_router.py +1437 -0
- contextsynapse/api/playground_conn.py +116 -0
- contextsynapse/api/projects_router.py +131 -0
- contextsynapse/api/queries_router.py +282 -0
- contextsynapse/api/quota.py +95 -0
- contextsynapse/api/rate_limit.py +64 -0
- contextsynapse/api/search_router.py +261 -0
- contextsynapse/api/shield_router.py +447 -0
- contextsynapse/api/tenant_guard.py +103 -0
- contextsynapse/api/tenant_quotas.py +231 -0
- contextsynapse/api/tenants.py +305 -0
- contextsynapse/api/users.py +646 -0
- contextsynapse/api/v1.py +167 -0
- contextsynapse/api/vertical_builder_router.py +387 -0
- contextsynapse/benchmark/__init__.py +15 -0
- contextsynapse/benchmark/__main__.py +64 -0
- contextsynapse/benchmark/agents.py +338 -0
- contextsynapse/benchmark/live_ab.py +338 -0
- contextsynapse/benchmark/reporter.py +149 -0
- contextsynapse/benchmark/runner.py +264 -0
- contextsynapse/benchmark/savings.py +266 -0
- contextsynapse/benchmark/token_counter.py +212 -0
- contextsynapse/benchmark/workloads.py +289 -0
- contextsynapse/buffer/__init__.py +154 -0
- contextsynapse/buffer/base.py +257 -0
- contextsynapse/buffer/duckdb_buffer.py +246 -0
- contextsynapse/buffer/file_buffer.py +229 -0
- contextsynapse/buffer/lmdb_buffer.py +286 -0
- contextsynapse/buffer/local_buffer.py +154 -0
- contextsynapse/buffer/redis_buffer.py +211 -0
- contextsynapse/buffer/sqlite_buffer.py +266 -0
- contextsynapse/cache.py +2 -0
- contextsynapse/cli/__init__.py +40 -0
- contextsynapse/cli/cli.py +475 -0
- contextsynapse/cli/config_cli.py +177 -0
- contextsynapse/cli/scaffold.py +465 -0
- contextsynapse/cognition/__init__.py +31 -0
- contextsynapse/cognition/derivation.py +55 -0
- contextsynapse/cognition/events.py +135 -0
- contextsynapse/cognition/feedback.py +52 -0
- contextsynapse/cognition/hallucination.py +90 -0
- contextsynapse/cognition/invalidation.py +70 -0
- contextsynapse/cognition/read_tracker.py +50 -0
- contextsynapse/collaboration.py +2 -0
- contextsynapse/comparison.py +2 -0
- contextsynapse/config/__init__.py +10 -0
- contextsynapse/config/connectors/amfi_nav.yaml +18 -0
- contextsynapse/config/connectors/auto_sector.yaml +20 -0
- contextsynapse/config/connectors/banking_sector.yaml +20 -0
- contextsynapse/config/connectors/energy_sector.yaml +20 -0
- contextsynapse/config/connectors/fmcg_sector.yaml +20 -0
- contextsynapse/config/connectors/nsdl_fpi.yaml +9 -0
- contextsynapse/config/connectors/nse_price.yaml +61 -0
- contextsynapse/config/connectors/pharma_sector.yaml +20 -0
- contextsynapse/config/connectors/rbi_dbie.yaml +12 -0
- contextsynapse/config/context_presets/ai_research.json +25 -0
- contextsynapse/config/context_presets/chatgpt_conversations.json +19 -0
- contextsynapse/config/context_presets/claude_conversations.json +19 -0
- contextsynapse/config/context_presets/legal_compliance.json +21 -0
- contextsynapse/config/context_presets/meeting_notes.json +21 -0
- contextsynapse/config/context_presets/slack_engineering.json +21 -0
- contextsynapse/config/context_presets/tech_climate.json +24 -0
- contextsynapse/config/context_presets/toi_politics.json +25 -0
- contextsynapse/config/database_config.py +453 -0
- contextsynapse/config/deployment.py +221 -0
- contextsynapse/config/gpt_action_schema.json +164 -0
- contextsynapse/config/indicators/india_macro.yaml +213 -0
- contextsynapse/config/logging_config.py +88 -0
- contextsynapse/config/mode_config.py +223 -0
- contextsynapse/config/schemas/api_spec.yaml +48 -0
- contextsynapse/config/schemas/architecture_doc.yaml +51 -0
- contextsynapse/config/schemas/chat_history.yaml +90 -0
- contextsynapse/config/schemas/chatgpt_conversation.yaml +101 -0
- contextsynapse/config/schemas/claude_conversation.yaml +148 -0
- contextsynapse/config/schemas/contract.yaml +48 -0
- contextsynapse/config/schemas/conversation.yaml +167 -0
- contextsynapse/config/schemas/database.yaml +74 -0
- contextsynapse/config/schemas/decision.yaml +72 -0
- contextsynapse/config/schemas/ecommerce.yaml +56 -0
- contextsynapse/config/schemas/education.yaml +42 -0
- contextsynapse/config/schemas/healthcare.yaml +133 -0
- contextsynapse/config/schemas/hr_document.yaml +48 -0
- contextsynapse/config/schemas/invoice.yaml +40 -0
- contextsynapse/config/schemas/knowledge_base.yaml +75 -0
- contextsynapse/config/schemas/legal.yaml +42 -0
- contextsynapse/config/schemas/marketing_content.yaml +48 -0
- contextsynapse/config/schemas/meeting_notes.yaml +51 -0
- contextsynapse/config/schemas/news_article.yaml +61 -0
- contextsynapse/config/schemas/real_estate.yaml +49 -0
- contextsynapse/config/schemas/requirements_doc.yaml +48 -0
- contextsynapse/config/schemas/research_paper.yaml +56 -0
- contextsynapse/config/schemas/resume.yaml +49 -0
- contextsynapse/config/schemas/retail.yaml +42 -0
- contextsynapse/config/schemas/rule_meta.yaml +173 -0
- contextsynapse/config/schemas/rules.yaml +72 -0
- contextsynapse/config/schemas/screener_meta.yaml +236 -0
- contextsynapse/config/schemas/sdlc.yaml +103 -0
- contextsynapse/config/schemas/session_graph.yaml +172 -0
- contextsynapse/config/schemas/support_ticket.yaml +48 -0
- contextsynapse/config/schemas/web.yaml +64 -0
- contextsynapse/config/sensors/earnings_calendar.yaml +52 -0
- contextsynapse/config/sensors/global_risk.yaml +53 -0
- contextsynapse/config/sensors/government_policy.yaml +54 -0
- contextsynapse/config/sensors/supply_chain.yaml +50 -0
- contextsynapse/config/sensors/templates/behavioral.yaml +56 -0
- contextsynapse/config/sensors/templates/equity_sentiment.yaml +48 -0
- contextsynapse/config/sensors/templates/global_macro.yaml +47 -0
- contextsynapse/config/sensors/templates/market_data.yaml +118 -0
- contextsynapse/config/sensors/templates/sector_technical.yaml +47 -0
- contextsynapse/config/sensors/weather.yaml +52 -0
- contextsynapse/config/storage_strategy.py +202 -0
- contextsynapse/config/templates/competitive_intel.yaml +39 -0
- contextsynapse/config/templates/geopolitical_risk.yaml +46 -0
- contextsynapse/config/templates/market_analysis.yaml +58 -0
- contextsynapse/connectors/__init__.py +15 -0
- contextsynapse/connectors/api_router.py +121 -0
- contextsynapse/connectors/base.py +357 -0
- contextsynapse/connectors/financial/audio.py +170 -0
- contextsynapse/connectors/financial/youtube.py +272 -0
- contextsynapse/connectors/github.py +164 -0
- contextsynapse/connectors/jira.py +120 -0
- contextsynapse/connectors/kafka_connector.py +124 -0
- contextsynapse/connectors/pipeline_connector.py +747 -0
- contextsynapse/connectors/registry.py +116 -0
- contextsynapse/connectors/scheduler.py +87 -0
- contextsynapse/connectors/universal.py +360 -0
- contextsynapse/context/__init__.py +96 -0
- contextsynapse/context/__main__.py +4 -0
- contextsynapse/context/acl.py +125 -0
- contextsynapse/context/agent_card.py +201 -0
- contextsynapse/context/agent_memory.py +814 -0
- contextsynapse/context/agents.py +472 -0
- contextsynapse/context/agents_redis.py +391 -0
- contextsynapse/context/assembled.py +204 -0
- contextsynapse/context/attribution.py +113 -0
- contextsynapse/context/blob.py +184 -0
- contextsynapse/context/boundaries.py +187 -0
- contextsynapse/context/boundary.py +507 -0
- contextsynapse/context/bundle.py +155 -0
- contextsynapse/context/cli.py +519 -0
- contextsynapse/context/collaboration.py +165 -0
- contextsynapse/context/compiler.py +604 -0
- contextsynapse/context/composite.py +536 -0
- contextsynapse/context/compression.py +147 -0
- contextsynapse/context/context_manager.py +888 -0
- contextsynapse/context/context_schema.py +90 -0
- contextsynapse/context/context_schema.yaml +105 -0
- contextsynapse/context/context_units.py +891 -0
- contextsynapse/context/conversation.py +488 -0
- contextsynapse/context/dedup.py +207 -0
- contextsynapse/context/document_processor.py +698 -0
- contextsynapse/context/embedding_hooks.py +338 -0
- contextsynapse/context/execution_schema.py +274 -0
- contextsynapse/context/fan_out.py +138 -0
- contextsynapse/context/frozen.py +80 -0
- contextsynapse/context/gravity.py +227 -0
- contextsynapse/context/hub.py +1401 -0
- contextsynapse/context/ingest.py +391 -0
- contextsynapse/context/injection.py +226 -0
- contextsynapse/context/interaction_graphifier.py +562 -0
- contextsynapse/context/layers.py +574 -0
- contextsynapse/context/projection.py +1195 -0
- contextsynapse/context/promotion.py +634 -0
- contextsynapse/context/proof.py +131 -0
- contextsynapse/context/propagation.py +577 -0
- contextsynapse/context/pubsub.py +135 -0
- contextsynapse/context/quality.py +1054 -0
- contextsynapse/context/quality_tracker.py +270 -0
- contextsynapse/context/scoping.py +370 -0
- contextsynapse/context/seed.py +992 -0
- contextsynapse/context/session.py +1142 -0
- contextsynapse/context/session_graph.py +593 -0
- contextsynapse/context/session_memory.py +309 -0
- contextsynapse/context/session_resolver.py +111 -0
- contextsynapse/context/skill_learning.py +237 -0
- contextsynapse/context/smart_budget.py +129 -0
- contextsynapse/context/source_policy.py +242 -0
- contextsynapse/context/store_factory.py +53 -0
- contextsynapse/context/sync.py +648 -0
- contextsynapse/context/token.py +236 -0
- contextsynapse/context/vector_integration.py +297 -0
- contextsynapse/context/webhooks.py +194 -0
- contextsynapse/context/working_memory.py +224 -0
- contextsynapse/core/__init__.py +18 -0
- contextsynapse/core/archiver.py +237 -0
- contextsynapse/core/change_stream.py +282 -0
- contextsynapse/core/checkpoint.py +310 -0
- contextsynapse/core/cloud_storage.py +387 -0
- contextsynapse/core/context_state.py +651 -0
- contextsynapse/core/cron.py +324 -0
- contextsynapse/core/datasource.py +643 -0
- contextsynapse/core/db.py +289 -0
- contextsynapse/core/federation.py +283 -0
- contextsynapse/core/graph_coordinator.py +201 -0
- contextsynapse/core/graph_intelligence.py +388 -0
- contextsynapse/core/graph_structures.py +106 -0
- contextsynapse/core/graph_sync.py +157 -0
- contextsynapse/core/hybrid_graph_storage.py +2998 -0
- contextsynapse/core/lifecycle.py +691 -0
- contextsynapse/core/multiworker.py +378 -0
- contextsynapse/core/pruning.py +312 -0
- contextsynapse/core/redis_registry.py +524 -0
- contextsynapse/core/registry.py +1043 -0
- contextsynapse/core/registry_factory.py +51 -0
- contextsynapse/core/registry_metadata.py +294 -0
- contextsynapse/core/replay.py +354 -0
- contextsynapse/core/replication.py +339 -0
- contextsynapse/core/time_travel.py +260 -0
- contextsynapse/core/write_behind.py +152 -0
- contextsynapse/core/write_context.py +39 -0
- contextsynapse/db/__init__.py +1 -0
- contextsynapse/db/postgres.py +267 -0
- contextsynapse/db/profile.py +236 -0
- contextsynapse/db/rules.py +328 -0
- contextsynapse/demo/__init__.py +0 -0
- contextsynapse/demo/report.py +147 -0
- contextsynapse/demo/runner.py +520 -0
- contextsynapse/demo/scenario.py +165 -0
- contextsynapse/demo/session_demo.py +280 -0
- contextsynapse/demo/session_report.py +143 -0
- contextsynapse/demo/universal_runner.py +257 -0
- contextsynapse/engine/__init__.py +15 -0
- contextsynapse/engine/core.py +555 -0
- contextsynapse/extraction/__init__.py +69 -0
- contextsynapse/extraction/cli.py +274 -0
- contextsynapse/extraction/config.py +107 -0
- contextsynapse/extraction/examples/example_usage.py +118 -0
- contextsynapse/extraction/examples/sample_manifest.json +53 -0
- contextsynapse/extraction/examples/sample_normalized.json +185 -0
- contextsynapse/extraction/extract_engine.py +440 -0
- contextsynapse/extraction/extractors/__init__.py +37 -0
- contextsynapse/extraction/extractors/chat_export_extractor.py +189 -0
- contextsynapse/extraction/extractors/csv_extractor.py +83 -0
- contextsynapse/extraction/extractors/docx_extractor.py +129 -0
- contextsynapse/extraction/extractors/excel_extractor.py +152 -0
- contextsynapse/extraction/extractors/html_extractor.py +146 -0
- contextsynapse/extraction/extractors/pdf_extractor.py +635 -0
- contextsynapse/extraction/extractors/pdf_extractor_layoutparser.py +408 -0
- contextsynapse/extraction/extractors/register_extractors.py +63 -0
- contextsynapse/extraction/extractors/text_extractor.py +65 -0
- contextsynapse/extraction/extractors/txt_extractor.py +120 -0
- contextsynapse/extraction/extractors/website_extractor.py +246 -0
- contextsynapse/extraction/fact_extractor.py +236 -0
- contextsynapse/extraction/file_manager.py +353 -0
- contextsynapse/extraction/hierarchy.py +239 -0
- contextsynapse/extraction/id_generator.py +450 -0
- contextsynapse/extraction/layout_detector.py +409 -0
- contextsynapse/extraction/llm_entity_extractor.py +301 -0
- contextsynapse/extraction/normalized_store.py +480 -0
- contextsynapse/extraction/normalizer.py +594 -0
- contextsynapse/extraction/parquet_writer.py +598 -0
- contextsynapse/extraction/post_processors/__init__.py +40 -0
- contextsynapse/extraction/post_processors/column_reorganizer.py +507 -0
- contextsynapse/extraction/ray_normalization.py +233 -0
- contextsynapse/extraction/ray_runner.py +207 -0
- contextsynapse/extraction/redis_schema_registry.py +222 -0
- contextsynapse/extraction/registry.py +204 -0
- contextsynapse/extraction/schema_loader.py +663 -0
- contextsynapse/extraction/schema_registry.py +230 -0
- contextsynapse/extraction/semantic_normalizer.py +245 -0
- contextsynapse/extraction/version_manager.py +314 -0
- contextsynapse/gateway/__init__.py +24 -0
- contextsynapse/gateway/action_emitter.py +212 -0
- contextsynapse/gateway/cost_tracker.py +508 -0
- contextsynapse/gateway/gateway.py +377 -0
- contextsynapse/gateway/policy.py +303 -0
- contextsynapse/governance/__init__.py +13 -0
- contextsynapse/governance/layer.py +513 -0
- contextsynapse/ingestion/__init__.py +15 -0
- contextsynapse/ingestion/amplifier.py +288 -0
- contextsynapse/ingestion/async_ingest.py +463 -0
- contextsynapse/ingestion/chunker.py +303 -0
- contextsynapse/ingestion/chunking.py +58 -0
- contextsynapse/ingestion/cleaner.py +190 -0
- contextsynapse/ingestion/cleanse.py +252 -0
- contextsynapse/ingestion/connectors/__init__.py +38 -0
- contextsynapse/ingestion/connectors/base.py +300 -0
- contextsynapse/ingestion/connectors/chatgpt_memory.py +247 -0
- contextsynapse/ingestion/connectors/claude_memory.py +274 -0
- contextsynapse/ingestion/connectors/sap_ingestor.py +208 -0
- contextsynapse/ingestion/content_detector.py +80 -0
- contextsynapse/ingestion/content_monitor.py +502 -0
- contextsynapse/ingestion/dedup.py +106 -0
- contextsynapse/ingestion/feed.py +640 -0
- contextsynapse/ingestion/filters.py +461 -0
- contextsynapse/ingestion/graph_builder.py +705 -0
- contextsynapse/ingestion/input_classifier.py +307 -0
- contextsynapse/ingestion/job_manager.py +571 -0
- contextsynapse/ingestion/llm_extractor.py +610 -0
- contextsynapse/ingestion/orchestrator.py +116 -0
- contextsynapse/ingestion/parsers/__init__.py +19 -0
- contextsynapse/ingestion/parsers/graph_parser_registry.py +103 -0
- contextsynapse/ingestion/parsers/graphml_parser.py +141 -0
- contextsynapse/ingestion/parsers/jsonld_parser.py +171 -0
- contextsynapse/ingestion/parsers/rdf_parser.py +150 -0
- contextsynapse/ingestion/pipeline_context.py +228 -0
- contextsynapse/ingestion/pipeline_store.py +1195 -0
- contextsynapse/ingestion/queue.py +133 -0
- contextsynapse/ingestion/reprocess.py +179 -0
- contextsynapse/ingestion/scenario_router.py +224 -0
- contextsynapse/ingestion/schema_extractor.py +759 -0
- contextsynapse/ingestion/schema_validator.py +274 -0
- contextsynapse/ingestion/sdlc_ingest.py +87 -0
- contextsynapse/ingestion/smart_ingest.py +2451 -0
- contextsynapse/ingestion/source_connector.py +171 -0
- contextsynapse/ingestion/stage_executor.py +2095 -0
- contextsynapse/ingestion/stages/__init__.py +9 -0
- contextsynapse/ingestion/stages/tabular_to_graph.py +289 -0
- contextsynapse/ingestion/strategies.py +386 -0
- contextsynapse/ingestion/universal/__init__.py +4 -0
- contextsynapse/ingestion/universal/_operator_registry.py +59 -0
- contextsynapse/ingestion/universal/ingest_content.py +32 -0
- contextsynapse/ingestion/universal/operators/__init__.py +1 -0
- contextsynapse/ingestion/universal/operators/base.py +19 -0
- contextsynapse/ingestion/universal/operators/build_edges.py +75 -0
- contextsynapse/ingestion/universal/operators/cluster_topics.py +397 -0
- contextsynapse/ingestion/universal/operators/deduplicate.py +45 -0
- contextsynapse/ingestion/universal/operators/detect_signals.py +90 -0
- contextsynapse/ingestion/universal/operators/embed.py +80 -0
- contextsynapse/ingestion/universal/operators/extract_entities.py +253 -0
- contextsynapse/ingestion/universal/operators/extract_preferences.py +117 -0
- contextsynapse/ingestion/universal/operators/filter_content.py +69 -0
- contextsynapse/ingestion/universal/operators/index_bm25.py +52 -0
- contextsynapse/ingestion/universal/operators/infer_domains.py +69 -0
- contextsynapse/ingestion/universal/operators/link_cross_reference.py +210 -0
- contextsynapse/ingestion/universal/operators/parse_records.py +66 -0
- contextsynapse/ingestion/universal/operators/resolve_entities.py +261 -0
- contextsynapse/ingestion/universal/operators/scanners/__init__.py +16 -0
- contextsynapse/ingestion/universal/operators/scanners/edges.py +173 -0
- contextsynapse/ingestion/universal/operators/scanners/git.py +187 -0
- contextsynapse/ingestion/universal/operators/scanners/github.py +135 -0
- contextsynapse/ingestion/universal/operators/scanners/github_api.py +509 -0
- contextsynapse/ingestion/universal/operators/scanners/helpers.py +67 -0
- contextsynapse/ingestion/universal/operators/scanners/jira.py +65 -0
- contextsynapse/ingestion/universal/operators/scanners/llm_enrichment.py +82 -0
- contextsynapse/ingestion/universal/operators/scanners/repo.py +149 -0
- contextsynapse/ingestion/universal/operators/sdlc_scan.py +213 -0
- contextsynapse/ingestion/universal/operators/spec_scanner.py +149 -0
- contextsynapse/ingestion/universal/operators/store_documents.py +72 -0
- contextsynapse/ingestion/universal/operators/synthesize_cu.py +180 -0
- contextsynapse/ingestion/universal/operators/validate_gate.py +65 -0
- contextsynapse/ingestion/universal/parsers/__init__.py +5 -0
- contextsynapse/ingestion/universal/parsers/record_parser.py +203 -0
- contextsynapse/ingestion/universal/parsers/turn_parser.py +329 -0
- contextsynapse/ingestion/universal/shared_signals.py +161 -0
- contextsynapse/ingestion/universal/stage_executor.py +219 -0
- contextsynapse/ingestion/web_crawler.py +265 -0
- contextsynapse/intelligence/__init__.py +53 -0
- contextsynapse/intelligence/alerts.py +198 -0
- contextsynapse/intelligence/collector.py +655 -0
- contextsynapse/intelligence/comparison.py +198 -0
- contextsynapse/intelligence/config.py +56 -0
- contextsynapse/intelligence/conflict_detector.py +182 -0
- contextsynapse/intelligence/context_gaps.py +192 -0
- contextsynapse/intelligence/context_radar.py +135 -0
- contextsynapse/intelligence/correlation_engine.py +416 -0
- contextsynapse/intelligence/correlation_template.py +120 -0
- contextsynapse/intelligence/dedup.py +296 -0
- contextsynapse/intelligence/event_bus.py +91 -0
- contextsynapse/intelligence/feedback_loop.py +101 -0
- contextsynapse/intelligence/freshness.py +307 -0
- contextsynapse/intelligence/fundamental_feed.py +551 -0
- contextsynapse/intelligence/geo_data.py +170 -0
- contextsynapse/intelligence/geo_reference.py +112 -0
- contextsynapse/intelligence/graph_fusion.py +465 -0
- contextsynapse/intelligence/heuristics.py +176 -0
- contextsynapse/intelligence/impact_tracker.py +336 -0
- contextsynapse/intelligence/macro_indicators.py +319 -0
- contextsynapse/intelligence/ocr.py +104 -0
- contextsynapse/intelligence/persistence.py +267 -0
- contextsynapse/intelligence/pipeline_health.py +130 -0
- contextsynapse/intelligence/price_feed.py +221 -0
- contextsynapse/intelligence/rate_limiter.py +130 -0
- contextsynapse/intelligence/reactive.py +411 -0
- contextsynapse/intelligence/runtime_context.py +390 -0
- contextsynapse/intelligence/sentiment_decay.py +426 -0
- contextsynapse/intelligence/session.py +277 -0
- contextsynapse/intelligence/signal_hierarchy.py +438 -0
- contextsynapse/intelligence/signals.py +185 -0
- contextsynapse/intelligence/source_watcher.py +132 -0
- contextsynapse/intelligence/table_enricher.py +256 -0
- contextsynapse/intelligence/tagger.py +319 -0
- contextsynapse/intelligence/timeseries.py +209 -0
- contextsynapse/intelligence/tracker.py +318 -0
- contextsynapse/intelligence/watchdog.py +392 -0
- contextsynapse/intelligence/watchdog_manager.py +263 -0
- contextsynapse/intelligence/webhook_receiver.py +165 -0
- contextsynapse/intelligence/weight_learner.py +234 -0
- contextsynapse/llm/__init__.py +8 -0
- contextsynapse/llm/client.py +348 -0
- contextsynapse/llm/rate_limiter.py +166 -0
- contextsynapse/logging_config.py +2 -0
- contextsynapse/marketplace/__init__.py +7 -0
- contextsynapse/marketplace/registry.py +173 -0
- contextsynapse/mcp/__init__.py +11 -0
- contextsynapse/mcp/__main__.py +4 -0
- contextsynapse/mcp/auth_middleware.py +212 -0
- contextsynapse/mcp/connection_pool.py +128 -0
- contextsynapse/mcp/server.py +986 -0
- contextsynapse/mcp/session_context.py +67 -0
- contextsynapse/memory/__init__.py +34 -0
- contextsynapse/memory/engine.py +475 -0
- contextsynapse/memory/temporal.py +327 -0
- contextsynapse/metadata/__init__.py +12 -0
- contextsynapse/metadata/metadata_db.py +272 -0
- contextsynapse/metadata/metadata_query_tool.py +300 -0
- contextsynapse/metadata/metadata_tracker.py +425 -0
- contextsynapse/models/__init__.py +27 -0
- contextsynapse/models/embedding_service.py +360 -0
- contextsynapse/models/model_registry.py +228 -0
- contextsynapse/multiworker.py +2 -0
- contextsynapse/pipelines/__init__.py +1 -0
- contextsynapse/pipelines/executor.py +851 -0
- contextsynapse/pipelines/filters.py +189 -0
- contextsynapse/pipelines/models.py +176 -0
- contextsynapse/pipelines/scheduler.py +268 -0
- contextsynapse/playground/__init__.py +1 -0
- contextsynapse/playground/templates.py +85 -0
- contextsynapse/plugins/__init__.py +43 -0
- contextsynapse/plugins/api.py +66 -0
- contextsynapse/plugins/base.py +350 -0
- contextsynapse/plugins/domain_interface.py +508 -0
- contextsynapse/plugins/domain_loader.py +241 -0
- contextsynapse/plugins/loader.py +148 -0
- contextsynapse/plugins/registry.py +265 -0
- contextsynapse/project/__init__.py +11 -0
- contextsynapse/project/code_context.py +807 -0
- contextsynapse/project/connectors/__init__.py +4 -0
- contextsynapse/project/connectors/github_connector.py +113 -0
- contextsynapse/project/connectors/jira_connector.py +160 -0
- contextsynapse/project/graph.py +1023 -0
- contextsynapse/project/project_context.py +545 -0
- contextsynapse/project/scanner_registry.py +61 -0
- contextsynapse/project/schema_manager.py +322 -0
- contextsynapse/project/schemas/knowledge.yaml +59 -0
- contextsynapse/project/schemas/sdlc.yaml +369 -0
- contextsynapse/project/sdlc_schema.py +172 -0
- contextsynapse/project/spec_parser.py +85 -0
- contextsynapse/project/task_lock.py +181 -0
- contextsynapse/project/task_stream.py +203 -0
- contextsynapse/project/team_tools.py +537 -0
- contextsynapse/py.typed +0 -0
- contextsynapse/realtime/__init__.py +6 -0
- contextsynapse/realtime/collaboration.py +147 -0
- contextsynapse/rules/__init__.py +10 -0
- contextsynapse/rules/engine.py +116 -0
- contextsynapse/rules/evaluators/__init__.py +6 -0
- contextsynapse/rules/evaluators/aggregate.py +205 -0
- contextsynapse/rules/evaluators/custom.py +170 -0
- contextsynapse/rules/evaluators/pre_action.py +125 -0
- contextsynapse/rules/evaluators/temporal.py +129 -0
- contextsynapse/rules/loader.py +52 -0
- contextsynapse/rules/models.py +124 -0
- contextsynapse/rules/universal.py +393 -0
- contextsynapse/scheduler.py +229 -0
- contextsynapse/schema/__init__.py +42 -0
- contextsynapse/schema/compiler.py +252 -0
- contextsynapse/schema/composer.py +158 -0
- contextsynapse/schema/dedup.py +73 -0
- contextsynapse/schema/derivation.py +172 -0
- contextsynapse/schema/sdl.py +326 -0
- contextsynapse/schema/validation_gate.py +124 -0
- contextsynapse/sdk/__init__.py +63 -0
- contextsynapse/sdk/agent.py +214 -0
- contextsynapse/sdk/client.py +269 -0
- contextsynapse/sdk/exceptions.py +23 -0
- contextsynapse/sdk/models.py +78 -0
- contextsynapse/sdk/session.py +408 -0
- contextsynapse/sdk/tracked.py +218 -0
- contextsynapse/sdk/worker.py +266 -0
- contextsynapse/sdk/workspace_client.py +98 -0
- contextsynapse/sdk/ws.py +41 -0
- contextsynapse/search/__init__.py +20 -0
- contextsynapse/search/embedding_cache.py +140 -0
- contextsynapse/search/enhanced_search.py +152 -0
- contextsynapse/search/fulltext.py +130 -0
- contextsynapse/search/graph_search.py +634 -0
- contextsynapse/search/lmdb_index.py +1218 -0
- contextsynapse/search/nl_to_aiql.py +199 -0
- contextsynapse/search/rag.py +1346 -0
- contextsynapse/search/rag_cache.py +167 -0
- contextsynapse/search/reasoning_chain.py +231 -0
- contextsynapse/search/redis_search.py +207 -0
- contextsynapse/search/retrieval_quality.py +314 -0
- contextsynapse/search/semantic_query.py +455 -0
- contextsynapse/search/text_resolver.py +159 -0
- contextsynapse/search/whoosh_search.py +373 -0
- contextsynapse/security/__init__.py +17 -0
- contextsynapse/security/audit.py +297 -0
- contextsynapse/security/audit_logger.py +97 -0
- contextsynapse/security/audit_trail.py +270 -0
- contextsynapse/security/auth_unified.py +284 -0
- contextsynapse/security/auto_tagger.py +230 -0
- contextsynapse/security/data_security.py +218 -0
- contextsynapse/security/encryption.py +207 -0
- contextsynapse/security/identity.py +447 -0
- contextsynapse/security/jwt_identity.py +59 -0
- contextsynapse/security/middleware.py +336 -0
- contextsynapse/security/pii.py +233 -0
- contextsynapse/security/rbac.py +96 -0
- contextsynapse/security/rls.py +205 -0
- contextsynapse/security/sanitize.py +233 -0
- contextsynapse/security/scoped_encryption.py +131 -0
- contextsynapse/security/tenant.py +401 -0
- contextsynapse/shield/__init__.py +21 -0
- contextsynapse/shield/anomaly.py +56 -0
- contextsynapse/shield/permissions.py +99 -0
- contextsynapse/shield/profile.py +103 -0
- contextsynapse/shield/shield.py +108 -0
- contextsynapse/shield/trust_engine.py +69 -0
- contextsynapse/skills/__init__.py +14 -0
- contextsynapse/skills/engine.py +233 -0
- contextsynapse/skills/loader.py +59 -0
- contextsynapse/skills/models.py +139 -0
- contextsynapse/storage/__init__.py +7 -0
- contextsynapse/storage/cache.py +208 -0
- contextsynapse/storage/columnar_store_v2.py +178 -0
- contextsynapse/storage/csr_graph_storage.py +587 -0
- contextsynapse/storage/csr_store.py +388 -0
- contextsynapse/storage/document_store.py +491 -0
- contextsynapse/storage/hnsw_index.py +294 -0
- contextsynapse/storage/hybrid_store_v2.py +278 -0
- contextsynapse/storage/lmdb_graph_storage.py +366 -0
- contextsynapse/storage/migration.py +279 -0
- contextsynapse/storage/namespace_store.py +346 -0
- contextsynapse/storage/pure_graph_storage.py +185 -0
- contextsynapse/storage/redis_graph_adapter.py +186 -0
- contextsynapse/storage/redis_graph_storage.py +375 -0
- contextsynapse/storage/router/__init__.py +29 -0
- contextsynapse/storage/router/duckdb_store.py +398 -0
- contextsynapse/storage/router/factory.py +83 -0
- contextsynapse/storage/router/interface.py +125 -0
- contextsynapse/storage/router/postgres_store.py +339 -0
- contextsynapse/storage/router/resolver.py +192 -0
- contextsynapse/storage/router/router.py +300 -0
- contextsynapse/storage/single_file_storage.py +391 -0
- contextsynapse/storage/storage_manager.py +214 -0
- contextsynapse/storage/storage_query_optimizer.py +314 -0
- contextsynapse/storage/wal.py +359 -0
- contextsynapse/temporal/__init__.py +0 -0
- contextsynapse/temporal/storage.py +106 -0
- contextsynapse/tests/__init__.py +11 -0
- contextsynapse/tests/regression/__init__.py +1 -0
- contextsynapse/tests/regression/add_metadata.py +395 -0
- contextsynapse/tests/regression/add_skip_flags.py +85 -0
- contextsynapse/tests/regression/cases/test_basic_create_node.yaml +20 -0
- contextsynapse/tests/regression/cases/test_basic_select.yaml +21 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail_filtered.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_blocks_range.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_get_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_latest_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_length.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_merkle_root.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_create_edge.yaml +28 -0
- contextsynapse/tests/regression/cases/test_delete_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_delete_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_evaluation_mrr.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_ndcg.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_precision.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_recall.yaml +40 -0
- contextsynapse/tests/regression/cases/test_group_by_basic.yaml +56 -0
- contextsynapse/tests/regression/cases/test_match_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_match_node_with_order_limit.yaml +31 -0
- contextsynapse/tests/regression/cases/test_namespace_switch.yaml +18 -0
- contextsynapse/tests/regression/cases/test_pipeline_cascaded.yaml +61 -0
- contextsynapse/tests/regression/cases/test_pipeline_fixed_size_chunking.yaml +48 -0
- contextsynapse/tests/regression/cases/test_pipeline_gpt4_chunking.yaml +54 -0
- contextsynapse/tests/regression/cases/test_pipeline_hybrid_indexing.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_large_embedding.yaml +52 -0
- contextsynapse/tests/regression/cases/test_pipeline_paragraph_chunking.yaml +49 -0
- contextsynapse/tests/regression/cases/test_pipeline_recursive_chunking.yaml +47 -0
- contextsynapse/tests/regression/cases/test_pipeline_run_pipeline.yaml +56 -0
- contextsynapse/tests/regression/cases/test_pipeline_section_based_chunking.yaml +53 -0
- contextsynapse/tests/regression/cases/test_pipeline_semantic_chunking.yaml +51 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_entity_extraction.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_relationships.yaml +62 -0
- contextsynapse/tests/regression/cases/test_rag_evaluation.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_bfs_with_eval.yaml +48 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_dfs_with_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_multi_hop_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_path.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_basic.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_bfs.yaml +52 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_dfs.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_multi_hop.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_shortest_path.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_weighted.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_shortest_path_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_traversal.yaml +30 -0
- contextsynapse/tests/regression/cases/test_rag_graph_weighted_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_search.yaml +33 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_with_prompt_embedding.yaml +44 -0
- contextsynapse/tests/regression/cases/test_rag_keyword_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_multi_hop_graph.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_path_based.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_profile_based.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_vector_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_graph.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_hybrid.yaml +31 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_chunking.yaml +57 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_detection.yaml +33 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_function.yaml +30 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_with_model.yaml +31 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_fixed_size.yaml +44 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_recursive.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_section.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_semantic.yaml +44 -0
- contextsynapse/tests/regression/cases/test_time_travel_as_of.yaml +35 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_commit.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_timestamp.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_for_system_time_all.yaml +37 -0
- contextsynapse/tests/regression/cases/test_time_travel_versions_between.yaml +39 -0
- contextsynapse/tests/regression/cases/test_traverse_basic.yaml +31 -0
- contextsynapse/tests/regression/cases/test_traverse_max_depth.yaml +34 -0
- contextsynapse/tests/regression/cases/test_update_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/evaluation_metrics.py +227 -0
- contextsynapse/tests/regression/regression_runner.py +1081 -0
- contextsynapse/tests/regression/setup_regression_data.py +212 -0
- contextsynapse/tests/regression/test_basic_only.py +84 -0
- contextsynapse/tests/regression/test_namespace_creation.py +29 -0
- contextsynapse/tests/regression/test_single_fix.py +61 -0
- contextsynapse/tests/regression/test_single_query.py +20 -0
- contextsynapse/tests/regression/validate_test_syntax.py +179 -0
- contextsynapse/tests/test_advanced_features.py +347 -0
- contextsynapse/tests/test_aiql_summary.py +283 -0
- contextsynapse/tests/test_all_aiql_queries.py +948 -0
- contextsynapse/tests/test_all_create_queries.py +213 -0
- contextsynapse/tests/test_api_vs_native.py +280 -0
- contextsynapse/tests/test_chunking_dedup.py +199 -0
- contextsynapse/tests/test_connectors.py +171 -0
- contextsynapse/tests/test_edges_and_match.py +202 -0
- contextsynapse/tests/test_extraction_pipeline_integration.py +581 -0
- contextsynapse/tests/test_name_property.py +224 -0
- contextsynapse/tests/test_node_edge_metadata.py +250 -0
- contextsynapse/tests/test_playground_conn.py +114 -0
- contextsynapse/tests/test_query_cache.py +213 -0
- contextsynapse/tests/test_source_policy_auth.py +348 -0
- contextsynapse/tests/test_temporal_and_domain.py +224 -0
- contextsynapse/tests/test_time_travel_e2e.py +571 -0
- contextsynapse/tests/test_traversal_and_aggregation.py +275 -0
- contextsynapse/tools/__init__.py +36 -0
- contextsynapse/tools/a2a_tools.py +106 -0
- contextsynapse/tools/cognition_tools.py +118 -0
- contextsynapse/tools/context.py +905 -0
- contextsynapse/tools/formatting.py +92 -0
- contextsynapse/tools/gateway_tools.py +186 -0
- contextsynapse/tools/graph.py +1700 -0
- contextsynapse/tools/intelligence.py +235 -0
- contextsynapse/tools/memory.py +118 -0
- contextsynapse/tools/registry.py +373 -0
- contextsynapse/tools/shield_tools.py +159 -0
- contextsynapse/tools/tasks.py +341 -0
- contextsynapse/tools/workspace_tools.py +124 -0
- contextsynapse/utils/__init__.py +15 -0
- contextsynapse/utils/config_loader.py +198 -0
- contextsynapse/utils/env_loader.py +156 -0
- contextsynapse/utils/file_utils.py +288 -0
- contextsynapse/utils/logging_optimizer.py +119 -0
- contextsynapse/vector/__init__.py +30 -0
- contextsynapse/vector/chroma_vector_store.py +152 -0
- contextsynapse/vector/custom_vector_store.py +537 -0
- contextsynapse/vector/faiss_vector_store.py +296 -0
- contextsynapse/vector/qdrant_vector_store.py +163 -0
- contextsynapse/vector/vector_db.py +953 -0
- contextsynapse/vector/vector_db_manager.py +197 -0
- contextsynapse/workspace/__init__.py +27 -0
- contextsynapse/workspace/base.py +94 -0
- contextsynapse/workspace/git.py +228 -0
- contextsynapse/workspace/github.py +78 -0
- contextsynapse/workspace/local.py +73 -0
- contextsynapse/workspace/tools.py +222 -0
- contextsynapse-1.0.0.dist-info/METADATA +847 -0
- contextsynapse-1.0.0.dist-info/RECORD +776 -0
- contextsynapse-1.0.0.dist-info/WHEEL +5 -0
- contextsynapse-1.0.0.dist-info/entry_points.txt +4 -0
- contextsynapse-1.0.0.dist-info/licenses/LICENSE +200 -0
- contextsynapse-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Column Reorganizer Post-Processor
|
|
3
|
+
|
|
4
|
+
Fixes interleaved multi-column text by reorganizing it to read complete columns.
|
|
5
|
+
Detects when text alternates between columns (row-by-row) and reorganizes to
|
|
6
|
+
read each column completely (column-by-column).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
import logging
|
|
11
|
+
from typing import List, Tuple, Dict
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ColumnReorganizer:
|
|
17
|
+
"""
|
|
18
|
+
Reorganizes interleaved multi-column text to proper column-by-column reading order.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
"""Initialize the column reorganizer."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def reorganize(self, text: str) -> str:
|
|
26
|
+
"""
|
|
27
|
+
Reorganize text if it appears to be interleaved between columns.
|
|
28
|
+
|
|
29
|
+
Handles two types of interleaving:
|
|
30
|
+
1. Line-by-line: Lines alternate between columns (row-by-row extraction)
|
|
31
|
+
2. Within-line: Single lines contain text from both columns (left-to-right reading)
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
text: Input text that may be interleaved
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Reorganized text with proper column-by-column reading order
|
|
38
|
+
"""
|
|
39
|
+
if not text or len(text.strip()) < 50:
|
|
40
|
+
return text
|
|
41
|
+
|
|
42
|
+
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
|
43
|
+
|
|
44
|
+
if len(lines) < 4:
|
|
45
|
+
# Too few lines to reorganize
|
|
46
|
+
return text
|
|
47
|
+
|
|
48
|
+
# Check for within-line interleaving (lines containing text from both columns)
|
|
49
|
+
# This happens when pdfplumber reads left-to-right across the page
|
|
50
|
+
lines_with_both_columns = self._detect_within_line_interleaving(lines)
|
|
51
|
+
|
|
52
|
+
if lines_with_both_columns:
|
|
53
|
+
logger.info(f"Detected within-line interleaving ({lines_with_both_columns} lines), splitting lines first...")
|
|
54
|
+
# Split lines that contain both columns
|
|
55
|
+
lines = self._split_mixed_column_lines(lines)
|
|
56
|
+
|
|
57
|
+
original_breaks = self._count_mid_breaks(lines)
|
|
58
|
+
|
|
59
|
+
# If there are significant mid-sentence breaks, try reorganizing
|
|
60
|
+
# This catches cases where extraction produced interleaved text
|
|
61
|
+
if original_breaks > len(lines) * 0.1: # More than 10% of lines have mid-breaks
|
|
62
|
+
logger.info(f"Attempting reorganization ({len(lines)} lines, {original_breaks} mid-breaks)...")
|
|
63
|
+
|
|
64
|
+
# Try reorganization
|
|
65
|
+
reorganized = self._reorganize_columns(lines)
|
|
66
|
+
reorganized_lines = reorganized.splitlines()
|
|
67
|
+
reorganized_breaks = self._count_mid_breaks(reorganized_lines)
|
|
68
|
+
|
|
69
|
+
# Use reorganized version if it's better
|
|
70
|
+
if reorganized_breaks < original_breaks:
|
|
71
|
+
improvement = original_breaks - reorganized_breaks
|
|
72
|
+
logger.info(f"Reorganization improved: {original_breaks} -> {reorganized_breaks} mid-sentence breaks (reduced by {improvement})")
|
|
73
|
+
return reorganized
|
|
74
|
+
else:
|
|
75
|
+
logger.debug(f"Reorganization didn't improve ({original_breaks} -> {reorganized_breaks} breaks), keeping original")
|
|
76
|
+
return '\n'.join(lines) # Return split lines even if reorganization didn't help
|
|
77
|
+
else:
|
|
78
|
+
# Few mid-breaks, likely not interleaved
|
|
79
|
+
return '\n'.join(lines)
|
|
80
|
+
|
|
81
|
+
def _detect_within_line_interleaving(self, lines: List[str]) -> int:
|
|
82
|
+
"""
|
|
83
|
+
Detect lines that contain text from both columns.
|
|
84
|
+
|
|
85
|
+
Indicators:
|
|
86
|
+
- Very long lines (>100 chars) with mid-sentence breaks
|
|
87
|
+
- Lines with multiple sentence fragments
|
|
88
|
+
- Lines that don't form coherent sentences
|
|
89
|
+
"""
|
|
90
|
+
count = 0
|
|
91
|
+
for line in lines:
|
|
92
|
+
# Long lines with no sentence-ending punctuation might contain both columns
|
|
93
|
+
if len(line) > 100 and line[-1] not in '.!?;:':
|
|
94
|
+
# Check if line has multiple sentence-like fragments
|
|
95
|
+
# (indicated by capital letters mid-line after lowercase)
|
|
96
|
+
has_fragments = False
|
|
97
|
+
for i in range(1, len(line) - 1):
|
|
98
|
+
if (line[i-1].islower() and line[i] == ' ' and
|
|
99
|
+
line[i+1].isupper() and i > 20): # Capital after space, not at start
|
|
100
|
+
has_fragments = True
|
|
101
|
+
break
|
|
102
|
+
if has_fragments:
|
|
103
|
+
count += 1
|
|
104
|
+
return count
|
|
105
|
+
|
|
106
|
+
def _split_mixed_column_lines(self, lines: List[str]) -> List[str]:
|
|
107
|
+
"""
|
|
108
|
+
Split lines that contain text from both columns.
|
|
109
|
+
|
|
110
|
+
The problem: pdfplumber.extract_text() reads left-to-right, so a single line
|
|
111
|
+
can contain: "left column text" + "right column text"
|
|
112
|
+
|
|
113
|
+
Strategy: Look for patterns indicating column boundaries:
|
|
114
|
+
1. Mid-sentence end (no punctuation) followed by capital letter
|
|
115
|
+
2. Long lines (>100 chars) with multiple sentence fragments
|
|
116
|
+
3. Pattern: "...word " + "Capital word..." (column boundary)
|
|
117
|
+
"""
|
|
118
|
+
split_lines = []
|
|
119
|
+
|
|
120
|
+
for line in lines:
|
|
121
|
+
if len(line) < 60:
|
|
122
|
+
# Short line, likely single column
|
|
123
|
+
split_lines.append(line)
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
# Look for split points
|
|
127
|
+
# Pattern 1: lowercase word, space, capital word (after 30% of line)
|
|
128
|
+
# This suggests: "...left column text " + "Right column text..."
|
|
129
|
+
best_split = None
|
|
130
|
+
best_score = 0
|
|
131
|
+
|
|
132
|
+
for i in range(int(len(line) * 0.3), len(line) - 20):
|
|
133
|
+
# Check for pattern: word boundary with case change
|
|
134
|
+
if i > 0 and i < len(line) - 1:
|
|
135
|
+
char_before = line[i-1] if i > 0 else ' '
|
|
136
|
+
char_at = line[i]
|
|
137
|
+
char_after = line[i+1] if i < len(line) - 1 else ' '
|
|
138
|
+
|
|
139
|
+
# Pattern: space or lowercase, then space, then capital
|
|
140
|
+
if (char_before.islower() and char_at == ' ' and char_after.isupper()):
|
|
141
|
+
before = line[:i].strip()
|
|
142
|
+
after = line[i:].strip()
|
|
143
|
+
|
|
144
|
+
# Score this split point
|
|
145
|
+
score = 0
|
|
146
|
+
|
|
147
|
+
# Good if before doesn't end with punctuation (mid-sentence)
|
|
148
|
+
if before and before[-1] not in '.!?;:':
|
|
149
|
+
score += 2
|
|
150
|
+
|
|
151
|
+
# Good if after starts with capital (new thought)
|
|
152
|
+
if after and after[0].isupper():
|
|
153
|
+
score += 2
|
|
154
|
+
|
|
155
|
+
# Good if both parts are substantial
|
|
156
|
+
if len(before) > 30 and len(after) > 20:
|
|
157
|
+
score += 1
|
|
158
|
+
|
|
159
|
+
# Prefer splits near middle (40-60% of line)
|
|
160
|
+
position_ratio = i / len(line)
|
|
161
|
+
if 0.4 <= position_ratio <= 0.6:
|
|
162
|
+
score += 1
|
|
163
|
+
|
|
164
|
+
if score > best_score:
|
|
165
|
+
best_score = score
|
|
166
|
+
best_split = i
|
|
167
|
+
|
|
168
|
+
if best_split and best_score >= 4: # Require good score
|
|
169
|
+
# Split the line
|
|
170
|
+
part1 = line[:best_split].strip()
|
|
171
|
+
part2 = line[best_split:].strip()
|
|
172
|
+
split_lines.append(part1)
|
|
173
|
+
split_lines.append(part2)
|
|
174
|
+
logger.debug(f"Split line ({len(line)} chars) at position {best_split} (score: {best_score})")
|
|
175
|
+
else:
|
|
176
|
+
split_lines.append(line)
|
|
177
|
+
|
|
178
|
+
return split_lines
|
|
179
|
+
|
|
180
|
+
def _is_interleaved(self, lines: List[str]) -> bool:
|
|
181
|
+
"""
|
|
182
|
+
Detect if text is interleaved between columns (row-by-row).
|
|
183
|
+
|
|
184
|
+
Interleaved pattern:
|
|
185
|
+
- Alternating between columns: col1_row1, col2_row1, col1_row2, col2_row2, ...
|
|
186
|
+
- Many mid-sentence breaks
|
|
187
|
+
- Lines that don't form complete thoughts
|
|
188
|
+
"""
|
|
189
|
+
if len(lines) < 4:
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
# Check for mid-sentence breaks (sentence continues on next line)
|
|
193
|
+
# This is a strong indicator of interleaved columns
|
|
194
|
+
mid_sentence_breaks = 0
|
|
195
|
+
for i in range(len(lines) - 1):
|
|
196
|
+
if (lines[i] and not lines[i][-1] in '.!?;:' and
|
|
197
|
+
len(lines[i]) > 10 and
|
|
198
|
+
lines[i+1] and lines[i+1][0].islower()):
|
|
199
|
+
mid_sentence_breaks += 1
|
|
200
|
+
|
|
201
|
+
mid_break_ratio = mid_sentence_breaks / len(lines) if lines else 0
|
|
202
|
+
|
|
203
|
+
# Check for alternating pattern in even/odd lines
|
|
204
|
+
# In interleaved text, even-indexed lines (col1) and odd-indexed lines (col2)
|
|
205
|
+
# should have similar characteristics
|
|
206
|
+
if len(lines) >= 4:
|
|
207
|
+
even_lines = [lines[i] for i in range(0, len(lines), 2)]
|
|
208
|
+
odd_lines = [lines[i] for i in range(1, len(lines), 2)]
|
|
209
|
+
|
|
210
|
+
# Check if even and odd lines have similar average lengths
|
|
211
|
+
# (both columns should have similar text density)
|
|
212
|
+
if len(even_lines) > 0 and len(odd_lines) > 0:
|
|
213
|
+
even_avg = sum(len(l) for l in even_lines) / len(even_lines)
|
|
214
|
+
odd_avg = sum(len(l) for l in odd_lines) / len(odd_lines)
|
|
215
|
+
|
|
216
|
+
# Similar average lengths suggest interleaving
|
|
217
|
+
length_similarity = abs(even_avg - odd_avg) < 30
|
|
218
|
+
|
|
219
|
+
# Check if both columns have some complete sentences
|
|
220
|
+
even_complete = sum(1 for l in even_lines if l and l[-1] in '.!?;:')
|
|
221
|
+
odd_complete = sum(1 for l in odd_lines if l and l[-1] in '.!?;:')
|
|
222
|
+
|
|
223
|
+
# If lengths are similar and both have sentences, likely interleaved
|
|
224
|
+
if length_similarity and even_complete > 0 and odd_complete > 0:
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
# Interleaved if:
|
|
228
|
+
# 1. High ratio of mid-sentence breaks (>10%) - strong indicator
|
|
229
|
+
# 2. OR both even/odd columns have similar characteristics (suggests interleaving)
|
|
230
|
+
is_interleaved = mid_break_ratio > 0.10
|
|
231
|
+
|
|
232
|
+
# Also check if even/odd pattern makes sense
|
|
233
|
+
if not is_interleaved and len(lines) >= 4:
|
|
234
|
+
even_lines = [lines[i] for i in range(0, len(lines), 2)]
|
|
235
|
+
odd_lines = [lines[i] for i in range(1, len(lines), 2)]
|
|
236
|
+
|
|
237
|
+
if len(even_lines) > 0 and len(odd_lines) > 0:
|
|
238
|
+
even_avg = sum(len(l) for l in even_lines) / len(even_lines)
|
|
239
|
+
odd_avg = sum(len(l) for l in odd_lines) / len(odd_lines)
|
|
240
|
+
|
|
241
|
+
# Similar average lengths + both have sentences = likely interleaved
|
|
242
|
+
if abs(even_avg - odd_avg) < 40:
|
|
243
|
+
even_complete = sum(1 for l in even_lines if l and l[-1] in '.!?;:')
|
|
244
|
+
odd_complete = sum(1 for l in odd_lines if l and l[-1] in '.!?;:')
|
|
245
|
+
if even_complete > 0 and odd_complete > 0:
|
|
246
|
+
is_interleaved = True
|
|
247
|
+
|
|
248
|
+
return is_interleaved
|
|
249
|
+
|
|
250
|
+
def _reorganize_columns(self, lines: List[str]) -> str:
|
|
251
|
+
"""
|
|
252
|
+
Reorganize interleaved lines into proper column-by-column reading order.
|
|
253
|
+
|
|
254
|
+
The problem: Text extracted row-by-row instead of column-by-column.
|
|
255
|
+
Pattern: Line 0 (col1,row1), Line 1 (col2,row1), Line 2 (col1,row2), Line 3 (col2,row2)
|
|
256
|
+
|
|
257
|
+
Solution: Try multiple split strategies and choose the one that produces
|
|
258
|
+
the best reading order (fewest mid-sentence breaks).
|
|
259
|
+
"""
|
|
260
|
+
if len(lines) < 4:
|
|
261
|
+
return '\n'.join(lines)
|
|
262
|
+
|
|
263
|
+
original_breaks = self._count_mid_breaks(lines)
|
|
264
|
+
|
|
265
|
+
# Strategy 1: Even/odd split (most common for row-by-row extraction)
|
|
266
|
+
even_lines = [lines[i] for i in range(0, len(lines), 2)]
|
|
267
|
+
odd_lines = [lines[i] for i in range(1, len(lines), 2)]
|
|
268
|
+
even_odd_breaks = self._count_mid_breaks(even_lines) + self._count_mid_breaks(odd_lines)
|
|
269
|
+
even_odd_score = self._evaluate_split_quality(even_lines, odd_lines)
|
|
270
|
+
|
|
271
|
+
# Strategy 2: Midpoint split
|
|
272
|
+
mid_point = len(lines) // 2
|
|
273
|
+
first_half = lines[:mid_point]
|
|
274
|
+
second_half = lines[mid_point:]
|
|
275
|
+
midpoint_breaks = self._count_mid_breaks(first_half) + self._count_mid_breaks(second_half)
|
|
276
|
+
midpoint_score = self._evaluate_split_quality(first_half, second_half)
|
|
277
|
+
|
|
278
|
+
# Strategy 3: Try different split points based on content
|
|
279
|
+
best_split = None
|
|
280
|
+
best_breaks = original_breaks
|
|
281
|
+
best_score = 0
|
|
282
|
+
|
|
283
|
+
# Try splits at various points (30%, 40%, 50%, 60%, 70%)
|
|
284
|
+
for ratio in [0.3, 0.4, 0.5, 0.6, 0.7]:
|
|
285
|
+
split_point = int(len(lines) * ratio)
|
|
286
|
+
if split_point < 5 or split_point > len(lines) - 5:
|
|
287
|
+
continue
|
|
288
|
+
col1 = lines[:split_point]
|
|
289
|
+
col2 = lines[split_point:]
|
|
290
|
+
total_breaks = self._count_mid_breaks(col1) + self._count_mid_breaks(col2)
|
|
291
|
+
score = self._evaluate_split_quality(col1, col2)
|
|
292
|
+
|
|
293
|
+
if total_breaks < best_breaks or (total_breaks == best_breaks and score > best_score):
|
|
294
|
+
best_split = (col1, col2)
|
|
295
|
+
best_breaks = total_breaks
|
|
296
|
+
best_score = score
|
|
297
|
+
|
|
298
|
+
# Choose best strategy based on:
|
|
299
|
+
# 1. Fewest total mid-breaks
|
|
300
|
+
# 2. Highest quality score
|
|
301
|
+
candidates = [
|
|
302
|
+
(even_lines, odd_lines, even_odd_breaks, even_odd_score, "even/odd"),
|
|
303
|
+
(first_half, second_half, midpoint_breaks, midpoint_score, "midpoint"),
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
if best_split:
|
|
307
|
+
candidates.append((best_split[0], best_split[1], best_breaks, best_score, "content-based"))
|
|
308
|
+
|
|
309
|
+
# Sort by: fewer breaks first, then higher score
|
|
310
|
+
candidates.sort(key=lambda x: (x[2], -x[3]))
|
|
311
|
+
best_col1, best_col2, _, _, method = candidates[0]
|
|
312
|
+
|
|
313
|
+
# Reorganize: column 1 complete, then column 2 complete
|
|
314
|
+
reorganized = best_col1 + best_col2
|
|
315
|
+
|
|
316
|
+
result = '\n'.join(reorganized)
|
|
317
|
+
final_breaks = self._count_mid_breaks(best_col1) + self._count_mid_breaks(best_col2)
|
|
318
|
+
logger.info(f"Reorganized {len(lines)} lines using {method}: {len(best_col1)} in col1, {len(best_col2)} in col2, breaks: {original_breaks} -> {final_breaks}")
|
|
319
|
+
|
|
320
|
+
return result
|
|
321
|
+
"""
|
|
322
|
+
Reorganize interleaved lines into proper column-by-column reading order.
|
|
323
|
+
|
|
324
|
+
The problem: Text is extracted row-by-row instead of column-by-column:
|
|
325
|
+
- Line 1 (col 1, row 1)
|
|
326
|
+
- Line 2 (col 2, row 1)
|
|
327
|
+
- Line 3 (col 1, row 2)
|
|
328
|
+
- Line 4 (col 2, row 2)
|
|
329
|
+
|
|
330
|
+
Should be:
|
|
331
|
+
- All lines from col 1 (complete)
|
|
332
|
+
- All lines from col 2 (complete)
|
|
333
|
+
|
|
334
|
+
Strategy:
|
|
335
|
+
1. Try even/odd split (most common interleaving pattern)
|
|
336
|
+
2. Evaluate which split produces better reading order
|
|
337
|
+
3. Use the best split
|
|
338
|
+
"""
|
|
339
|
+
if len(lines) < 4:
|
|
340
|
+
return '\n'.join(lines)
|
|
341
|
+
|
|
342
|
+
# Method 1: Try even/odd split (assumes perfect alternation)
|
|
343
|
+
even_lines = [lines[i] for i in range(0, len(lines), 2)]
|
|
344
|
+
odd_lines = [lines[i] for i in range(1, len(lines), 2)]
|
|
345
|
+
|
|
346
|
+
# Evaluate even/odd split quality
|
|
347
|
+
even_odd_score = self._evaluate_split_quality(even_lines, odd_lines)
|
|
348
|
+
|
|
349
|
+
# Method 2: Try midpoint split
|
|
350
|
+
mid_point = len(lines) // 2
|
|
351
|
+
first_half = lines[:mid_point]
|
|
352
|
+
second_half = lines[mid_point:]
|
|
353
|
+
midpoint_score = self._evaluate_split_quality(first_half, second_half)
|
|
354
|
+
|
|
355
|
+
# Method 3: Try using column breaks
|
|
356
|
+
column_breaks = self._detect_column_boundaries(lines)
|
|
357
|
+
break_score = -1
|
|
358
|
+
break_split = None
|
|
359
|
+
if column_breaks:
|
|
360
|
+
# Try first significant break
|
|
361
|
+
split_point = column_breaks[0]
|
|
362
|
+
col1 = lines[:split_point]
|
|
363
|
+
col2 = lines[split_point:]
|
|
364
|
+
break_score = self._evaluate_split_quality(col1, col2)
|
|
365
|
+
break_split = (col1, col2)
|
|
366
|
+
|
|
367
|
+
# Choose best split
|
|
368
|
+
best_score = max(even_odd_score, midpoint_score, break_score)
|
|
369
|
+
|
|
370
|
+
if best_score == even_odd_score and even_odd_score > 0:
|
|
371
|
+
column1_lines = even_lines
|
|
372
|
+
column2_lines = odd_lines
|
|
373
|
+
method = "even/odd"
|
|
374
|
+
elif best_score == break_score and break_split:
|
|
375
|
+
column1_lines, column2_lines = break_split
|
|
376
|
+
method = "column break"
|
|
377
|
+
else:
|
|
378
|
+
column1_lines = first_half
|
|
379
|
+
column2_lines = second_half
|
|
380
|
+
method = "midpoint"
|
|
381
|
+
|
|
382
|
+
# Reorganize: column 1 complete, then column 2 complete
|
|
383
|
+
reorganized = column1_lines + column2_lines
|
|
384
|
+
|
|
385
|
+
# Join lines, preserving paragraph structure
|
|
386
|
+
result = '\n'.join(reorganized)
|
|
387
|
+
|
|
388
|
+
logger.info(f"Reorganized {len(lines)} lines using {method}: {len(column1_lines)} in column 1, {len(column2_lines)} in column 2 (score: {best_score:.2f})")
|
|
389
|
+
|
|
390
|
+
return result
|
|
391
|
+
|
|
392
|
+
def _evaluate_split_quality(self, col1_lines: List[str], col2_lines: List[str]) -> float:
|
|
393
|
+
"""
|
|
394
|
+
Evaluate quality of a column split.
|
|
395
|
+
|
|
396
|
+
Higher score = better split (fewer mid-sentence breaks, more complete sentences).
|
|
397
|
+
"""
|
|
398
|
+
if not col1_lines or not col2_lines:
|
|
399
|
+
return 0.0
|
|
400
|
+
|
|
401
|
+
score = 0.0
|
|
402
|
+
|
|
403
|
+
# Check both columns have reasonable length
|
|
404
|
+
col1_avg = sum(len(l) for l in col1_lines) / len(col1_lines)
|
|
405
|
+
col2_avg = sum(len(l) for l in col2_lines) / len(col2_lines)
|
|
406
|
+
|
|
407
|
+
# Similar average lengths is good (both columns have similar content)
|
|
408
|
+
length_diff = abs(col1_avg - col2_avg)
|
|
409
|
+
if length_diff < 30:
|
|
410
|
+
score += 0.3
|
|
411
|
+
elif length_diff < 50:
|
|
412
|
+
score += 0.1
|
|
413
|
+
|
|
414
|
+
# Count complete sentences in each column
|
|
415
|
+
col1_complete = sum(1 for l in col1_lines if l and l[-1] in '.!?;:')
|
|
416
|
+
col2_complete = sum(1 for l in col2_lines if l and l[-1] in '.!?;:')
|
|
417
|
+
|
|
418
|
+
# Both columns should have some complete sentences
|
|
419
|
+
if col1_complete > 0 and col2_complete > 0:
|
|
420
|
+
score += 0.3
|
|
421
|
+
|
|
422
|
+
# Count mid-sentence breaks (fewer is better)
|
|
423
|
+
col1_breaks = self._count_mid_breaks(col1_lines)
|
|
424
|
+
col2_breaks = self._count_mid_breaks(col2_lines)
|
|
425
|
+
|
|
426
|
+
total_breaks = col1_breaks + col2_breaks
|
|
427
|
+
total_lines = len(col1_lines) + len(col2_lines)
|
|
428
|
+
break_ratio = total_breaks / total_lines if total_lines > 0 else 1.0
|
|
429
|
+
|
|
430
|
+
# Lower break ratio is better
|
|
431
|
+
if break_ratio < 0.1:
|
|
432
|
+
score += 0.4
|
|
433
|
+
elif break_ratio < 0.2:
|
|
434
|
+
score += 0.2
|
|
435
|
+
elif break_ratio < 0.3:
|
|
436
|
+
score += 0.1
|
|
437
|
+
|
|
438
|
+
return score
|
|
439
|
+
|
|
440
|
+
def _count_mid_breaks(self, lines: List[str]) -> int:
|
|
441
|
+
"""Count mid-sentence breaks in a list of lines."""
|
|
442
|
+
breaks = 0
|
|
443
|
+
for i in range(len(lines) - 1):
|
|
444
|
+
if (lines[i] and not lines[i][-1] in '.!?;:' and
|
|
445
|
+
len(lines[i]) > 10 and
|
|
446
|
+
lines[i+1] and lines[i+1][0].islower()):
|
|
447
|
+
breaks += 1
|
|
448
|
+
return breaks
|
|
449
|
+
|
|
450
|
+
def _detect_column_boundaries(self, lines: List[str]) -> List[int]:
|
|
451
|
+
"""
|
|
452
|
+
Detect column boundaries in interleaved text.
|
|
453
|
+
|
|
454
|
+
Returns list of line indices where columns change.
|
|
455
|
+
"""
|
|
456
|
+
boundaries = []
|
|
457
|
+
|
|
458
|
+
# Look for patterns that indicate column changes:
|
|
459
|
+
# 1. Short line followed by line starting with capital (new sentence/paragraph)
|
|
460
|
+
# 2. Line ending with punctuation followed by short line
|
|
461
|
+
# 3. Significant change in line length
|
|
462
|
+
|
|
463
|
+
for i in range(len(lines) - 1):
|
|
464
|
+
current = lines[i]
|
|
465
|
+
next_line = lines[i+1]
|
|
466
|
+
|
|
467
|
+
# Pattern 1: Short line + capital start (potential column break)
|
|
468
|
+
if len(current) < 25 and next_line and next_line[0].isupper():
|
|
469
|
+
boundaries.append(i)
|
|
470
|
+
|
|
471
|
+
# Pattern 2: Punctuation end + short line (potential column break)
|
|
472
|
+
elif current and current[-1] in '.!?' and len(next_line) < 25:
|
|
473
|
+
boundaries.append(i)
|
|
474
|
+
|
|
475
|
+
# Pattern 3: Significant length change
|
|
476
|
+
elif abs(len(current) - len(next_line)) > 40:
|
|
477
|
+
boundaries.append(i)
|
|
478
|
+
|
|
479
|
+
return boundaries
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|