archeai-sdk 0.1.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.
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ dist/
4
+ build/
5
+ .env
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.5
2
+ Name: archeai-sdk
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the ArcheAI behavioral intelligence API — executive behavioral histories, deception-relevant signals, personality, and communication-style analytics from speech.
5
+ Project-URL: Homepage, https://arche-ai.com
6
+ Project-URL: Documentation, https://api.arche-ai.com/docs
7
+ Author-email: ArcheAI <contact@arche-ai.com>
8
+ License: MIT
9
+ Keywords: alternative-data,behavioral-analytics,earnings-calls,nlp,quantitative-finance,voice-analysis
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Financial and Insurance Industry
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Office/Business :: Financial :: Investment
15
+ Requires-Python: >=3.9
16
+ Requires-Dist: requests>=2.28
17
+ Provides-Extra: pandas
18
+ Requires-Dist: pandas>=1.5; extra == 'pandas'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # arche-ai
22
+
23
+ Official Python SDK for the [ArcheAI](https://arche-ai.com) behavioral
24
+ intelligence API — executive behavioral histories, deception-relevant
25
+ signals, personality, and communication-style analytics from speech.
26
+
27
+ ```bash
28
+ pip install arche-ai[pandas]
29
+ ```
30
+
31
+ ## Quant quickstart
32
+
33
+ ```python
34
+ from arche_ai import ArcheClient
35
+
36
+ c = ArcheClient(api_key="arche_sk_...")
37
+
38
+ # Flagship: per-executive quarterly behavioral trajectories, from
39
+ # ArcheAI's 1.8M-earnings-call research corpus (2005-present).
40
+ # Point-in-time safe: each quarter's scores derive only from that
41
+ # quarter's calls; history is append-only — safe for backtests.
42
+ df = c.behavioral_history("AAPL", from_q="2018Q1")
43
+ # one row per (executive, quarter):
44
+ # 7 communication-style z-scores + Big Five estimates
45
+
46
+ # Example: flag executives breaching their own uncertainty baseline
47
+ pivot = df.pivot_table(index="quarter", columns="executive",
48
+ values="style_uncertain_certain")
49
+ z = (pivot - pivot.expanding().mean()) / pivot.expanding().std()
50
+ print(z.tail(4)) # who no longer sounds like themselves?
51
+ ```
52
+
53
+ These are the same measures behind ArcheAI's published event-study
54
+ results (out-of-sample lift over price, Loughran-McDonald sentiment,
55
+ and SUE baselines at 1–5 day horizons).
56
+
57
+ ## Text analyses (async jobs)
58
+
59
+ ```python
60
+ job = c.analyze_fraud_language(qa_transcript_text) # >= 200 chars
61
+ job = c.analyze_personality(text)
62
+ job = c.analyze_style(text)
63
+
64
+ result = c.wait(job) # poll to completion
65
+ print(result.result)
66
+ ```
67
+
68
+ ## Audio (bring your own recordings)
69
+
70
+ ```python
71
+ audio_id = c.upload_audio("interview.wav") # one call: 3-step flow
72
+ job = c.analyze_deception_audio(audio_id) # research signal
73
+ job = c.analyze_voice_personality(audio_id) # voice-only Big Five
74
+ final = c.wait(job)
75
+ ```
76
+
77
+ Uploaded audio is automatically deleted from storage after 7 days;
78
+ delete sooner via the API or your account's My Data page.
79
+
80
+ ## Utilities
81
+
82
+ ```python
83
+ c.models() # available models + per-call credit costs
84
+ c.account() # remaining credits
85
+ ```
86
+
87
+ ## Important framing
88
+
89
+ All scores are **research signals intended to inform professional
90
+ judgment** — not investment advice, accusations, lie detection, or
91
+ determinations of fact. Validation methodology, published nulls, and
92
+ boundary conditions are documented at
93
+ [api.arche-ai.com/docs](https://api.arche-ai.com/docs).
94
+
95
+ ## Roadmap
96
+
97
+ - Speaker identification against ArcheAI's executive voiceprint
98
+ database (`speakers="auto"`)
99
+ - Bulk/point-in-time history export for backtesting
100
+ - Event-study starter kit (reproduce our published results on your
101
+ own universe)
102
+
103
+ © ArcheAI. Contact: contact@arche-ai.com
@@ -0,0 +1,83 @@
1
+ # arche-ai
2
+
3
+ Official Python SDK for the [ArcheAI](https://arche-ai.com) behavioral
4
+ intelligence API — executive behavioral histories, deception-relevant
5
+ signals, personality, and communication-style analytics from speech.
6
+
7
+ ```bash
8
+ pip install arche-ai[pandas]
9
+ ```
10
+
11
+ ## Quant quickstart
12
+
13
+ ```python
14
+ from arche_ai import ArcheClient
15
+
16
+ c = ArcheClient(api_key="arche_sk_...")
17
+
18
+ # Flagship: per-executive quarterly behavioral trajectories, from
19
+ # ArcheAI's 1.8M-earnings-call research corpus (2005-present).
20
+ # Point-in-time safe: each quarter's scores derive only from that
21
+ # quarter's calls; history is append-only — safe for backtests.
22
+ df = c.behavioral_history("AAPL", from_q="2018Q1")
23
+ # one row per (executive, quarter):
24
+ # 7 communication-style z-scores + Big Five estimates
25
+
26
+ # Example: flag executives breaching their own uncertainty baseline
27
+ pivot = df.pivot_table(index="quarter", columns="executive",
28
+ values="style_uncertain_certain")
29
+ z = (pivot - pivot.expanding().mean()) / pivot.expanding().std()
30
+ print(z.tail(4)) # who no longer sounds like themselves?
31
+ ```
32
+
33
+ These are the same measures behind ArcheAI's published event-study
34
+ results (out-of-sample lift over price, Loughran-McDonald sentiment,
35
+ and SUE baselines at 1–5 day horizons).
36
+
37
+ ## Text analyses (async jobs)
38
+
39
+ ```python
40
+ job = c.analyze_fraud_language(qa_transcript_text) # >= 200 chars
41
+ job = c.analyze_personality(text)
42
+ job = c.analyze_style(text)
43
+
44
+ result = c.wait(job) # poll to completion
45
+ print(result.result)
46
+ ```
47
+
48
+ ## Audio (bring your own recordings)
49
+
50
+ ```python
51
+ audio_id = c.upload_audio("interview.wav") # one call: 3-step flow
52
+ job = c.analyze_deception_audio(audio_id) # research signal
53
+ job = c.analyze_voice_personality(audio_id) # voice-only Big Five
54
+ final = c.wait(job)
55
+ ```
56
+
57
+ Uploaded audio is automatically deleted from storage after 7 days;
58
+ delete sooner via the API or your account's My Data page.
59
+
60
+ ## Utilities
61
+
62
+ ```python
63
+ c.models() # available models + per-call credit costs
64
+ c.account() # remaining credits
65
+ ```
66
+
67
+ ## Important framing
68
+
69
+ All scores are **research signals intended to inform professional
70
+ judgment** — not investment advice, accusations, lie detection, or
71
+ determinations of fact. Validation methodology, published nulls, and
72
+ boundary conditions are documented at
73
+ [api.arche-ai.com/docs](https://api.arche-ai.com/docs).
74
+
75
+ ## Roadmap
76
+
77
+ - Speaker identification against ArcheAI's executive voiceprint
78
+ database (`speakers="auto"`)
79
+ - Bulk/point-in-time history export for backtesting
80
+ - Event-study starter kit (reproduce our published results on your
81
+ own universe)
82
+
83
+ © ArcheAI. Contact: contact@arche-ai.com
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "archeai-sdk"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for the ArcheAI behavioral intelligence API — executive behavioral histories, deception-relevant signals, personality, and communication-style analytics from speech."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "ArcheAI", email = "contact@arche-ai.com" }]
13
+ keywords = [
14
+ "behavioral-analytics", "earnings-calls", "quantitative-finance",
15
+ "alternative-data", "nlp", "voice-analysis",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Intended Audience :: Financial and Insurance Industry",
20
+ "Intended Audience :: Science/Research",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Office/Business :: Financial :: Investment",
23
+ ]
24
+ dependencies = [
25
+ "requests>=2.28",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ pandas = ["pandas>=1.5"]
30
+
31
+ [project.urls]
32
+ Homepage = "https://arche-ai.com"
33
+ Documentation = "https://api.arche-ai.com/docs"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["src/arche_ai"]
@@ -0,0 +1,28 @@
1
+ """arche-ai — official Python SDK for the ArcheAI behavioral
2
+ intelligence API.
3
+
4
+ Quant-first design: the primary objects are point-in-time-safe
5
+ behavioral score feeds keyed by ticker/executive/quarter, returned as
6
+ pandas DataFrames when pandas is installed (plain dicts otherwise).
7
+
8
+ Quickstart (quant):
9
+ from arche_ai import ArcheClient
10
+ c = ArcheClient(api_key="arche_sk_...")
11
+ df = c.behavioral_history("AAPL", from_q="2018Q1")
12
+ # -> one row per (executive, quarter): 7 style dims + Big Five
13
+
14
+ Quickstart (text analytics):
15
+ job = c.analyze_fraud_language(text) # research signal
16
+ job = c.analyze_personality(text)
17
+ job = c.analyze_style(text)
18
+ result = c.wait(job) # poll to completion
19
+
20
+ All scores are research signals intended to inform professional
21
+ judgment — not investment advice, accusations, or determinations of
22
+ fact.
23
+ """
24
+
25
+ from .client import ArcheClient, ArcheAPIError, Job
26
+
27
+ __version__ = "0.1.0"
28
+ __all__ = ["ArcheClient", "ArcheAPIError", "Job", "__version__"]
@@ -0,0 +1,206 @@
1
+ """ArcheAI API client — quant-first SDK core.
2
+
3
+ Design notes:
4
+ - behavioral_history() is the flagship: point-in-time-safe quarterly
5
+ behavioral trajectories per executive. Long-format DataFrame out.
6
+ - Text analyses are async (job queue): analyze_*() returns a Job,
7
+ wait() polls it to completion.
8
+ - Audio upload wraps the 3-step signed-URL flow in one call.
9
+ - No pandas hard-dependency: DataFrame conversion degrades to
10
+ list-of-dicts when pandas is absent.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import time
16
+ from dataclasses import dataclass
17
+ from typing import Optional
18
+
19
+ import requests
20
+
21
+ DEFAULT_BASE = "https://api.arche-ai.com"
22
+ _UA = "arche-ai-python-sdk"
23
+
24
+
25
+ class ArcheAPIError(Exception):
26
+ """API returned an error response."""
27
+
28
+ def __init__(self, status: int, code: str, message: str,
29
+ meta: Optional[dict] = None):
30
+ self.status = status
31
+ self.code = code
32
+ self.message = message
33
+ self.meta = meta or {}
34
+ super().__init__(f"[{status} {code}] {message}")
35
+
36
+
37
+ @dataclass
38
+ class Job:
39
+ """Handle for an async analysis job."""
40
+ job_id: str
41
+ model: str
42
+ status: str = "queued"
43
+ result: Optional[dict] = None
44
+
45
+
46
+ def _maybe_df(records: list, prefer_df: bool):
47
+ if not prefer_df:
48
+ return records
49
+ try:
50
+ import pandas as pd # noqa: PLC0415
51
+ return pd.DataFrame(records)
52
+ except ImportError:
53
+ return records
54
+
55
+
56
+ class ArcheClient:
57
+ """Client for the ArcheAI behavioral intelligence API.
58
+
59
+ Args:
60
+ api_key: your ArcheAI API key ("arche_sk_...").
61
+ base_url: override for staging gateways.
62
+ dataframes: return pandas DataFrames where natural (default
63
+ True; degrades to lists of dicts without pandas).
64
+ """
65
+
66
+ def __init__(self, api_key: str, base_url: str = DEFAULT_BASE,
67
+ dataframes: bool = True, timeout: float = 60.0):
68
+ self._s = requests.Session()
69
+ self._s.headers.update({
70
+ "Authorization": f"Bearer {api_key}",
71
+ "User-Agent": _UA,
72
+ })
73
+ self._base = base_url.rstrip("/")
74
+ self._df = dataframes
75
+ self._timeout = timeout
76
+
77
+ def _req(self, method: str, path: str, **kw) -> dict:
78
+ r = self._s.request(method, self._base + path,
79
+ timeout=self._timeout, **kw)
80
+ try:
81
+ body = r.json()
82
+ except ValueError:
83
+ body = {}
84
+ if r.status_code >= 400:
85
+ raise ArcheAPIError(
86
+ r.status_code,
87
+ str(body.get("error", "UNKNOWN")),
88
+ str(body.get("message", r.text[:200])),
89
+ body.get("meta"),
90
+ )
91
+ return body
92
+
93
+ # ── quant surface ────────────────────────────────────────────────
94
+ def behavioral_history(self, ticker: str,
95
+ from_q: Optional[str] = None,
96
+ to_q: Optional[str] = None):
97
+ """Per-executive quarterly behavioral trajectories for a
98
+ company (point-in-time safe; append-only history).
99
+
100
+ Long-format output: one row per (executive, quarter) with 7
101
+ communication-style z-scores + Big Five estimates.
102
+ Costs 5 credits per call.
103
+ """
104
+ params = {}
105
+ if from_q:
106
+ params["from"] = from_q
107
+ if to_q:
108
+ params["to"] = to_q
109
+ data = self._req(
110
+ "GET", f"/v1/companies/{ticker}/behavioral-history",
111
+ params=params)["data"]
112
+ records = []
113
+ for ex in data["executives"]:
114
+ for q in ex["quarters"]:
115
+ row = {
116
+ "ticker": data["ticker"],
117
+ "speaker_id": ex["speakerId"],
118
+ "executive": ex["name"],
119
+ "quarter": q["quarter"],
120
+ "n_calls": q["nCalls"],
121
+ "n_words": q["nWords"],
122
+ }
123
+ row.update({f"style_{k}": v
124
+ for k, v in q["style"].items()})
125
+ row.update({f"big5_{k}": v
126
+ for k, v in q["bigFive"].items()})
127
+ records.append(row)
128
+ return _maybe_df(records, self._df)
129
+
130
+ def account(self) -> dict:
131
+ """Account status incl. remaining credits."""
132
+ return self._req("GET", "/v1/account")["data"]
133
+
134
+ def models(self):
135
+ """List available models and per-call credit costs."""
136
+ data = self._req("GET", "/v1/models")["data"]
137
+ return _maybe_df(data, self._df)
138
+
139
+ # ── text analyses (async jobs) ───────────────────────────────────
140
+ def _analyze_text(self, line: str, text: str) -> Job:
141
+ data = self._req("POST", f"/v1/analyses/{line}",
142
+ json={"text": text})["data"]
143
+ return Job(job_id=data["jobId"], model=line,
144
+ status=data.get("status", "queued"))
145
+
146
+ def analyze_fraud_language(self, text: str) -> Job:
147
+ """Fraud-language screening for unscripted executive text
148
+ (research signal; >=200 chars required)."""
149
+ return self._analyze_text("fraud-language", text)
150
+
151
+ def analyze_personality(self, text: str) -> Job:
152
+ """Big Five personality estimate from unscripted text."""
153
+ return self._analyze_text("personality", text)
154
+
155
+ def analyze_style(self, text: str) -> Job:
156
+ """7-dimension communication style vs executive norms."""
157
+ return self._analyze_text("style", text)
158
+
159
+ # ── audio (signed-URL upload + async analyses) ───────────────────
160
+ def upload_audio(self, path: str,
161
+ content_type: str = "audio/wav") -> str:
162
+ """Upload a local audio file (3-step signed-URL flow in one
163
+ call). Returns the audioId for analysis calls. Audio
164
+ auto-deletes from storage after 7 days."""
165
+ import os # noqa: PLC0415
166
+ data = self._req("POST", "/v1/audio", json={
167
+ "filename": os.path.basename(path),
168
+ "contentType": content_type})["data"]
169
+ with open(path, "rb") as f:
170
+ up = requests.put(data["uploadUrl"], data=f,
171
+ headers={"Content-Type": content_type},
172
+ timeout=600)
173
+ up.raise_for_status()
174
+ self._req("POST", f"/v1/audio/{data['audioId']}/confirm")
175
+ return data["audioId"]
176
+
177
+ def analyze_deception_audio(self, audio_id: str) -> Job:
178
+ """Deception-relevant vocal indicators (research signal)."""
179
+ data = self._req("POST", "/v1/analyses/deception",
180
+ json={"audioId": audio_id})["data"]
181
+ return Job(job_id=data["jobId"], model="deception")
182
+
183
+ def analyze_voice_personality(self, audio_id: str) -> Job:
184
+ """Voice-only Big Five (verification channel)."""
185
+ data = self._req("POST", "/v1/analyses/voice-personality",
186
+ json={"audioId": audio_id})["data"]
187
+ return Job(job_id=data["jobId"], model="voice-personality")
188
+
189
+ # ── job polling ──────────────────────────────────────────────────
190
+ def job(self, job: "Job | str") -> Job:
191
+ """Fetch current job state."""
192
+ jid = job.job_id if isinstance(job, Job) else job
193
+ d = self._req("GET", f"/v1/jobs/{jid}")["data"]
194
+ return Job(job_id=jid, model=d.get("modelSlug", ""),
195
+ status=d["status"], result=d.get("result"))
196
+
197
+ def wait(self, job: "Job | str", timeout: float = 300.0,
198
+ interval: float = 3.0) -> Job:
199
+ """Poll a job until completed/failed. Returns final Job."""
200
+ t0 = time.time()
201
+ while time.time() - t0 < timeout:
202
+ j = self.job(job)
203
+ if j.status in ("completed", "failed"):
204
+ return j
205
+ time.sleep(interval)
206
+ raise TimeoutError(f"job not finished in {timeout}s")