stratasynth-cli 0.2.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,63 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ .venv/
8
+ venv/
9
+ env/
10
+ .env
11
+ .env.test
12
+ *.egg-info/
13
+ dist/
14
+ build/
15
+ .uv/
16
+
17
+ # Node
18
+ node_modules/
19
+ dist/
20
+ .next/
21
+
22
+ # Playwright
23
+ apps/frontend/e2e/report/
24
+ apps/frontend/test-results/
25
+ apps/frontend/playwright-report/
26
+ out/
27
+ .turbo/
28
+
29
+ # AWS / Serverless
30
+ .serverless/
31
+ *.zip
32
+
33
+ # IDE
34
+ .idea/
35
+ .vscode/
36
+ *.swp
37
+ *.swo
38
+
39
+ # Archivos temporales de scripting con Claude Code
40
+ _*.json
41
+ _*.py
42
+ _*.js
43
+ _token*.txt
44
+ _resp*.json
45
+ _login*.json
46
+ _payload*.json
47
+
48
+ # Secretos y configuración local
49
+ *.local
50
+ .env.test
51
+ .env.production.local
52
+ apps/backend/.env
53
+ apps/frontend/.env.local
54
+ apps/frontend/.env.production
55
+ Docs/CREDENTIALS_DEV.md
56
+ docs/CREDENTIALS_MARKETPULSE.md
57
+
58
+ # Parquet (no en layers — archivos locales de desarrollo)
59
+ *.parquet
60
+
61
+ # OS
62
+ .DS_Store
63
+ Thumbs.db
@@ -0,0 +1,54 @@
1
+ # CLAUDE.md — StrataSynth CLI
2
+
3
+ ## Stack
4
+ - Python 3.12
5
+ - uv como package manager
6
+ - Distribuido en PyPI como `stratasynth-cli`
7
+ - Click para CLI framework
8
+
9
+ ## Instalación y uso
10
+ ```bash
11
+ pip install stratasynth-cli # producción
12
+ uv run stratasynth --help # desarrollo local
13
+
14
+ # Dataset Engine:
15
+ stratasynth auth login --api-key ss_live_...
16
+ stratasynth generate --scenario FAM-01 --count 100 --complexity 3 --adapter llamaindex_nodes
17
+ stratasynth jobs list
18
+ stratasynth jobs status {jobId}
19
+ stratasynth personas generate --archetype working_mother --complexity 4
20
+ stratasynth evaluate start --job-id {jobId}
21
+ stratasynth evaluate results --eval-id {evalId}
22
+ stratasynth evaluate results --eval-id {evalId} --json
23
+ # Humans Engine:
24
+ stratasynth humans generate -d '{"age_range":"28-40","gender":"female","country":"ES"}' -c '{"category":"yogures funcionales","study_brands":["Activia"]}'
25
+ stratasynth humans status --id hu_xxx
26
+ stratasynth humans batch --count 3 -d '{"age_range":"25-45","country":"ES"}'
27
+ stratasynth humans interview --id hu_xxx --interview-style narrative --verbosity high
28
+ ```
29
+
30
+ ## Estructura
31
+ ```
32
+ stratasynth_cli/
33
+ commands/
34
+ auth.py ← login, logout, whoami
35
+ generate.py ← generate dataset
36
+ jobs.py ← list, status, download
37
+ personas.py ← generate, view
38
+ evaluate.py ← start evaluation, results
39
+ scenarios.py ← list scenarios
40
+ humans.py ← generate, status, batch, interview (Humans Engine)
41
+ config.py ← Dataset + Humans API URLs, token management
42
+ output.py ← Rich formatting, progress bars
43
+ __main__.py ← CLI entry point
44
+ ```
45
+
46
+ ## Token management
47
+ - Token guardado en `~/.stratasynth/config.json` (no en código)
48
+ - TTL de 24h — regenerar con `stratasynth auth login`
49
+
50
+ ## Deploy
51
+ ```bash
52
+ uv build # genera dist/
53
+ uv publish # publicar a PyPI
54
+ ```
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: stratasynth-cli
3
+ Version: 0.2.0
4
+ Summary: CLI for StrataSynth — synthetic conversational data with psychological depth
5
+ Project-URL: Homepage, https://stratasynth.com
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: click>=8.1.0
8
+ Requires-Dist: httpx>=0.27.0
9
+ Requires-Dist: pydantic>=2.6.0
10
+ Requires-Dist: python-dotenv>=1.0.0
11
+ Requires-Dist: pyyaml>=6.0
12
+ Requires-Dist: rich>=13.7.0
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.build.targets.wheel]
6
+ packages = ["stratasynth_cli"]
7
+
8
+ [project]
9
+ name = "stratasynth-cli"
10
+ version = "0.2.0"
11
+ description = "CLI for StrataSynth — synthetic conversational data with psychological depth"
12
+ requires-python = ">=3.12"
13
+ dependencies = [
14
+ "click>=8.1.0",
15
+ "httpx>=0.27.0",
16
+ "rich>=13.7.0",
17
+ "pydantic>=2.6.0",
18
+ "python-dotenv>=1.0.0",
19
+ "pyyaml>=6.0",
20
+ ]
21
+
22
+ [project.scripts]
23
+ stratasynth = "stratasynth_cli.__main__:cli"
24
+
25
+ [project.urls]
26
+ Homepage = "https://stratasynth.com"
@@ -0,0 +1,54 @@
1
+ """
2
+ CLI auth commands — login, logout, whoami.
3
+
4
+ $ stratasynth auth login --api-key ss_live_...
5
+ $ stratasynth auth logout
6
+ """
7
+ import click
8
+ import httpx
9
+ from stratasynth_cli.config import get_api_url, save_token, clear_token, get_token
10
+ from stratasynth_cli.output import print_error, print_success, print_login_success, print_whoami
11
+
12
+
13
+ @click.group()
14
+ def auth():
15
+ """Authentication commands."""
16
+ pass
17
+
18
+
19
+ @auth.command()
20
+ @click.option("--api-key", required=True, envvar="STRATASYNTH_API_KEY", help="Your StrataSynth API key (ss_live_...)")
21
+ def login(api_key):
22
+ """Login with your API key."""
23
+ try:
24
+ response = httpx.post(
25
+ f"{get_api_url()}/auth/token",
26
+ json={"api_key": api_key},
27
+ timeout=10,
28
+ )
29
+ if response.status_code == 200:
30
+ token = response.json()["data"]["token"]
31
+ save_token(token)
32
+ print_login_success()
33
+ else:
34
+ msg = response.json().get("message", "Invalid API key")
35
+ print_error(f"Login failed: {msg}")
36
+ raise SystemExit(1)
37
+ except SystemExit:
38
+ raise
39
+ except Exception as e:
40
+ print_error(f"Connection error: {e}")
41
+ raise SystemExit(1)
42
+
43
+
44
+ @auth.command()
45
+ def logout():
46
+ """Logout and remove saved token."""
47
+ clear_token()
48
+ print_success("Logged out.")
49
+
50
+
51
+ @auth.command()
52
+ def whoami():
53
+ """Show current authentication status."""
54
+ print_whoami(authenticated=bool(get_token()))
@@ -0,0 +1,111 @@
1
+ """
2
+ CLI evaluate commands — evaluar output y ver resultados.
3
+
4
+ $ stratasynth evaluate start --job-id job_xxx
5
+ $ stratasynth evaluate results --eval-id eval_xxx
6
+ $ stratasynth evaluate results --eval-id eval_xxx --json
7
+ """
8
+ import json
9
+ import time
10
+
11
+ import click
12
+ import httpx
13
+ from stratasynth_cli.config import get_api_url, get_token
14
+ from stratasynth_cli.output import (
15
+ print_error,
16
+ print_eval_started,
17
+ print_eval_results,
18
+ )
19
+
20
+
21
+ @click.group()
22
+ def evaluate():
23
+ """Evaluate your system's output against StrataSynth ground truth."""
24
+ pass
25
+
26
+
27
+ @evaluate.command()
28
+ @click.option("--job-id", required=True, help="StrataSynth job ID (el dataset generado)")
29
+ @click.option("--output-url", default=None, help="S3 key del output de tu sistema a evaluar (opcional)")
30
+ @click.option("--json", "json_output", is_flag=True, help="Output as JSON for scripting")
31
+ def start(job_id, output_url, json_output):
32
+ """Start a new evaluation for a completed job."""
33
+ token = get_token()
34
+ if not token:
35
+ print_error("Not authenticated. Run: stratasynth auth login --api-key ss_live_...")
36
+ raise SystemExit(1)
37
+
38
+ payload: dict = {"jobId": job_id}
39
+ if output_url:
40
+ payload["system_output"] = output_url
41
+
42
+ response = httpx.post(
43
+ f"{get_api_url()}/evaluate",
44
+ json=payload,
45
+ headers={"Authorization": f"Bearer {token}"},
46
+ timeout=10,
47
+ )
48
+ if response.status_code in (200, 201):
49
+ data = response.json()["data"]
50
+ if json_output:
51
+ click.echo(json.dumps(data))
52
+ else:
53
+ print_eval_started(data["evalId"])
54
+ else:
55
+ print_error(response.json().get("message", "Unknown error"))
56
+ raise SystemExit(1)
57
+
58
+
59
+ @evaluate.command()
60
+ @click.option("--eval-id", required=True, help="Evaluation ID from 'evaluate start'")
61
+ @click.option("--wait/--no-wait", default=True, help="Wait for evaluation to complete (default: wait)")
62
+ @click.option("--json", "json_output", is_flag=True, help="Output as JSON for scripting")
63
+ def results(eval_id, wait, json_output):
64
+ """Get evaluation results (polls until COMPLETED if --wait)."""
65
+ token = get_token()
66
+ if not token:
67
+ print_error("Not authenticated. Run: stratasynth auth login --api-key ss_live_...")
68
+ raise SystemExit(1)
69
+
70
+ headers = {"Authorization": f"Bearer {token}"}
71
+ api_url = get_api_url()
72
+
73
+ max_polls = 24 if wait else 1
74
+ result = None
75
+
76
+ for _ in range(max_polls):
77
+ response = httpx.get(
78
+ f"{api_url}/evaluate/{eval_id}",
79
+ headers=headers,
80
+ timeout=10,
81
+ )
82
+
83
+ if response.status_code == 404:
84
+ print_error(f"Evaluation {eval_id} not found.")
85
+ raise SystemExit(1)
86
+ if response.status_code != 200:
87
+ print_error(f"API error: {response.status_code} — {response.text}")
88
+ raise SystemExit(1)
89
+
90
+ result = response.json()["data"]
91
+ status = result.get("status", "UNKNOWN")
92
+
93
+ if status in ("COMPLETED", "FAILED"):
94
+ break
95
+
96
+ if wait:
97
+ time.sleep(5)
98
+
99
+ if json_output:
100
+ click.echo(json.dumps(result))
101
+ return
102
+
103
+ if result.get("status") == "FAILED":
104
+ print_error(f"Evaluation {eval_id} failed.")
105
+ raise SystemExit(1)
106
+
107
+ if result.get("status") != "COMPLETED":
108
+ print_error(f"Evaluation {eval_id} still {result.get('status')}. Use --wait to poll.")
109
+ raise SystemExit(1)
110
+
111
+ print_eval_results(result)
@@ -0,0 +1,112 @@
1
+ """
2
+ CLI generate command — crear job de generación de dataset.
3
+ """
4
+ import json
5
+ import click
6
+ import httpx
7
+ from stratasynth_cli.config import get_api_url, get_token
8
+ from stratasynth_cli.output import print_error, print_job_created
9
+
10
+
11
+ VALID_ADAPTERS = [
12
+ "flat_jsonl", "llamaindex_nodes", "openai_finetuning",
13
+ "langchain_memory", "huggingface_dataset", "csv_tabular",
14
+ "anthropic_claude", "luminoracore", "custom_adapter",
15
+ ]
16
+ VALID_MEDIUMS = ["text_chat", "voice_call", "face_to_face", "email", "unspecified"]
17
+ VALID_LOCATIONS = ["home", "work", "public", "unspecified"]
18
+ VALID_TURN_LENGTHS = ["brief", "natural", "extended"]
19
+ VALID_LANGUAGES = ["en", "es", "de", "fr"]
20
+
21
+
22
+ _GENERATE_EPILOG = """
23
+ \b
24
+ SCENARIOS (run `stratasynth scenarios list` to see all 12):
25
+ FAM-01 Family — mother/child accumulated tension
26
+ FAM-02 Family — father/daughter reconnection after estrangement
27
+ ROM-01 Romance — couple in post-relocation crisis
28
+ ROM-02 Romance — relationship slowly ending
29
+ PRO-01 Professional — silent burnout
30
+ VIT-01 Vital — grief after loss of parent
31
+
32
+ \b
33
+ ADAPTERS:
34
+ flat_jsonl Raw JSON per turn. Use for custom pipelines.
35
+ openai_finetuning ChatML format, ready for OpenAI fine-tuning API.
36
+ llamaindex_nodes TextNode objects for LlamaIndex / vector stores.
37
+ langchain_memory HumanMessage/AIMessage for LangChain.
38
+ huggingface_dataset Arrow/Parquet, load with datasets.load_dataset().
39
+ anthropic_claude Anthropic Messages API format.
40
+ csv_tabular One row per turn — good for pandas / Excel.
41
+
42
+ \b
43
+ EXAMPLES:
44
+ # 500 conversations for OpenAI fine-tuning, family conflict
45
+ stratasynth generate --scenario FAM-01 --count 500 --adapter openai_finetuning
46
+
47
+ # Spanish romantic conflict, text chat context, brief turns
48
+ stratasynth generate --scenario ROM-02 --count 200 \\
49
+ --language es --medium text_chat --turn-length brief
50
+
51
+ # Reproducible dataset (same seed = identical output every time)
52
+ stratasynth generate --scenario PRO-01 --count 1000 --seed 42
53
+
54
+ # Pipe job ID to another command
55
+ JOB=$(stratasynth generate --scenario FAM-02 --count 50 --json | jq -r '.jobId')
56
+ stratasynth jobs status --job-id $JOB
57
+ """
58
+
59
+
60
+ @click.command(epilog=_GENERATE_EPILOG)
61
+ @click.option("--scenario", required=True, help="Scenario ID. Run `stratasynth scenarios list` to see all 12.")
62
+ @click.option("--count", default=100, show_default=True, help="Number of conversations to generate.")
63
+ @click.option("--complexity", default=3, show_default=True, type=click.IntRange(1, 5), help="PsycheGraph depth: 1=minimal, 3=standard (recommended), 5=deep.")
64
+ @click.option("--adapter", default="flat_jsonl", show_default=True, type=click.Choice(VALID_ADAPTERS), help="Output format (see ADAPTERS below).")
65
+ @click.option("--language", default="en", show_default=True, type=click.Choice(VALID_LANGUAGES), help="Language for generated conversations.")
66
+ @click.option("--medium", default="unspecified", show_default=True, type=click.Choice(VALID_MEDIUMS), help="Conversation channel — affects tone and style of generated text.")
67
+ @click.option("--location", default="unspecified", show_default=True, type=click.Choice(VALID_LOCATIONS), help="Physical context injected into each turn.")
68
+ @click.option("--turn-length", default="natural", show_default=True, type=click.Choice(VALID_TURN_LENGTHS), help="Turn length: brief (1-2 sentences), natural (3-5), extended (paragraphs).")
69
+ @click.option("--noise", default=0.12, show_default=True, type=click.FloatRange(0.0, 0.5), help="Noise injection rate: fraction of turns with intentional noise (0.0-0.5).")
70
+ @click.option("--seed", default=None, type=int, help="Random seed for reproducible generation.")
71
+ @click.option("--json", "json_output", is_flag=True, help="Output as JSON (for scripting / pipes).")
72
+ def generate(scenario, count, complexity, adapter, language, medium, location, turn_length, noise, seed, json_output):
73
+ """Generate a synthetic conversational dataset."""
74
+ token = get_token()
75
+ if not token:
76
+ print_error("Not authenticated. Run: stratasynth auth login --api-key ss_live_...")
77
+ raise SystemExit(1)
78
+
79
+ payload = {
80
+ "scenario_id": scenario,
81
+ "conversation_count": count,
82
+ "complexity": complexity,
83
+ "adapter": adapter,
84
+ "language": language,
85
+ "noise_pct": noise,
86
+ "turn_length_target": turn_length,
87
+ "conversation_setting": {"medium": medium, "location": location},
88
+ }
89
+ if seed is not None:
90
+ payload["seed"] = seed
91
+
92
+ try:
93
+ response = httpx.post(
94
+ f"{get_api_url()}/jobs/dataset",
95
+ json=payload,
96
+ headers={"Authorization": f"Bearer {token}"},
97
+ timeout=10,
98
+ )
99
+ if response.status_code == 200:
100
+ data = response.json()["data"]
101
+ if json_output:
102
+ click.echo(json.dumps(data))
103
+ else:
104
+ print_job_created(data)
105
+ else:
106
+ print_error(f"Error {response.status_code}: {response.text}")
107
+ raise SystemExit(1)
108
+ except SystemExit:
109
+ raise
110
+ except Exception as e:
111
+ print_error(f"Connection error: {e}")
112
+ raise SystemExit(1)