docoreai 2.2.0__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {docoreai-2.2.0 → docoreai-2.3.0}/MANIFEST.in +5 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/PKG-INFO +4 -3
- {docoreai-2.2.0 → docoreai-2.3.0}/README.md +1 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/auto_patch.py +12 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/cli.py +46 -19
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/init_engine.py +5 -4
- docoreai-2.3.0/docore_ai/pth_installer.py +68 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/config.py +3 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/telemetry_wp.py +1 -1
- docoreai-2.3.0/docore_ai/train/__init__.py +13 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/auto_retrain_manager.py +4 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/budget_recommendation.py +2 -3
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/daily_pacing_engine.py +2 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/EXTINCT-model_registry.py +3 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/helpers.py +55 -15
- {docoreai-2.2.0 → docoreai-2.3.0}/docoreai.egg-info/SOURCES.txt +0 -2
- {docoreai-2.2.0 → docoreai-2.3.0}/requirements.txt +1 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/setup.py +73 -37
- docoreai-2.2.0/docore_ai/pth_installer.py +0 -117
- docoreai-2.2.0/docore_ai/telemetry/.docoreai_usage.json +0 -10
- docoreai-2.2.0/docore_ai/train/__init__.py +0 -25
- docoreai-2.2.0/docoreai_autopatch.pth +0 -1
- {docoreai-2.2.0 → docoreai-2.3.0}/LICENSE.md +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/api/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/api/main.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/config/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/config/db.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/config/init_db_async.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/fusion_log_server.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/model.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/patch_manager.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/patcher.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/prompt_updates/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/prompt_updates/check_prompt_update.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/prompt_updates/prompt_loader.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/providers/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/providers/bedrock_adapter.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/providers/ollama.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/proxy.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/runtime/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/runtime/settings.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/comparator/base.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/comparator/llama_cpp_comparator.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/core/alert_emitter.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/core/confidence_engine.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/core/derived_gate.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/core/governance_dispatcher.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/core/policy.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/detectors/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/detectors/content_policy.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/detectors/pii_detector.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/export/exporter_map.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/export/sdk_hooks.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/export/sdk_hooks1.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/lineage/fingerprint.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/lineage/lifecycle.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/lineage/tracker.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/semantic/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/semantic/matcher.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/semantic/sketch.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/semantic/thresholds.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/state/cache.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/state/context.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/state/ttl.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/structure/detector.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/structure/heuristics.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/security/types.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/dispatcher.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/safe_sender.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/safe_sender1.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/telemetry_local.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/token_auth.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/token_utils.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/tracker.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/telemetry/usage_limits.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/test_server.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/ab_test_controller.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/agentic_predictor.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/auto_trainer.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/budget_manager.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/cli_integration.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/config.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/data_extraction.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/drift_detector.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/drift_monitor_service.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/evaluation.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/feature_engineering.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/hourly_patterns.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/local_budget_checker.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/monitor.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/performance_tracker.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/phase2_config.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/predict.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/runtime_predictor.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/session_tracker.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/soft_limit_injector.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_fetch_budget_api.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_phase1.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_phase2.1_complete.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_phase2.2_live.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_phase2_mock.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tests/test_quick.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/tokenization_learner.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/train/train_model.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/charts/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/charts/cost_chart.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/charts/daily_spend_chart.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/charts/usage_requests_chart.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/governance_event_log.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/live_tab.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/money_burn_tab.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/phase2_config_tab.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/settings_header.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/text_input.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/toggle.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/components/usage_volume_tab.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/launcher.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/ui/main_window.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/__init__.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/budget_sync.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/csv_logger.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/docoreai_log.csv +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/logger.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/metric_aggregator.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/model_registry_sync.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/run_streamlit_with_shutdown.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/docore_ai/utils/show_app.py +0 -0
- {docoreai-2.2.0 → docoreai-2.3.0}/setup.cfg +0 -0
|
@@ -6,7 +6,11 @@ include setup.py
|
|
|
6
6
|
include MANIFEST.in
|
|
7
7
|
include docore_ai/prompt_updates/data/*.enc
|
|
8
8
|
include docore_ai/prompt_updates/data/*.sig
|
|
9
|
-
|
|
9
|
+
include docore_ai/providers/__init__.py
|
|
10
|
+
include docore_ai/providers/bedrock_adapter.py
|
|
11
|
+
include docore_ai/train/hourly_patterns.py
|
|
12
|
+
include docore_ai/train/session_tracker.py
|
|
13
|
+
include docore_ai/patch_manager.py
|
|
10
14
|
|
|
11
15
|
include docore_ai/telemetry/.docoreai_usage.json
|
|
12
16
|
include docore_ai/utils/docoreai_log.csv
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docoreai
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Self-tuning AI budgets, built privacy-first.
|
|
5
5
|
Home-page: https://docoreai.com
|
|
6
6
|
Author: Saji John Miranda
|
|
@@ -12,7 +12,7 @@ Project-URL: Blog Post, https://mobilights.medium.com/intelligent-prompt-optimiz
|
|
|
12
12
|
Project-URL: Funding, https://docoreai.com/pricing/
|
|
13
13
|
Project-URL: Support, https://docoreai.com/contact-us
|
|
14
14
|
Keywords: llm observability,ai cost control,llm budget management,privacy-first ai,zero prompt storage,ai governance,token tracking,llmops,ai observability,budget pacing,enterprise ai,llm monitoring,prompt monitoring,anthropic,openai,groq,google gemini,ollama,llm cost reduction,ai spending,docoreai
|
|
15
|
-
Classifier: Development Status ::
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: License :: Other/Proprietary License
|
|
@@ -49,6 +49,7 @@ Requires-Dist: packaging>=20.0
|
|
|
49
49
|
Requires-Dist: streamlit
|
|
50
50
|
Requires-Dist: pandas
|
|
51
51
|
Requires-Dist: streamlit-aggrid
|
|
52
|
+
Requires-Dist: charset-normalizer>=3.0.0
|
|
52
53
|
Dynamic: author
|
|
53
54
|
Dynamic: author-email
|
|
54
55
|
Dynamic: classifier
|
|
@@ -72,7 +73,7 @@ Dynamic: summary
|
|
|
72
73
|
|
|
73
74
|
[](https://pypi.org/project/docoreai/)
|
|
74
75
|
[](https://pypi.org/project/docoreai/)
|
|
75
|
-
[](https://pepy.tech/projects/docoreai)
|
|
76
77
|
[](https://creativecommons.org/licenses/by-nc-nd/4.0/)
|
|
77
78
|
[](https://docoreai.com)
|
|
78
79
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
[](https://pypi.org/project/docoreai/)
|
|
9
9
|
[](https://pypi.org/project/docoreai/)
|
|
10
|
-
[](https://pepy.tech/projects/docoreai)
|
|
11
11
|
[](https://creativecommons.org/licenses/by-nc-nd/4.0/)
|
|
12
12
|
[](https://docoreai.com)
|
|
13
13
|
|
|
@@ -65,11 +65,23 @@ from docore_ai.train.local_budget_checker import check_local_budget, get_todays_
|
|
|
65
65
|
# (handles case where client app runs in a separate process from CLI)
|
|
66
66
|
# ------------------------------------------------------------
|
|
67
67
|
if not os.environ.get("DOCOREAI_ENV_PATH"):
|
|
68
|
+
# Try bootstrap file written by docoreai start
|
|
68
69
|
for candidate in [Path.cwd() / ".docoreai_env_path",
|
|
69
70
|
Path.home() / ".docoreai_env_path"]:
|
|
70
71
|
if candidate.exists():
|
|
71
72
|
os.environ["DOCOREAI_ENV_PATH"] = candidate.read_text(encoding="utf-8").strip()
|
|
72
73
|
break
|
|
74
|
+
# Final fallback — install_path.txt always exists after pip install
|
|
75
|
+
# Final fallback — install_path.txt in repo root
|
|
76
|
+
if not os.environ.get("DOCOREAI_ENV_PATH"):
|
|
77
|
+
try:
|
|
78
|
+
import docore_ai
|
|
79
|
+
import sysconfig
|
|
80
|
+
install_path_file = Path(sysconfig.get_paths()["purelib"]) / "docoreai_install_path.txt"
|
|
81
|
+
if install_path_file.exists():
|
|
82
|
+
os.environ["DOCOREAI_ENV_PATH"] = install_path_file.read_text(encoding="utf-8").strip()
|
|
83
|
+
except Exception:
|
|
84
|
+
pass
|
|
73
85
|
# ------------------------------------------------------------
|
|
74
86
|
# ENV bootstrap (UNCHANGED)
|
|
75
87
|
# ------------------------------------------------------------
|
|
@@ -22,7 +22,7 @@ from docore_ai.config.db import TELEMETRY_CONFIG
|
|
|
22
22
|
|
|
23
23
|
from importlib.metadata import version as get_version, PackageNotFoundError
|
|
24
24
|
from docore_ai.pth_installer import install_pth_file, blank_pth_file
|
|
25
|
-
from docore_ai.utils.helpers import
|
|
25
|
+
from docore_ai.utils.helpers import is_port_in_use
|
|
26
26
|
|
|
27
27
|
from pathlib import Path
|
|
28
28
|
#from api.main import app as docoreai_api_app
|
|
@@ -151,18 +151,10 @@ def start():
|
|
|
151
151
|
except Exception as e:
|
|
152
152
|
dprint(f"⚠️ Auto-training check failed: {e}")
|
|
153
153
|
|
|
154
|
-
os.environ["DOCOREAI_ENV_PATH"] =
|
|
155
|
-
dprint("Starting DoCoreAI -
|
|
156
|
-
|
|
157
|
-
# Write it to a small bootstrap file so auto_patch can find it
|
|
158
|
-
env_dir = str(Path.cwd().resolve())
|
|
159
|
-
for target in [Path.cwd().resolve(), Path.home()]:
|
|
160
|
-
try:
|
|
161
|
-
(target / ".docoreai_env_path").write_text(env_dir, encoding="utf-8")
|
|
162
|
-
dprint(f"📌 Bootstrap path written to: {target / '.docoreai_env_path'}")
|
|
163
|
-
except Exception as e:
|
|
164
|
-
dprint(f"⚠️ Could not write bootstrap to {target}: {e}")
|
|
154
|
+
#os.environ["DOCOREAI_ENV_PATH"] = get_docoreai_env_path()
|
|
155
|
+
dprint("Starting DoCoreAI - setting .env path to:", Path.cwd() / ".env")
|
|
165
156
|
|
|
157
|
+
|
|
166
158
|
try:
|
|
167
159
|
|
|
168
160
|
ensure_openai_installed()
|
|
@@ -365,6 +357,7 @@ def start():
|
|
|
365
357
|
stop()
|
|
366
358
|
|
|
367
359
|
|
|
360
|
+
|
|
368
361
|
#CLI Command for Manual Retraining:
|
|
369
362
|
@app.command()
|
|
370
363
|
def retrain_tokens_model():
|
|
@@ -557,8 +550,7 @@ def sync():
|
|
|
557
550
|
typer.secho("❌ Model registry sync failed!", fg=typer.colors.RED,err=True)
|
|
558
551
|
|
|
559
552
|
|
|
560
|
-
|
|
561
|
-
app()
|
|
553
|
+
|
|
562
554
|
|
|
563
555
|
|
|
564
556
|
def ensure_openai_installed(min_version="0.28.1", max_version="2.0.0"):
|
|
@@ -654,11 +646,7 @@ def _reset_learning_window_if_fresh_db():
|
|
|
654
646
|
except Exception:
|
|
655
647
|
pass
|
|
656
648
|
|
|
657
|
-
|
|
658
|
-
if cache_dir.exists():
|
|
659
|
-
for f in cache_dir.iterdir():
|
|
660
|
-
f.unlink()
|
|
661
|
-
dprint("🗑️ Training cache cleared")
|
|
649
|
+
clear_training_cache()
|
|
662
650
|
else:
|
|
663
651
|
dprint(f"📊 Existing data found ({success_count} records) — learning window state preserved.")
|
|
664
652
|
|
|
@@ -826,6 +814,45 @@ def quick_account_check():
|
|
|
826
814
|
dprint(f"❌ Failed to fetch membership info: {str(e)}")
|
|
827
815
|
|
|
828
816
|
|
|
817
|
+
from pathlib import Path
|
|
818
|
+
import shutil
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
def clear_training_cache():
|
|
822
|
+
train_dir = Path(__file__).resolve().parent / "train"
|
|
823
|
+
|
|
824
|
+
for folder_name in ["saved_models", ".cache"]:
|
|
825
|
+
folder = train_dir / folder_name
|
|
826
|
+
|
|
827
|
+
if folder.exists():
|
|
828
|
+
for item in folder.iterdir():
|
|
829
|
+
try:
|
|
830
|
+
if item.is_dir():
|
|
831
|
+
shutil.rmtree(item)
|
|
832
|
+
else:
|
|
833
|
+
item.unlink()
|
|
834
|
+
|
|
835
|
+
dprint(f"🧹 Removed: {item}")
|
|
836
|
+
|
|
837
|
+
except Exception as e:
|
|
838
|
+
dprint(f"⚠️ Could not remove {item}: {e}")
|
|
839
|
+
|
|
840
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir
|
|
841
|
+
data_dir = get_docoreai_data_dir()
|
|
842
|
+
|
|
843
|
+
if data_dir.exists():
|
|
844
|
+
for item in data_dir.iterdir():
|
|
845
|
+
try:
|
|
846
|
+
if item.is_dir():
|
|
847
|
+
shutil.rmtree(item)
|
|
848
|
+
else:
|
|
849
|
+
item.unlink()
|
|
850
|
+
dprint(f"🧹 Removed: {item}")
|
|
851
|
+
except Exception as e:
|
|
852
|
+
dprint(f"⚠️ Could not remove {item}: {e}")
|
|
853
|
+
|
|
854
|
+
if __name__ == "__main__":
|
|
855
|
+
app()
|
|
829
856
|
|
|
830
857
|
#Retention when added to stop: was throwing error messages in Ctrl+c - To DO Later
|
|
831
858
|
# session = requests.Session()
|
|
@@ -56,7 +56,7 @@ def initialize():
|
|
|
56
56
|
#ensure_env_file_exists_and_valid() # Depricated as the new version does not require .env file
|
|
57
57
|
|
|
58
58
|
load_dotenv(dotenv_path=dotenv_path, override=True)
|
|
59
|
-
dprint(f"📂
|
|
59
|
+
dprint(f"📂 Client calling from: {dotenv_path}")
|
|
60
60
|
|
|
61
61
|
_ENGINE_STATE["env_path"] = dotenv_path
|
|
62
62
|
|
|
@@ -136,7 +136,7 @@ def initialize():
|
|
|
136
136
|
resp = session.post(
|
|
137
137
|
f"{TELEMETRY_CONFIG["api_url"]}/wp-json/docoreai/v1/get_member_info?action=true",
|
|
138
138
|
json={"user_id": user_id},
|
|
139
|
-
timeout=
|
|
139
|
+
timeout=5,
|
|
140
140
|
headers=headers
|
|
141
141
|
)
|
|
142
142
|
data = resp.json()
|
|
@@ -158,7 +158,8 @@ def initialize():
|
|
|
158
158
|
except Exception as e:
|
|
159
159
|
dprint(f"⚠️ Prompt update failed: {e}")
|
|
160
160
|
return None
|
|
161
|
-
|
|
161
|
+
|
|
162
|
+
_ENGINE_STATE["initialized"] = True
|
|
162
163
|
# Execute API calls in parallel (but don't wait for all - fail gracefully)
|
|
163
164
|
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
|
|
164
165
|
# First: validate token (required)
|
|
@@ -186,7 +187,7 @@ def initialize():
|
|
|
186
187
|
dprint(f"⚠️ Member info fetch failed: {e}")
|
|
187
188
|
|
|
188
189
|
|
|
189
|
-
_ENGINE_STATE["initialized"] = True
|
|
190
|
+
#_ENGINE_STATE["initialized"] = True # remove this
|
|
190
191
|
dprint("--------------------------------------------------")
|
|
191
192
|
|
|
192
193
|
'''
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
import sysconfig
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from docore_ai.utils.logger import dprint
|
|
8
|
+
|
|
9
|
+
SITE_PACKAGES_PATH = sysconfig.get_paths()["purelib"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def install_pth_file():
|
|
13
|
+
global SITE_PACKAGES_PATH
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
if not SITE_PACKAGES_PATH:
|
|
17
|
+
raise ValueError("SITE_PACKAGES_PATH not set")
|
|
18
|
+
|
|
19
|
+
pth_path = os.path.join(SITE_PACKAGES_PATH, "docoreai_autopatch.pth")
|
|
20
|
+
|
|
21
|
+
# Read the project path baked into install_path.txt during pip install.
|
|
22
|
+
# SITE_PACKAGES_PATH is already known, so read directly from there.
|
|
23
|
+
# Falls back to CWD if the file is missing (e.g. dev/editable installs).
|
|
24
|
+
install_path_file = Path(SITE_PACKAGES_PATH) / "docoreai_install_path.txt"
|
|
25
|
+
if install_path_file.exists():
|
|
26
|
+
install_path = install_path_file.read_text(encoding="utf-8").strip()
|
|
27
|
+
else:
|
|
28
|
+
install_path = str(Path.cwd().resolve())
|
|
29
|
+
dprint("⚠️ install_path.txt not found — falling back to CWD")
|
|
30
|
+
|
|
31
|
+
pth_code = (
|
|
32
|
+
f"import os; os.environ.setdefault('DOCOREAI_ENV_PATH', {repr(install_path)}); "
|
|
33
|
+
f"import docore_ai.auto_patch\n"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
with open(pth_path, "w", encoding="utf-8") as f:
|
|
37
|
+
f.write(pth_code)
|
|
38
|
+
|
|
39
|
+
dprint(f"✅ .pth installed — governance active in client processes from: {install_path}")
|
|
40
|
+
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
dprint(f"❌ [ERROR] Failed to create .pth file: {e}")
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def blank_pth_file():
|
|
49
|
+
global SITE_PACKAGES_PATH
|
|
50
|
+
try:
|
|
51
|
+
if not SITE_PACKAGES_PATH:
|
|
52
|
+
raise ValueError("SITE_PACKAGES_PATH not set")
|
|
53
|
+
|
|
54
|
+
pth_path = os.path.join(SITE_PACKAGES_PATH, "docoreai_autopatch.pth")
|
|
55
|
+
|
|
56
|
+
if os.path.exists(pth_path):
|
|
57
|
+
with open(pth_path, "w", encoding="utf-8") as f:
|
|
58
|
+
f.write("") # Blank out the file instead of deleting
|
|
59
|
+
else:
|
|
60
|
+
dprint("[INFO] No .pth file found to blank out.")
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
subprocess.run([sys.executable, "-c", "print('🔕 dopatch is now disabled')"])
|
|
64
|
+
except subprocess.CalledProcessError:
|
|
65
|
+
pass # Silently ignore if subprocess fails
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
dprint(f"❌ [ERROR] Failed to blank out .pth file: {e}")
|
|
@@ -12,6 +12,8 @@ load_dotenv(dotenv_path=dotenv_path, override=True)
|
|
|
12
12
|
# Configuration variables
|
|
13
13
|
DOCOREAI_API_URL = TELEMETRY_CONFIG["api_url"] #os.getenv("DOCOREAI_API_URL", "https://docoreai.com")
|
|
14
14
|
TELEMETRY_ENABLED = TELEMETRY_CONFIG["enabled"] #os.getenv("DOCOREAI_TELEMETRY", "True").strip().lower() in ("true", "1", "yes")
|
|
15
|
-
|
|
15
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir as _get_data_dir
|
|
16
|
+
TELEMETRY_LOCAL_FILE = os.getenv("DOCOREAI_LOCAL_FILE", str(_get_data_dir() / "telemetry_log.json"))
|
|
17
|
+
|
|
16
18
|
DOCOREAI_TOKEN = TELEMETRY_CONFIG["token"] # Sqlite os.getenv("DOCOREAI_TOKEN", "") # Must be set by user
|
|
17
19
|
ALLOW_SYSTEM_MESSAGE_INJECTION=os.getenv("ALLOW_SYSTEM_MESSAGE_INJECTION")
|
|
@@ -163,7 +163,7 @@ def prepare_telemetry_payload(
|
|
|
163
163
|
usage = _normalize_usage(usage)
|
|
164
164
|
|
|
165
165
|
payload = {
|
|
166
|
-
"user_id": int(user_id),
|
|
166
|
+
"user_id": int(user_id) if user_id is not None else 0,
|
|
167
167
|
"local_timestamp": datetime.now().astimezone().isoformat(),
|
|
168
168
|
"prompt_length": len(user_content),
|
|
169
169
|
"response_length": len(response_content["optimized_response"]) if success and response_content else 0,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Max Tokens Prediction Training Module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .runtime_predictor import (get_global_predictor,
|
|
6
|
+
predict_max_tokens,
|
|
7
|
+
reload_predictor,
|
|
8
|
+
get_predictor_info)
|
|
9
|
+
|
|
10
|
+
from .train_model import ModelTrainer
|
|
11
|
+
from .budget_manager import BudgetManager, get_budget_manager
|
|
12
|
+
|
|
13
|
+
__all__ = [...]
|
|
@@ -13,6 +13,7 @@ Handles:
|
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
15
|
from datetime import datetime, timedelta
|
|
16
|
+
import os
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
import threading
|
|
18
19
|
from docore_ai.config.db import get_phase2_config
|
|
@@ -58,7 +59,9 @@ class AutoRetrainingManager:
|
|
|
58
59
|
'success_only': get_phase2_config('auto_retrain', 'success_only', _c['data']['success_only']),
|
|
59
60
|
},
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir
|
|
63
|
+
self.state_file = get_docoreai_data_dir() / '.docoreai_retrain_state.json'
|
|
64
|
+
|
|
62
65
|
self.state = self._load_state()
|
|
63
66
|
|
|
64
67
|
def _load_state(self):
|
|
@@ -286,9 +286,8 @@ def _get_state_file_path():
|
|
|
286
286
|
except Exception:
|
|
287
287
|
filename = '.docoreai_learning_state.json'
|
|
288
288
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return base / filename
|
|
289
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir
|
|
290
|
+
return get_docoreai_data_dir() / filename
|
|
292
291
|
|
|
293
292
|
|
|
294
293
|
def _load_state():
|
|
@@ -121,7 +121,8 @@ class DailyPacingEngine:
|
|
|
121
121
|
|
|
122
122
|
},
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir
|
|
125
|
+
self.cache_file = get_docoreai_data_dir() / '.docoreai_pacing_cache.json'
|
|
125
126
|
self.patterns = self._load_patterns()
|
|
126
127
|
|
|
127
128
|
def _load_patterns(self):
|
|
@@ -8,7 +8,9 @@ import time
|
|
|
8
8
|
import requests
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
from docore_ai.utils.helpers import get_docoreai_data_dir as _get_data_dir
|
|
12
|
+
CACHE_FILE = _get_data_dir() / ".docoreai_model_prices.json"
|
|
13
|
+
|
|
12
14
|
CACHE_TTL_SECONDS = 300 # 5 minutes
|
|
13
15
|
|
|
14
16
|
DEFAULT_FALLBACK = {
|
|
@@ -28,23 +28,40 @@ import os
|
|
|
28
28
|
|
|
29
29
|
from pathlib import Path
|
|
30
30
|
|
|
31
|
-
def
|
|
31
|
+
def get_docoreai_data_dir() -> Path:
|
|
32
32
|
"""
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
Single home folder for all DoCoreAI runtime JSON files.
|
|
34
|
+
Priority:
|
|
35
|
+
1. DOCOREAI_ENV_PATH env var (container / sysadmin)
|
|
36
|
+
2. install_path.txt baked into package at pip install time
|
|
37
|
+
3. Path.home() as last resort
|
|
35
38
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
# Priority 1 — container or explicit override
|
|
40
|
+
env_path = os.environ.get("DOCOREAI_ENV_PATH")
|
|
41
|
+
if env_path:
|
|
42
|
+
data_dir = Path(env_path) / "docoreai_data"
|
|
43
|
+
data_dir.mkdir(exist_ok=True)
|
|
44
|
+
return data_dir
|
|
45
|
+
|
|
46
|
+
# Priority 2 — install path baked at pip install time
|
|
47
|
+
# Priority 2 — install_path.txt in repo root
|
|
42
48
|
try:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
import docore_ai
|
|
50
|
+
import sysconfig
|
|
51
|
+
#install_path_file = Path(docore_ai.__file__).parent.parent / "install_path.txt"
|
|
52
|
+
install_path_file = Path(sysconfig.get_paths()["purelib"]) / "docoreai_install_path.txt"
|
|
53
|
+
if install_path_file.exists():
|
|
54
|
+
base = Path(install_path_file.read_text(encoding="utf-8").strip())
|
|
55
|
+
data_dir = base / "docoreai_data"
|
|
56
|
+
data_dir.mkdir(exist_ok=True)
|
|
57
|
+
return data_dir
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
# Priority 3 — fallback
|
|
62
|
+
data_dir = Path.home() / "docoreai_data"
|
|
63
|
+
data_dir.mkdir(exist_ok=True)
|
|
64
|
+
return data_dir
|
|
48
65
|
|
|
49
66
|
def get_retry_session(retries=3, backoff_factor=0.5, status_forcelist=(502, 503, 504), session=None):
|
|
50
67
|
session = session or requests.Session()
|
|
@@ -120,4 +137,27 @@ def extract_semantic_role_from_content(content: str) -> str:
|
|
|
120
137
|
return extracted_role
|
|
121
138
|
|
|
122
139
|
#dprint("⚠️ No semantic role found in content, defaulting to 'system'")
|
|
123
|
-
return "Generalist"
|
|
140
|
+
return "Generalist"
|
|
141
|
+
|
|
142
|
+
'''
|
|
143
|
+
#Depricated
|
|
144
|
+
def get_docoreai_env_path():
|
|
145
|
+
"""
|
|
146
|
+
Reads the docoreai_cwd.txt file in the current working directory
|
|
147
|
+
and returns the path to the .env file inside that directory.
|
|
148
|
+
"""
|
|
149
|
+
cwd_file = Path.cwd() / "docoreai_cwd.txt"
|
|
150
|
+
|
|
151
|
+
if not cwd_file.exists():
|
|
152
|
+
print(f"⚠️ {cwd_file} not found.")
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
base_path = Path(cwd_file.read_text(encoding="utf-8").strip()).expanduser().resolve()
|
|
157
|
+
return str(Path(base_path) / ".env")
|
|
158
|
+
except Exception as e:
|
|
159
|
+
print(f"⚠️ Error reading {cwd_file}: {e}")
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
'''
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
LICENSE.md
|
|
2
2
|
MANIFEST.in
|
|
3
3
|
README.md
|
|
4
|
-
docoreai_autopatch.pth
|
|
5
4
|
requirements.txt
|
|
6
5
|
setup.py
|
|
7
6
|
api/__init__.py
|
|
@@ -55,7 +54,6 @@ docore_ai/security/state/context.py
|
|
|
55
54
|
docore_ai/security/state/ttl.py
|
|
56
55
|
docore_ai/security/structure/detector.py
|
|
57
56
|
docore_ai/security/structure/heuristics.py
|
|
58
|
-
docore_ai/telemetry/.docoreai_usage.json
|
|
59
57
|
docore_ai/telemetry/__init__.py
|
|
60
58
|
docore_ai/telemetry/config.py
|
|
61
59
|
docore_ai/telemetry/dispatcher.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import sysconfig
|
|
2
2
|
from setuptools import setup, find_packages
|
|
3
|
-
from setuptools.command.build_py import build_py as build_py_orig
|
|
3
|
+
#from setuptools.command.build_py import build_py as build_py_orig
|
|
4
4
|
import shutil
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import site
|
|
@@ -8,44 +8,81 @@ import sys
|
|
|
8
8
|
import os
|
|
9
9
|
import platform
|
|
10
10
|
|
|
11
|
+
# ---------------------------------------------------------
|
|
12
|
+
# Create install_path.txt in the directory where pip runs
|
|
13
|
+
# ---------------------------------------------------------
|
|
14
|
+
INSTALL_PATH_FILE = "install_path.txt"
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
current_path = os.getcwd()
|
|
18
|
+
install_path_file = os.path.join(current_path, INSTALL_PATH_FILE)
|
|
19
|
+
|
|
20
|
+
with open(install_path_file, "w", encoding="utf-8") as f:
|
|
21
|
+
f.write(current_path)
|
|
22
|
+
|
|
23
|
+
print(f"Created {install_path_file}")
|
|
24
|
+
print(f"Install path: {current_path}")
|
|
25
|
+
|
|
26
|
+
except Exception as e:
|
|
27
|
+
print(f"WARNING: Could not create {INSTALL_PATH_FILE}: {e}")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------
|
|
31
|
+
# Create site_path.txt with the Python site-packages path
|
|
32
|
+
# ---------------------------------------------------------
|
|
33
|
+
SITE_PATH_FILE = "site_path.txt"
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
site_packages_path = sysconfig.get_paths()["purelib"]
|
|
37
|
+
current_path = os.getcwd()
|
|
38
|
+
site_path_file = os.path.join(current_path, SITE_PATH_FILE)
|
|
39
|
+
|
|
40
|
+
with open(site_path_file, "w", encoding="utf-8") as f:
|
|
41
|
+
f.write(site_packages_path)
|
|
42
|
+
|
|
43
|
+
print(f"Created {site_path_file}")
|
|
44
|
+
print(f"Site-packages path: {site_packages_path}")
|
|
45
|
+
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print(f"WARNING: Could not create {SITE_PATH_FILE}: {e}")
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------
|
|
50
|
+
# Create docoreai_autopatch.pth in site-packages
|
|
51
|
+
# ---------------------------------------------------------
|
|
11
52
|
PTH_FILE = "docoreai_autopatch.pth"
|
|
53
|
+
#INSTALL_PATH_FILE = "docoreai_install_path.txt"
|
|
12
54
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
cwd_path = os.getcwd()
|
|
37
|
-
with open("docoreai_cwd.txt", "w", encoding="utf-8") as f:
|
|
38
|
-
f.write(cwd_path)
|
|
39
|
-
print(f"docoreai_cwd.txt written to install path: {cwd_path}")
|
|
40
|
-
except Exception as e:
|
|
41
|
-
print(f"Failed to write docoreai_cwd.txt: {e}")
|
|
55
|
+
# try:
|
|
56
|
+
# site_packages_path = sysconfig.get_paths()["purelib"]
|
|
57
|
+
|
|
58
|
+
# # Create and copy .pth file
|
|
59
|
+
# if not os.path.exists(PTH_FILE):
|
|
60
|
+
# print(f"Creating source pth {PTH_FILE}")
|
|
61
|
+
# with open(PTH_FILE, "w", encoding="utf-8") as f:
|
|
62
|
+
# f.write("")
|
|
63
|
+
# shutil.copy2(PTH_FILE, os.path.join(site_packages_path, PTH_FILE))
|
|
64
|
+
|
|
65
|
+
# # Create and copy install path file
|
|
66
|
+
# if not os.path.exists(INSTALL_PATH_FILE):
|
|
67
|
+
# print(f"Creating Install Path File {INSTALL_PATH_FILE}")
|
|
68
|
+
# with open(INSTALL_PATH_FILE, "w", encoding="utf-8") as f:
|
|
69
|
+
# f.write(os.getcwd())
|
|
70
|
+
# shutil.copy2(INSTALL_PATH_FILE, os.path.join(site_packages_path, INSTALL_PATH_FILE))
|
|
71
|
+
|
|
72
|
+
# print(f"SUCCESS: Created files in {site_packages_path}")
|
|
73
|
+
|
|
74
|
+
# except Exception as e:
|
|
75
|
+
# print(f"ERROR: {e}")
|
|
76
|
+
|
|
42
77
|
|
|
43
78
|
with open("README.md", "r", encoding="utf-8") as fh:
|
|
44
79
|
long_description = fh.read()
|
|
45
|
-
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
46
83
|
setup(
|
|
47
84
|
name="docoreai",
|
|
48
|
-
version="2.
|
|
85
|
+
version="2.3.0",
|
|
49
86
|
author="Saji John Miranda",
|
|
50
87
|
author_email="saji.john@docoreai.com",
|
|
51
88
|
license="CC BY-NC-ND 4.0",
|
|
@@ -53,7 +90,7 @@ setup(
|
|
|
53
90
|
include=["docore_ai", "docore_ai.*", "api", "api.*"],
|
|
54
91
|
exclude=["docore_ai.Tests", "docore_ai.Tests.*"],
|
|
55
92
|
),
|
|
56
|
-
|
|
93
|
+
|
|
57
94
|
package_data={
|
|
58
95
|
"": ["LICENSE.md"],
|
|
59
96
|
"docore_ai.prompt_updates": ["data/*.enc", "data/*.sig"], # Include encrypted prompt files
|
|
@@ -95,10 +132,11 @@ description="Self-tuning AI budgets, built privacy-first.",
|
|
|
95
132
|
"streamlit",
|
|
96
133
|
"pandas",
|
|
97
134
|
"streamlit-aggrid",
|
|
135
|
+
"charset-normalizer>=3.0.0",
|
|
98
136
|
],
|
|
99
137
|
classifiers=[
|
|
100
|
-
# Development stage
|
|
101
|
-
"Development Status ::
|
|
138
|
+
# Development stage
|
|
139
|
+
"Development Status :: 4 - Beta",
|
|
102
140
|
|
|
103
141
|
|
|
104
142
|
# Python versions actually supported
|
|
@@ -138,6 +176,4 @@ description="Self-tuning AI budgets, built privacy-first.",
|
|
|
138
176
|
},
|
|
139
177
|
include_package_data=True,
|
|
140
178
|
zip_safe=False,
|
|
141
|
-
data_files=[(sysconfig.get_paths()["purelib"], [PTH_FILE])], #31-Jul helps remove pth file in pip uninstall
|
|
142
|
-
|
|
143
179
|
)
|