compair-core 0.3.15__tar.gz → 0.4.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.
Potentially problematic release.
This version of compair-core might be problematic. Click here for more details.
- {compair_core-0.3.15 → compair_core-0.4.0}/PKG-INFO +6 -3
- {compair_core-0.3.15 → compair_core-0.4.0}/README.md +5 -2
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/api.py +7 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/__init__.py +35 -10
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/feedback.py +43 -1
- compair_core-0.4.0/compair_core/server/local_model/ocr.py +44 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/routers/capabilities.py +4 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core.egg-info/PKG-INFO +6 -3
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core.egg-info/SOURCES.txt +1 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/pyproject.toml +1 -1
- {compair_core-0.3.15 → compair_core-0.4.0}/LICENSE +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/celery_app.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/default_groups.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/embeddings.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/logger.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/main.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/models.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/schema.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/tasks.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair/utils.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair_email/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair_email/email.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair_email/email_core.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair_email/templates.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/compair_email/templates_core.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/app.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/deps.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/local_model/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/local_model/app.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/console_mailer.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/contracts.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/local_storage.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/noop_analytics.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/noop_billing.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/providers/noop_ocr.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/routers/__init__.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core/server/settings.py +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core.egg-info/dependency_links.txt +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core.egg-info/requires.txt +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/compair_core.egg-info/top_level.txt +0 -0
- {compair_core-0.3.15 → compair_core-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compair-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Open-source foundation of the Compair collaboration platform.
|
|
5
5
|
Author: RocketResearch, Inc.
|
|
6
6
|
License: MIT
|
|
@@ -86,7 +86,8 @@ Container definitions and build pipelines live outside this public package:
|
|
|
86
86
|
Key environment variables for the core edition:
|
|
87
87
|
|
|
88
88
|
- `COMPAIR_EDITION` (`core`) – corresponds to this core local implementation.
|
|
89
|
-
- `
|
|
89
|
+
- `COMPAIR_DATABASE_URL` – optional explicit SQLAlchemy URL (e.g. `postgresql+psycopg2://user:pass@host/db`). When omitted, Compair falls back to a local SQLite file.
|
|
90
|
+
- `COMPAIR_DB_DIR` / `COMPAIR_DB_NAME` – directory and filename for the bundled SQLite database (default: `~/.compair-core/data/compair.db`). Legacy `COMPAIR_SQLITE_*` variables remain supported.
|
|
90
91
|
- `COMPAIR_LOCAL_MODEL_URL` – endpoint for your local embeddings/feedback service (defaults to `http://local-model:9000`).
|
|
91
92
|
- `COMPAIR_EMAIL_BACKEND` – the core mailer logs emails to stdout; cloud overrides this with transactional delivery.
|
|
92
93
|
- `COMPAIR_REQUIRE_AUTHENTICATION` (`true`) – set to `false` to run the API in single-user mode without login or account management. When disabled, Compair auto-provisions a local user, group, and long-lived session token so you can upload documents immediately.
|
|
@@ -94,8 +95,10 @@ Key environment variables for the core edition:
|
|
|
94
95
|
- `COMPAIR_INCLUDE_LEGACY_ROUTES` (`false`) – opt-in to the full legacy API surface (used by the hosted product) when running the core edition. Leave unset to expose only the streamlined single-user endpoints in Swagger.
|
|
95
96
|
- `COMPAIR_EMBEDDING_DIM` – force the embedding vector size stored in the database (defaults to 384 for core, 1536 for cloud). Keep this in sync with whichever embedding model you configure.
|
|
96
97
|
- `COMPAIR_VECTOR_BACKEND` (`auto`) – set to `pgvector` when running against PostgreSQL with the pgvector extension, or `json` to store embeddings as JSON (the default for SQLite deployments).
|
|
97
|
-
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), or `fallback` (skip generation and surface similar references only).
|
|
98
|
+
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), `http` (POST the request to a custom endpoint), or `fallback` (skip generation and surface similar references only).
|
|
98
99
|
- `COMPAIR_OPENAI_API_KEY` / `COMPAIR_OPENAI_MODEL` – when using the OpenAI provider, supply your API key and optional model name (defaults to `gpt-4o-mini`). The fallback kicks in automatically if the key or SDK is unavailable.
|
|
100
|
+
- `COMPAIR_GENERATION_ENDPOINT` – HTTP endpoint invoked when `COMPAIR_GENERATION_PROVIDER=http`; the service receives a JSON payload (`document`, `references`, `length_instruction`) and should return `{"feedback": ...}`.
|
|
101
|
+
- `COMPAIR_OCR_ENDPOINT` – endpoint the backend calls for OCR uploads (defaults to the bundled Tesseract wrapper at `http://local-ocr:9001/ocr-file`). Provide your own service by overriding this URL.
|
|
99
102
|
|
|
100
103
|
See `compair_core/server/settings.py` for the full settings surface.
|
|
101
104
|
|
|
@@ -51,7 +51,8 @@ Container definitions and build pipelines live outside this public package:
|
|
|
51
51
|
Key environment variables for the core edition:
|
|
52
52
|
|
|
53
53
|
- `COMPAIR_EDITION` (`core`) – corresponds to this core local implementation.
|
|
54
|
-
- `
|
|
54
|
+
- `COMPAIR_DATABASE_URL` – optional explicit SQLAlchemy URL (e.g. `postgresql+psycopg2://user:pass@host/db`). When omitted, Compair falls back to a local SQLite file.
|
|
55
|
+
- `COMPAIR_DB_DIR` / `COMPAIR_DB_NAME` – directory and filename for the bundled SQLite database (default: `~/.compair-core/data/compair.db`). Legacy `COMPAIR_SQLITE_*` variables remain supported.
|
|
55
56
|
- `COMPAIR_LOCAL_MODEL_URL` – endpoint for your local embeddings/feedback service (defaults to `http://local-model:9000`).
|
|
56
57
|
- `COMPAIR_EMAIL_BACKEND` – the core mailer logs emails to stdout; cloud overrides this with transactional delivery.
|
|
57
58
|
- `COMPAIR_REQUIRE_AUTHENTICATION` (`true`) – set to `false` to run the API in single-user mode without login or account management. When disabled, Compair auto-provisions a local user, group, and long-lived session token so you can upload documents immediately.
|
|
@@ -59,8 +60,10 @@ Key environment variables for the core edition:
|
|
|
59
60
|
- `COMPAIR_INCLUDE_LEGACY_ROUTES` (`false`) – opt-in to the full legacy API surface (used by the hosted product) when running the core edition. Leave unset to expose only the streamlined single-user endpoints in Swagger.
|
|
60
61
|
- `COMPAIR_EMBEDDING_DIM` – force the embedding vector size stored in the database (defaults to 384 for core, 1536 for cloud). Keep this in sync with whichever embedding model you configure.
|
|
61
62
|
- `COMPAIR_VECTOR_BACKEND` (`auto`) – set to `pgvector` when running against PostgreSQL with the pgvector extension, or `json` to store embeddings as JSON (the default for SQLite deployments).
|
|
62
|
-
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), or `fallback` (skip generation and surface similar references only).
|
|
63
|
+
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), `http` (POST the request to a custom endpoint), or `fallback` (skip generation and surface similar references only).
|
|
63
64
|
- `COMPAIR_OPENAI_API_KEY` / `COMPAIR_OPENAI_MODEL` – when using the OpenAI provider, supply your API key and optional model name (defaults to `gpt-4o-mini`). The fallback kicks in automatically if the key or SDK is unavailable.
|
|
65
|
+
- `COMPAIR_GENERATION_ENDPOINT` – HTTP endpoint invoked when `COMPAIR_GENERATION_PROVIDER=http`; the service receives a JSON payload (`document`, `references`, `length_instruction`) and should return `{"feedback": ...}`.
|
|
66
|
+
- `COMPAIR_OCR_ENDPOINT` – endpoint the backend calls for OCR uploads (defaults to the bundled Tesseract wrapper at `http://local-ocr:9001/ocr-file`). Provide your own service by overriding this URL.
|
|
64
67
|
|
|
65
68
|
See `compair_core/server/settings.py` for the full settings surface.
|
|
66
69
|
|
|
@@ -2370,6 +2370,8 @@ def get_activity_feed(
|
|
|
2370
2370
|
):
|
|
2371
2371
|
"""Retrieve recent activities for a user's groups."""
|
|
2372
2372
|
require_feature(HAS_ACTIVITY, "Activity feed")
|
|
2373
|
+
if not IS_CLOUD:
|
|
2374
|
+
raise HTTPException(status_code=501, detail="Activity feed is only available in the Compair Cloud edition.")
|
|
2373
2375
|
with compair.Session() as session:
|
|
2374
2376
|
# Get user's groups
|
|
2375
2377
|
|
|
@@ -3514,7 +3516,11 @@ CORE_PATHS: set[str] = {
|
|
|
3514
3516
|
"/load_documents",
|
|
3515
3517
|
"/load_document",
|
|
3516
3518
|
"/load_document_by_id",
|
|
3519
|
+
"/load_user_files",
|
|
3517
3520
|
"/create_doc",
|
|
3521
|
+
"/update_doc",
|
|
3522
|
+
"/delete_doc",
|
|
3523
|
+
"/delete_docs",
|
|
3518
3524
|
"/process_doc",
|
|
3519
3525
|
"/status/{task_id}",
|
|
3520
3526
|
"/upload/ocr-file",
|
|
@@ -3523,6 +3529,7 @@ CORE_PATHS: set[str] = {
|
|
|
3523
3529
|
"/load_references",
|
|
3524
3530
|
"/load_feedback",
|
|
3525
3531
|
"/documents/{document_id}/feedback",
|
|
3532
|
+
"/get_activity_feed",
|
|
3526
3533
|
}
|
|
3527
3534
|
|
|
3528
3535
|
for route in router.routes:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from sqlalchemy import Engine, create_engine
|
|
5
6
|
from sqlalchemy.orm import sessionmaker
|
|
6
7
|
|
|
@@ -37,27 +38,51 @@ if edition == "cloud":
|
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
def _handle_engine() -> Engine:
|
|
41
|
+
# Preferred configuration: explicit database URL
|
|
42
|
+
explicit_url = (
|
|
43
|
+
os.getenv("COMPAIR_DATABASE_URL")
|
|
44
|
+
or os.getenv("COMPAIR_DB_URL")
|
|
45
|
+
or os.getenv("DATABASE_URL")
|
|
46
|
+
)
|
|
47
|
+
if explicit_url:
|
|
48
|
+
if explicit_url.startswith("sqlite:"):
|
|
49
|
+
return create_engine(explicit_url, connect_args={"check_same_thread": False})
|
|
50
|
+
return create_engine(explicit_url)
|
|
51
|
+
|
|
52
|
+
# Backwards compatibility with legacy Postgres env variables
|
|
40
53
|
db = os.getenv("DB")
|
|
41
54
|
db_user = os.getenv("DB_USER")
|
|
42
55
|
db_passw = os.getenv("DB_PASSW")
|
|
43
|
-
|
|
56
|
+
db_host = os.getenv("DB_URL")
|
|
44
57
|
|
|
45
|
-
if all([db, db_user, db_passw,
|
|
58
|
+
if all([db, db_user, db_passw, db_host]):
|
|
46
59
|
return create_engine(
|
|
47
|
-
f"postgresql+psycopg2://{db_user}:{db_passw}@{
|
|
60
|
+
f"postgresql+psycopg2://{db_user}:{db_passw}@{db_host}/{db}",
|
|
48
61
|
pool_size=10,
|
|
49
62
|
max_overflow=0,
|
|
50
63
|
)
|
|
51
64
|
|
|
52
|
-
|
|
65
|
+
# Local default: place an SQLite database inside COMPAIR_DB_DIR
|
|
66
|
+
db_dir = (
|
|
67
|
+
os.getenv("COMPAIR_DB_DIR")
|
|
68
|
+
or os.getenv("COMPAIR_SQLITE_DIR")
|
|
69
|
+
or os.path.join(Path.home(), ".compair-core", "data")
|
|
70
|
+
)
|
|
71
|
+
db_name = os.getenv("COMPAIR_DB_NAME") or os.getenv("COMPAIR_SQLITE_NAME") or "compair.db"
|
|
72
|
+
|
|
73
|
+
db_path = Path(db_dir).expanduser()
|
|
53
74
|
try:
|
|
54
|
-
|
|
75
|
+
db_path.mkdir(parents=True, exist_ok=True)
|
|
55
76
|
except OSError:
|
|
56
|
-
fallback_dir =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
77
|
+
fallback_dir = Path(os.getcwd()) / "compair_data"
|
|
78
|
+
fallback_dir.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
db_path = fallback_dir
|
|
80
|
+
|
|
81
|
+
sqlite_path = db_path / db_name
|
|
82
|
+
return create_engine(
|
|
83
|
+
f"sqlite:///{sqlite_path}",
|
|
84
|
+
connect_args={"check_same_thread": False},
|
|
85
|
+
)
|
|
61
86
|
|
|
62
87
|
|
|
63
88
|
def initialize_database() -> None:
|
|
@@ -35,7 +35,8 @@ class Reviewer:
|
|
|
35
35
|
|
|
36
36
|
self._cloud_impl = None
|
|
37
37
|
self._openai_client = None
|
|
38
|
-
self.openai_model = os.getenv("COMPAIR_OPENAI_MODEL", "gpt-
|
|
38
|
+
self.openai_model = os.getenv("COMPAIR_OPENAI_MODEL", "gpt-5-nano")
|
|
39
|
+
self.custom_endpoint = os.getenv("COMPAIR_GENERATION_ENDPOINT")
|
|
39
40
|
|
|
40
41
|
if self.edition == "cloud" and CloudReviewer is not None:
|
|
41
42
|
self._cloud_impl = CloudReviewer()
|
|
@@ -55,6 +56,9 @@ class Reviewer:
|
|
|
55
56
|
if self._openai_client is None and not hasattr(openai, "ChatCompletion"):
|
|
56
57
|
log_event("openai_feedback_unavailable", reason="openai_library_missing")
|
|
57
58
|
self.provider = "fallback"
|
|
59
|
+
if self.provider == "http" and not self.custom_endpoint:
|
|
60
|
+
log_event("custom_feedback_unavailable", reason="missing_endpoint")
|
|
61
|
+
self.provider = "fallback"
|
|
58
62
|
if self.provider == "local":
|
|
59
63
|
self.model = os.getenv("COMPAIR_LOCAL_GENERATION_MODEL", "local-feedback")
|
|
60
64
|
base_url = os.getenv("COMPAIR_LOCAL_MODEL_URL", "http://local-model:9000")
|
|
@@ -63,6 +67,9 @@ class Reviewer:
|
|
|
63
67
|
else:
|
|
64
68
|
self.model = "external"
|
|
65
69
|
self.endpoint = None
|
|
70
|
+
if self.provider not in {"local", "openai", "http", "fallback"}:
|
|
71
|
+
log_event("feedback_provider_unknown", provider=self.provider)
|
|
72
|
+
self.provider = "fallback"
|
|
66
73
|
|
|
67
74
|
@property
|
|
68
75
|
def is_cloud(self) -> bool:
|
|
@@ -181,6 +188,36 @@ def _local_feedback(
|
|
|
181
188
|
return None
|
|
182
189
|
|
|
183
190
|
|
|
191
|
+
def _http_feedback(
|
|
192
|
+
reviewer: Reviewer,
|
|
193
|
+
text: str,
|
|
194
|
+
references: list[Any],
|
|
195
|
+
user: User,
|
|
196
|
+
) -> str | None:
|
|
197
|
+
if not reviewer.custom_endpoint:
|
|
198
|
+
return None
|
|
199
|
+
payload = {
|
|
200
|
+
"document": text,
|
|
201
|
+
"references": [getattr(ref, "content", "") for ref in references],
|
|
202
|
+
"length_instruction": reviewer.length_map.get(
|
|
203
|
+
user.preferred_feedback_length,
|
|
204
|
+
"1–2 short sentences",
|
|
205
|
+
),
|
|
206
|
+
}
|
|
207
|
+
try:
|
|
208
|
+
response = requests.post(reviewer.custom_endpoint, json=payload, timeout=30)
|
|
209
|
+
response.raise_for_status()
|
|
210
|
+
data = response.json()
|
|
211
|
+
feedback = data.get("feedback") or data.get("text")
|
|
212
|
+
if isinstance(feedback, str):
|
|
213
|
+
feedback = feedback.strip()
|
|
214
|
+
if feedback:
|
|
215
|
+
return feedback
|
|
216
|
+
except Exception as exc: # pragma: no cover - network failures stay graceful
|
|
217
|
+
log_event("custom_feedback_failed", error=str(exc))
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
|
|
184
221
|
def get_feedback(
|
|
185
222
|
reviewer: Reviewer,
|
|
186
223
|
doc: Document,
|
|
@@ -196,6 +233,11 @@ def get_feedback(
|
|
|
196
233
|
if feedback:
|
|
197
234
|
return feedback
|
|
198
235
|
|
|
236
|
+
if reviewer.provider == "http":
|
|
237
|
+
feedback = _http_feedback(reviewer, text, references, user)
|
|
238
|
+
if feedback:
|
|
239
|
+
return feedback
|
|
240
|
+
|
|
199
241
|
if reviewer.provider == "local" and getattr(reviewer, "endpoint", None):
|
|
200
242
|
feedback = _local_feedback(reviewer, text, references, user)
|
|
201
243
|
if feedback:
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Minimal OCR endpoint leveraging pytesseract when available."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import io
|
|
5
|
+
import os
|
|
6
|
+
from typing import Any, Dict
|
|
7
|
+
|
|
8
|
+
from fastapi import FastAPI, File, HTTPException, UploadFile
|
|
9
|
+
|
|
10
|
+
app = FastAPI(title="Compair Local OCR", version="0.1.0")
|
|
11
|
+
|
|
12
|
+
try: # Optional dependency
|
|
13
|
+
import pytesseract # type: ignore
|
|
14
|
+
from PIL import Image # type: ignore
|
|
15
|
+
except ImportError: # pragma: no cover - optional
|
|
16
|
+
pytesseract = None # type: ignore
|
|
17
|
+
Image = None # type: ignore
|
|
18
|
+
|
|
19
|
+
_OCR_FALLBACK = os.getenv("COMPAIR_LOCAL_OCR_FALLBACK", "text") # text | none
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _extract_text(data: bytes) -> str:
|
|
23
|
+
if pytesseract is None or Image is None:
|
|
24
|
+
if _OCR_FALLBACK == "text":
|
|
25
|
+
try:
|
|
26
|
+
return data.decode("utf-8")
|
|
27
|
+
except UnicodeDecodeError:
|
|
28
|
+
return data.decode("latin-1", errors="ignore")
|
|
29
|
+
return ""
|
|
30
|
+
try:
|
|
31
|
+
image = Image.open(io.BytesIO(data))
|
|
32
|
+
return pytesseract.image_to_string(image)
|
|
33
|
+
except Exception:
|
|
34
|
+
return ""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@app.post("/ocr-file")
|
|
38
|
+
async def ocr_file(file: UploadFile = File(...)) -> Dict[str, Any]:
|
|
39
|
+
payload = await file.read()
|
|
40
|
+
text = _extract_text(payload)
|
|
41
|
+
if not text:
|
|
42
|
+
raise HTTPException(status_code=501, detail="OCR not available or failed to extract text.")
|
|
43
|
+
return {"extracted_text": text}
|
|
44
|
+
|
|
@@ -36,6 +36,10 @@ def capabilities(settings: Settings = Depends(get_settings)) -> dict[str, object
|
|
|
36
36
|
"docs": None if edition == "core" else 100,
|
|
37
37
|
"feedback_per_day": None if edition == "core" else 50,
|
|
38
38
|
},
|
|
39
|
+
"features": {
|
|
40
|
+
"ocr_upload": settings.ocr_enabled,
|
|
41
|
+
"activity_feed": edition == "cloud",
|
|
42
|
+
},
|
|
39
43
|
"server": "Compair Cloud" if edition == "cloud" else "Compair Core",
|
|
40
44
|
"version": settings.version,
|
|
41
45
|
"legacy_routes": settings.include_legacy_routes,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compair-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Open-source foundation of the Compair collaboration platform.
|
|
5
5
|
Author: RocketResearch, Inc.
|
|
6
6
|
License: MIT
|
|
@@ -86,7 +86,8 @@ Container definitions and build pipelines live outside this public package:
|
|
|
86
86
|
Key environment variables for the core edition:
|
|
87
87
|
|
|
88
88
|
- `COMPAIR_EDITION` (`core`) – corresponds to this core local implementation.
|
|
89
|
-
- `
|
|
89
|
+
- `COMPAIR_DATABASE_URL` – optional explicit SQLAlchemy URL (e.g. `postgresql+psycopg2://user:pass@host/db`). When omitted, Compair falls back to a local SQLite file.
|
|
90
|
+
- `COMPAIR_DB_DIR` / `COMPAIR_DB_NAME` – directory and filename for the bundled SQLite database (default: `~/.compair-core/data/compair.db`). Legacy `COMPAIR_SQLITE_*` variables remain supported.
|
|
90
91
|
- `COMPAIR_LOCAL_MODEL_URL` – endpoint for your local embeddings/feedback service (defaults to `http://local-model:9000`).
|
|
91
92
|
- `COMPAIR_EMAIL_BACKEND` – the core mailer logs emails to stdout; cloud overrides this with transactional delivery.
|
|
92
93
|
- `COMPAIR_REQUIRE_AUTHENTICATION` (`true`) – set to `false` to run the API in single-user mode without login or account management. When disabled, Compair auto-provisions a local user, group, and long-lived session token so you can upload documents immediately.
|
|
@@ -94,8 +95,10 @@ Key environment variables for the core edition:
|
|
|
94
95
|
- `COMPAIR_INCLUDE_LEGACY_ROUTES` (`false`) – opt-in to the full legacy API surface (used by the hosted product) when running the core edition. Leave unset to expose only the streamlined single-user endpoints in Swagger.
|
|
95
96
|
- `COMPAIR_EMBEDDING_DIM` – force the embedding vector size stored in the database (defaults to 384 for core, 1536 for cloud). Keep this in sync with whichever embedding model you configure.
|
|
96
97
|
- `COMPAIR_VECTOR_BACKEND` (`auto`) – set to `pgvector` when running against PostgreSQL with the pgvector extension, or `json` to store embeddings as JSON (the default for SQLite deployments).
|
|
97
|
-
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), or `fallback` (skip generation and surface similar references only).
|
|
98
|
+
- `COMPAIR_GENERATION_PROVIDER` (`local`) – choose how feedback is produced. Options: `local` (call the bundled FastAPI service), `openai` (use ChatGPT-compatible APIs with an API key), `http` (POST the request to a custom endpoint), or `fallback` (skip generation and surface similar references only).
|
|
98
99
|
- `COMPAIR_OPENAI_API_KEY` / `COMPAIR_OPENAI_MODEL` – when using the OpenAI provider, supply your API key and optional model name (defaults to `gpt-4o-mini`). The fallback kicks in automatically if the key or SDK is unavailable.
|
|
100
|
+
- `COMPAIR_GENERATION_ENDPOINT` – HTTP endpoint invoked when `COMPAIR_GENERATION_PROVIDER=http`; the service receives a JSON payload (`document`, `references`, `length_instruction`) and should return `{"feedback": ...}`.
|
|
101
|
+
- `COMPAIR_OCR_ENDPOINT` – endpoint the backend calls for OCR uploads (defaults to the bundled Tesseract wrapper at `http://local-ocr:9001/ocr-file`). Provide your own service by overriding this URL.
|
|
99
102
|
|
|
100
103
|
See `compair_core/server/settings.py` for the full settings surface.
|
|
101
104
|
|
|
@@ -30,6 +30,7 @@ compair_core/server/deps.py
|
|
|
30
30
|
compair_core/server/settings.py
|
|
31
31
|
compair_core/server/local_model/__init__.py
|
|
32
32
|
compair_core/server/local_model/app.py
|
|
33
|
+
compair_core/server/local_model/ocr.py
|
|
33
34
|
compair_core/server/providers/__init__.py
|
|
34
35
|
compair_core/server/providers/console_mailer.py
|
|
35
36
|
compair_core/server/providers/contracts.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|