sc-research 1.0.13 → 1.1.0
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.
- package/LICENSE +21 -0
- package/README.md +225 -64
- package/dist/web/assets/index-Bo0b_RP8.css +1 -0
- package/dist/web/assets/{index-sZb3bzqd.js → index-DhbLI1q5.js} +16 -16
- package/dist/web/icon.svg +3 -0
- package/dist/web/index.html +4 -4
- package/dist/web/mocks/classified_controversy.json +122 -0
- package/dist/web/mocks/classified_discovery.json +151 -0
- package/dist/web/mocks/classified_rank.json +160 -0
- package/dist/web/mocks/classified_sentiment.json +52 -0
- package/dist/web/mocks/classified_trend.json +175 -0
- package/package.json +2 -1
- package/templates/base/commands/controversy.md +8 -20
- package/templates/base/commands/deep-research.md +8 -19
- package/templates/base/commands/discovery.md +10 -22
- package/templates/base/commands/quick.md +6 -7
- package/templates/base/commands/rank.md +8 -19
- package/templates/base/commands/research.md +12 -6
- package/templates/base/commands/sentiment.md +8 -20
- package/templates/base/commands/trend.md +8 -19
- package/templates/base/commands/visualize.md +7 -7
- package/templates/base/skills/social_media_controversy.md +53 -23
- package/templates/base/skills/social_media_discovery.md +55 -43
- package/templates/base/skills/social_media_fetch.md +81 -49
- package/templates/base/skills/social_media_rank.md +49 -20
- package/templates/base/skills/social_media_schema.md +105 -19
- package/templates/base/skills/social_media_sentiment.md +59 -23
- package/templates/base/skills/social_media_trend.md +60 -20
- package/templates/base/skills/using_social_media_research.md +92 -74
- package/dist/web/assets/index-FB2oq23H.css +0 -1
- package/dist/web/vite.svg +0 -11
|
@@ -1,57 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: social_media_discovery
|
|
3
|
-
description:
|
|
3
|
+
description: Analysis-only worker. Reads existing raw Reddit/X data to find emerging or viral themes and generates `classified_discovery.json` with strict `DiscoveryData` output.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Social Media Discovery Skill
|
|
7
7
|
|
|
8
|
-
This worker clusters noisy social discussions into trend themes that can be visualized.
|
|
8
|
+
This worker clusters noisy social discussions into trend themes that can be visualized. It performs **analysis only** — fetching is handled by the orchestrator via `social_media_fetch`.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Prerequisites
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The following files must already exist (produced by `social_media_fetch`):
|
|
13
13
|
|
|
14
|
-
- `reddit_data.json`
|
|
15
|
-
- `x_data.json`
|
|
14
|
+
- `reddit_data.json` and/or `x_data.json`
|
|
16
15
|
|
|
17
|
-
At least one valid source file must
|
|
16
|
+
At least one valid source file must be present. If both are missing, **stop and report failure** — do not attempt to fetch data.
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Use this sequence when running discovery end-to-end:
|
|
22
|
-
|
|
23
|
-
1. Fetch or refresh discovery raw data (outside this worker):
|
|
24
|
-
|
|
25
|
-
- Broad weekly discovery feed: `sc-research research:deep "DISCOVERY_WEEKLY" --mode=discovery`
|
|
26
|
-
- Topic-focused discovery: `sc-research research:deep "TOPIC" --mode=discovery`
|
|
27
|
-
- Optional filters: `--source=reddit|x|both --from=YYYY-MM-DD --to=YYYY-MM-DD`
|
|
28
|
-
|
|
29
|
-
2. Run this `social_media_discovery` worker to analyze existing raw files and produce `classified_discovery.json`.
|
|
30
|
-
3. Optional visualization step:
|
|
31
|
-
|
|
32
|
-
- `sc-research visualize`
|
|
33
|
-
|
|
34
|
-
If raw files are missing, stale, or mismatched for the requested topic/date range, instruct the caller to run step 1 first.
|
|
35
|
-
|
|
36
|
-
## Discovery Fetch Behavior (Code-Aligned)
|
|
37
|
-
|
|
38
|
-
When `--mode=discovery` is used, runtime behavior differs by topic:
|
|
39
|
-
|
|
40
|
-
1. If topic is exactly `DISCOVERY_WEEKLY` and Reddit is enabled:
|
|
41
|
-
|
|
42
|
-
- Fetches Reddit trending posts from `r/popular/top` with `t=week` and limit `25`.
|
|
43
|
-
|
|
44
|
-
2. For other topics in discovery mode and Reddit enabled:
|
|
45
|
-
|
|
46
|
-
- Maps topic to candidate subreddits first.
|
|
47
|
-
- Per subreddit, uses either top posts (`week`, limit `5`) or subreddit search (`week`, limit `5`) based on topic/subreddit match.
|
|
48
|
-
- If mapping returns no subreddits, falls back to legacy Reddit keyword-thread flow.
|
|
49
|
-
|
|
50
|
-
3. X source behavior:
|
|
51
|
-
|
|
52
|
-
- X fetch still runs through normal X search flow (`maxItems` based on depth), even in discovery mode.
|
|
53
|
-
|
|
54
|
-
This skill consumes the resulting `reddit_data.json` / `x_data.json`; it does not perform fetching itself.
|
|
18
|
+
**Note on discovery data**: For best results, the orchestrator should have fetched with `--mode=discovery`. This skill analyzes whatever raw data exists — it does not control how data was fetched.
|
|
55
19
|
|
|
56
20
|
## Step 1: Preflight Validation
|
|
57
21
|
|
|
@@ -112,6 +76,54 @@ Save strict JSON to:
|
|
|
112
76
|
|
|
113
77
|
- `classified_discovery.json`
|
|
114
78
|
|
|
79
|
+
## Output Type Contract
|
|
80
|
+
|
|
81
|
+
Your output MUST match this exact shape. The dashboard detects discovery data by checking for `trending_topics` (array). Missing this field = broken tab.
|
|
82
|
+
|
|
83
|
+
**WARNING**: Discovery uses DIFFERENT enum casing than other skills. Everything is **lowercase** here.
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"topic": "AI tools 2025",
|
|
88
|
+
"period": "2025-01-01 to 2025-01-31",
|
|
89
|
+
"total_posts_analyzed": 156,
|
|
90
|
+
"trending_topics": [
|
|
91
|
+
{
|
|
92
|
+
"id": "local-llm-hosting",
|
|
93
|
+
"topic_name": "Local LLM Hosting",
|
|
94
|
+
"description": "Growing interest in running language models locally using consumer hardware",
|
|
95
|
+
"category": "Technology",
|
|
96
|
+
"engagement_score": 4500,
|
|
97
|
+
"sentiment": "positive",
|
|
98
|
+
"key_posts": [
|
|
99
|
+
{
|
|
100
|
+
"title": "I got Llama 3 running on my M3 MacBook and it's incredible",
|
|
101
|
+
"url": "https://reddit.com/r/LocalLLaMA/comments/mno345",
|
|
102
|
+
"platform": "reddit",
|
|
103
|
+
"engagement": 2100
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"highlight_comments": [
|
|
107
|
+
{
|
|
108
|
+
"text": "The performance gains with quantization are impressive",
|
|
109
|
+
"author": "u/ml_enthusiast",
|
|
110
|
+
"link": "https://reddit.com/r/LocalLLaMA/comments/mno345/comment/abc",
|
|
111
|
+
"platform": "reddit"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Enum Rules for Discovery (ALL LOWERCASE)
|
|
120
|
+
|
|
121
|
+
Discovery is the **only** classified type that uses lowercase sentiment values. Do NOT copy Title Case from rank/sentiment/controversy.
|
|
122
|
+
|
|
123
|
+
- `sentiment` on DiscoveryTopic: **lowercase** — `"positive"`, `"negative"`, `"neutral"`, `"mixed"`. NEVER use `"Positive"`, `"Mixed"`, or `"Very Positive"`.
|
|
124
|
+
- `platform` on key_posts and highlight_comments: **lowercase** — `"reddit"`, `"x"`. NEVER use `"Reddit"`, `"X"`, or `"twitter"`.
|
|
125
|
+
- `id`: use a **slug-like** identifier (e.g., `"local-llm-hosting"`), not a UUID or number.
|
|
126
|
+
|
|
115
127
|
## Final Validation Checklist
|
|
116
128
|
|
|
117
129
|
- JSON parse succeeds.
|
|
@@ -1,61 +1,83 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: social_media_fetch
|
|
3
|
-
description:
|
|
3
|
+
description: The sole data-fetching authority for the research pipeline. Handles CLI execution, data freshness checks, and output validation. Always called by the orchestrator — never by worker skills directly.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Social Media Fetch Skill
|
|
7
7
|
|
|
8
|
-
This
|
|
8
|
+
This is the **only** skill that runs `sc-research research` CLI commands. No other skill or command should execute fetch commands. The orchestrator delegates here; worker skills consume the output.
|
|
9
9
|
|
|
10
|
-
## Inputs
|
|
10
|
+
## Inputs (provided by orchestrator)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
The orchestrator will specify:
|
|
13
|
+
|
|
14
|
+
- **topic**: the search query string
|
|
15
|
+
- **depth**: `quick` or `deep`
|
|
16
|
+
- **mode**: `research` (default) or `discovery`
|
|
17
|
+
- **source** (optional): `reddit`, `x`, or omit for all available
|
|
18
|
+
- **date range** (optional): `from` / `to` as `YYYY-MM-DD`
|
|
19
|
+
|
|
20
|
+
## Outputs
|
|
21
|
+
|
|
22
|
+
- `reddit_data.json` (project root)
|
|
23
|
+
- `x_data.json` (project root)
|
|
16
24
|
|
|
17
25
|
At least one output file must be produced for a successful fetch.
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
---
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
## Step 1: Check Data Freshness
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
- Deep fetch: `sc-research research:deep "TOPIC"`
|
|
25
|
-
- Discovery fetch: `sc-research research:deep "TOPIC" --mode=discovery`
|
|
31
|
+
Before running a new fetch, check whether existing raw files can be reused:
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
1. Does `reddit_data.json` or `x_data.json` exist?
|
|
34
|
+
2. Is the file valid JSON with a top-level `items` array?
|
|
35
|
+
3. Does the `query` field match the current topic (same or equivalent intent)?
|
|
36
|
+
4. Does the `dateRange` match the requested window (if provided)?
|
|
37
|
+
5. Does the source scope match (e.g., if user asked for Reddit-only, is Reddit data present)?
|
|
28
38
|
|
|
29
|
-
|
|
39
|
+
**If all checks pass** → skip fetch, use existing data and report "Using cached data."
|
|
40
|
+
**If any check fails** → proceed with fresh fetch.
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
- `sc-research research "TOPIC"`
|
|
33
|
-
- **Deep mode** (default for analysis workflows):
|
|
34
|
-
- `sc-research research:deep "TOPIC"`
|
|
35
|
-
- **Discovery mode** (theme clustering data):
|
|
36
|
-
- `sc-research research:deep "TOPIC" --mode=discovery`
|
|
42
|
+
## Step 2: Build CLI Command
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
Construct the command based on inputs:
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
**Standard analysis routes:**
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
48
|
+
```bash
|
|
49
|
+
sc-research research:deep "TOPIC"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Quick-answer route:**
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
```bash
|
|
55
|
+
sc-research research "TOPIC" --source=reddit
|
|
56
|
+
```
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
**Discovery route (broad weekly):**
|
|
49
59
|
|
|
50
60
|
```bash
|
|
51
|
-
sc-research research:deep "
|
|
52
|
-
sc-research research:deep "wireless earbuds" --source=reddit --from=2025-01-01 --to=2025-12-31
|
|
53
|
-
sc-research research:deep "wireless earbuds" --mode=discovery --source=both
|
|
61
|
+
sc-research research:deep "DISCOVERY_WEEKLY" --mode=discovery
|
|
54
62
|
```
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
**Discovery route (topic-focused):**
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
sc-research research:deep "TOPIC" --mode=discovery
|
|
68
|
+
```
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
Append optional flags only when provided by the orchestrator:
|
|
71
|
+
|
|
72
|
+
- `--source=reddit|x|both`
|
|
73
|
+
- `--from=YYYY-MM-DD --to=YYYY-MM-DD`
|
|
74
|
+
- `--mode=discovery`
|
|
75
|
+
|
|
76
|
+
When `--source` is omitted, runtime uses all sources whose API keys are available.
|
|
77
|
+
|
|
78
|
+
## Step 3: Execute and Validate
|
|
79
|
+
|
|
80
|
+
Run the constructed command, then validate each produced file:
|
|
59
81
|
|
|
60
82
|
1. File exists.
|
|
61
83
|
2. JSON is parseable.
|
|
@@ -65,30 +87,40 @@ After running the command, verify each produced source file:
|
|
|
65
87
|
|
|
66
88
|
If a source was explicitly requested but its file is missing or malformed, report the failure clearly.
|
|
67
89
|
|
|
68
|
-
## Step 4: Return
|
|
90
|
+
## Step 4: Return Fetch Summary
|
|
69
91
|
|
|
70
|
-
Return:
|
|
92
|
+
Return to the orchestrator:
|
|
71
93
|
|
|
72
94
|
- topic
|
|
73
|
-
-
|
|
74
|
-
-
|
|
95
|
+
- mode used (`research` / `discovery`)
|
|
96
|
+
- sources fetched
|
|
75
97
|
- date range used
|
|
76
98
|
- item count per source
|
|
77
|
-
- any missing
|
|
99
|
+
- any warnings (missing source, partial results, cached data reuse)
|
|
78
100
|
|
|
79
|
-
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Discovery Fetch Behavior (runtime details)
|
|
104
|
+
|
|
105
|
+
When `--mode=discovery` is used, runtime behavior differs by topic:
|
|
80
106
|
|
|
81
|
-
1.
|
|
82
|
-
2.
|
|
83
|
-
3.
|
|
84
|
-
4. **Fail loudly on malformed output**: do not continue as if fetch succeeded when validation fails.
|
|
107
|
+
1. Topic is exactly `DISCOVERY_WEEKLY` with Reddit enabled → fetches `r/popular/top` with `t=week`, limit `25`.
|
|
108
|
+
2. Other topics in discovery mode with Reddit enabled → maps topic to candidate subreddits, then fetches top posts or searches per subreddit.
|
|
109
|
+
3. X source → runs normal X search flow regardless of discovery mode.
|
|
85
110
|
|
|
86
111
|
## Error Handling
|
|
87
112
|
|
|
88
|
-
| Scenario | Symptom
|
|
89
|
-
| ---------------------------------- |
|
|
90
|
-
| Missing `OPENAI_API_KEY` | Auth failure on Reddit fetch
|
|
91
|
-
| Missing `XAI_API_KEY` | X file missing
|
|
92
|
-
| No relevant results | `items` is empty
|
|
93
|
-
| Rate limit / transient API failure | Timeout or provider error
|
|
94
|
-
| Malformed output | JSON parse failure or missing `items`
|
|
113
|
+
| Scenario | Symptom | Action |
|
|
114
|
+
| ---------------------------------- | ------------------------------------- | ---------------------------------------------------- |
|
|
115
|
+
| Missing `OPENAI_API_KEY` | Auth failure on Reddit fetch | Set valid `OPENAI_API_KEY` in `.sc-research` |
|
|
116
|
+
| Missing `XAI_API_KEY` | X file missing while Reddit succeeds | Set `XAI_API_KEY` in `.sc-research` to enable X |
|
|
117
|
+
| No relevant results | `items` is empty | Broaden topic keywords and retry |
|
|
118
|
+
| Rate limit / transient API failure | Timeout or provider error | Wait, then retry once with same parameters |
|
|
119
|
+
| Malformed output | JSON parse failure or missing `items` | Re-run fetch; if repeated, report failure explicitly |
|
|
120
|
+
|
|
121
|
+
## Critical Rules
|
|
122
|
+
|
|
123
|
+
1. **No analysis here** — do not rank, classify, or generate classified files.
|
|
124
|
+
2. **No fabricated data** — do not create synthetic posts.
|
|
125
|
+
3. **This is the only fetch point** — worker skills must never run fetch commands.
|
|
126
|
+
4. **Fail loudly** — do not continue as if fetch succeeded when validation fails.
|
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: social_media_rank
|
|
3
|
-
description:
|
|
3
|
+
description: Analysis-only worker. Reads existing raw Reddit/X data and generates `classified_rank.json` using the strict `ClassifiedData` schema. Use for ranking, best-of, compare, or recommendation requests.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Social Media Ranking Skill
|
|
7
7
|
|
|
8
|
-
This worker converts raw discussion data into a ranked report suitable for the dashboard.
|
|
8
|
+
This worker converts raw discussion data into a ranked report suitable for the dashboard. It performs **analysis only** — fetching is handled by the orchestrator via `social_media_fetch`.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Prerequisites
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The following files must already exist (produced by `social_media_fetch`):
|
|
13
13
|
|
|
14
|
-
- `reddit_data.json`
|
|
15
|
-
- `x_data.json`
|
|
14
|
+
- `reddit_data.json` and/or `x_data.json`
|
|
16
15
|
|
|
17
|
-
At least one valid source file must
|
|
18
|
-
|
|
19
|
-
## Command Execution Flow
|
|
20
|
-
|
|
21
|
-
Use this sequence for ranking:
|
|
22
|
-
|
|
23
|
-
1. Fetch or refresh raw data (outside this worker):
|
|
24
|
-
- `sc-research research:deep "TOPIC"`
|
|
25
|
-
- Optional filters: `--source=reddit|x|both --from=YYYY-MM-DD --to=YYYY-MM-DD`
|
|
26
|
-
2. Run this `social_media_rank` worker to generate `classified_rank.json`.
|
|
27
|
-
3. Optional visualization:
|
|
28
|
-
- `sc-research visualize`
|
|
29
|
-
|
|
30
|
-
If raw files are missing, stale, or mismatched for the requested topic/date range, run step 1 first.
|
|
16
|
+
At least one valid source file must be present. If both are missing, **stop and report failure** — do not attempt to fetch data.
|
|
31
17
|
|
|
32
18
|
## Step 1: Preflight Validation
|
|
33
19
|
|
|
@@ -91,6 +77,49 @@ Required top-level fields:
|
|
|
91
77
|
- `products`
|
|
92
78
|
- `key_insights`
|
|
93
79
|
|
|
80
|
+
## Output Type Contract
|
|
81
|
+
|
|
82
|
+
Your output MUST match this exact shape. The dashboard detects rank data by checking for `products` (array) + `key_insights` (array). Missing either field = broken tab.
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"topic": "best wireless earbuds 2025",
|
|
87
|
+
"products": [
|
|
88
|
+
{
|
|
89
|
+
"rank": 1,
|
|
90
|
+
"name": "Sony WF-1000XM5",
|
|
91
|
+
"sentiment": "Very Positive",
|
|
92
|
+
"mentions": 42,
|
|
93
|
+
"estimated_engagement_score": 8750,
|
|
94
|
+
"consensus": "Widely praised for ANC quality and sound clarity",
|
|
95
|
+
"pros": [
|
|
96
|
+
"Best-in-class ANC",
|
|
97
|
+
"Excellent sound quality",
|
|
98
|
+
"Comfortable fit"
|
|
99
|
+
],
|
|
100
|
+
"cons": ["Premium price", "Average battery life"],
|
|
101
|
+
"highlight_quotes": [
|
|
102
|
+
{
|
|
103
|
+
"text": "The XM5s completely changed how I listen to music",
|
|
104
|
+
"author": "u/audiophile_reviews",
|
|
105
|
+
"link": "https://reddit.com/r/headphones/comments/abc123",
|
|
106
|
+
"context": "pro"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"key_insights": [
|
|
112
|
+
"Sony and Apple dominate recommendations with 70% of mentions",
|
|
113
|
+
"ANC quality is the most-discussed factor across all posts"
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Enum Rules for Rank
|
|
119
|
+
|
|
120
|
+
- `sentiment` on Product: **Title Case** — `"Very Positive"`, `"Positive"`, `"Mixed"`, `"Negative"`. NEVER use `"positive"` or `"neutral"`.
|
|
121
|
+
- `context` on quotes: **lowercase** — `"pro"`, `"con"`, `"general"`. NEVER use `"Pro"` or `"Con"`.
|
|
122
|
+
|
|
94
123
|
## Final Validation Checklist
|
|
95
124
|
|
|
96
125
|
- JSON is parseable.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: social_media_schema
|
|
3
|
-
description: Reference-only skill that defines canonical JSON schemas for classified output files.
|
|
3
|
+
description: Reference-only skill that defines canonical JSON schemas for classified output files. Includes enum warnings and dashboard detection rules.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Social Media Schema Reference
|
|
@@ -13,7 +13,7 @@ Use this file as the canonical schema source for all classified outputs:
|
|
|
13
13
|
- `classified_controversy.json`
|
|
14
14
|
- `classified_discovery.json`
|
|
15
15
|
|
|
16
|
-
If another skill instruction conflicts with this file, this file wins
|
|
16
|
+
If another skill instruction conflicts with this file, **this file wins**.
|
|
17
17
|
|
|
18
18
|
## Command Execution Note
|
|
19
19
|
|
|
@@ -22,20 +22,91 @@ This is a reference-only skill. There is no direct CLI command to run this skill
|
|
|
22
22
|
- Use it by reading this schema before writing any `classified_*.json` output.
|
|
23
23
|
- Runnable commands belong to fetch/analysis/visualize skills (for example `sc-research research:deep "TOPIC"` and `sc-research visualize`).
|
|
24
24
|
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Dashboard Detection Rules
|
|
28
|
+
|
|
29
|
+
The web dashboard auto-detects which classified type a JSON file contains by checking for **unique field signatures**. If required fields are missing or misnamed, that tab will not appear.
|
|
30
|
+
|
|
31
|
+
| Classified Type | Detection Rule (fields checked) | Dashboard Tab |
|
|
32
|
+
| --------------- | ----------------------------------------------------------- | ------------------- |
|
|
33
|
+
| **rank** | `products` (array) AND `key_insights` (array) | Product Rankings |
|
|
34
|
+
| **sentiment** | `distribution` (object) AND `by_source` (object) | Sentiment Analysis |
|
|
35
|
+
| **trend** | `date_range` (object) AND `timeline` (array) | Trend Timeline |
|
|
36
|
+
| **controversy** | `overall_divisiveness` (string) AND `controversies` (array) | Controversy Map |
|
|
37
|
+
| **discovery** | `trending_topics` (array) | Discovery Dashboard |
|
|
38
|
+
|
|
39
|
+
**These field names are non-negotiable.** Renaming, omitting, or nesting them differently will break dashboard detection.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Enum Value Warnings
|
|
44
|
+
|
|
45
|
+
### SentimentLabel (Title Case — used in rank, sentiment, controversy contexts)
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
CORRECT: "Very Positive", "Positive", "Mixed", "Negative"
|
|
49
|
+
WRONG: "very positive", "very_positive", "POSITIVE", "positive", "neutral"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`"neutral"` is NOT a valid SentimentLabel. Use `"Mixed"` instead.
|
|
53
|
+
|
|
54
|
+
### Divisiveness (Title Case — used in controversy)
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
CORRECT: "Low", "Medium", "High"
|
|
58
|
+
WRONG: "low", "medium", "high", "LOW", "MEDIUM", "HIGH"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Discovery sentiment (lowercase — DIFFERENT from SentimentLabel)
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
CORRECT: "positive", "negative", "neutral", "mixed"
|
|
65
|
+
WRONG: "Positive", "Negative", "Neutral", "Mixed", "Very Positive"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Discovery is the ONLY type that uses lowercase sentiment and includes `"neutral"`.
|
|
69
|
+
|
|
70
|
+
### Discovery platform (lowercase)
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
CORRECT: "reddit", "x"
|
|
74
|
+
WRONG: "Reddit", "X", "twitter", "Twitter"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Key Moment significance (lowercase — used in trend)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
CORRECT: "high", "medium", "low"
|
|
81
|
+
WRONG: "High", "Medium", "Low"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Quote context (lowercase — used in rank)
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
CORRECT: "pro", "con", "general"
|
|
88
|
+
WRONG: "Pro", "Con", "General"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
25
93
|
## Canonical Type Definitions
|
|
26
94
|
|
|
27
95
|
```typescript
|
|
96
|
+
// === RANK (classified_rank.json) ===
|
|
97
|
+
// Dashboard detects via: products + key_insights
|
|
98
|
+
|
|
28
99
|
export interface ClassifiedData {
|
|
29
100
|
topic: string;
|
|
30
101
|
source_file?: string;
|
|
31
|
-
products: Product[];
|
|
32
|
-
key_insights: string[];
|
|
102
|
+
products: Product[]; // REQUIRED for dashboard detection
|
|
103
|
+
key_insights: string[]; // REQUIRED for dashboard detection
|
|
33
104
|
}
|
|
34
105
|
|
|
35
106
|
export interface Product {
|
|
36
107
|
rank: number;
|
|
37
108
|
name: string;
|
|
38
|
-
sentiment: SentimentLabel;
|
|
109
|
+
sentiment: SentimentLabel; // Title Case: "Positive", "Mixed", etc.
|
|
39
110
|
mentions: number;
|
|
40
111
|
estimated_engagement_score: number;
|
|
41
112
|
consensus: string;
|
|
@@ -45,7 +116,7 @@ export interface Product {
|
|
|
45
116
|
text: string;
|
|
46
117
|
author: string;
|
|
47
118
|
link: string;
|
|
48
|
-
context?: "pro" | "con" | "general";
|
|
119
|
+
context?: "pro" | "con" | "general"; // lowercase
|
|
49
120
|
}>;
|
|
50
121
|
}
|
|
51
122
|
|
|
@@ -55,16 +126,21 @@ export type SentimentLabel =
|
|
|
55
126
|
| "Mixed"
|
|
56
127
|
| "Very Positive";
|
|
57
128
|
|
|
129
|
+
// === SENTIMENT (classified_sentiment.json) ===
|
|
130
|
+
// Dashboard detects via: distribution + by_source
|
|
131
|
+
|
|
58
132
|
export interface SentimentData {
|
|
59
133
|
topic: string;
|
|
60
134
|
overall_mood: SentimentLabel;
|
|
61
135
|
distribution: {
|
|
62
|
-
|
|
136
|
+
// REQUIRED for dashboard detection
|
|
137
|
+
very_positive: number; // snake_case keys, not camelCase
|
|
63
138
|
positive: number;
|
|
64
139
|
mixed: number;
|
|
65
140
|
negative: number;
|
|
66
141
|
};
|
|
67
142
|
by_source: {
|
|
143
|
+
// REQUIRED for dashboard detection
|
|
68
144
|
reddit: SourceSentiment;
|
|
69
145
|
x: SourceSentiment;
|
|
70
146
|
};
|
|
@@ -87,23 +163,27 @@ export interface ProductSentiment {
|
|
|
87
163
|
text: string;
|
|
88
164
|
author: string;
|
|
89
165
|
link: string;
|
|
90
|
-
sentiment: SentimentLabel;
|
|
166
|
+
sentiment: SentimentLabel; // Title Case
|
|
91
167
|
}>;
|
|
92
168
|
}
|
|
93
169
|
|
|
170
|
+
// === TREND (classified_trend.json) ===
|
|
171
|
+
// Dashboard detects via: date_range + timeline
|
|
172
|
+
|
|
94
173
|
export interface TrendData {
|
|
95
174
|
topic: string;
|
|
96
175
|
date_range: {
|
|
176
|
+
// REQUIRED for dashboard detection
|
|
97
177
|
from: string;
|
|
98
178
|
to: string;
|
|
99
179
|
};
|
|
100
180
|
granularity?: "day" | "week" | "month";
|
|
101
|
-
timeline: TimelinePoint[];
|
|
181
|
+
timeline: TimelinePoint[]; // REQUIRED for dashboard detection
|
|
102
182
|
key_moments: KeyMoment[];
|
|
103
183
|
}
|
|
104
184
|
|
|
105
185
|
export interface TimelinePoint {
|
|
106
|
-
period: string;
|
|
186
|
+
period: string; // Format depends on granularity (see worker skill)
|
|
107
187
|
post_count: number;
|
|
108
188
|
total_engagement: number;
|
|
109
189
|
reddit_posts: number;
|
|
@@ -113,20 +193,23 @@ export interface TimelinePoint {
|
|
|
113
193
|
export interface KeyMoment {
|
|
114
194
|
date: string;
|
|
115
195
|
event: string;
|
|
116
|
-
significance: "high" | "medium" | "low";
|
|
196
|
+
significance: "high" | "medium" | "low"; // lowercase
|
|
117
197
|
url?: string;
|
|
118
198
|
}
|
|
119
199
|
|
|
200
|
+
// === CONTROVERSY (classified_controversy.json) ===
|
|
201
|
+
// Dashboard detects via: overall_divisiveness + controversies
|
|
202
|
+
|
|
120
203
|
export interface ControversyData {
|
|
121
204
|
topic: string;
|
|
122
|
-
overall_divisiveness: "Low" | "Medium" | "High";
|
|
123
|
-
controversies: Controversy[];
|
|
205
|
+
overall_divisiveness: "Low" | "Medium" | "High"; // REQUIRED + Title Case
|
|
206
|
+
controversies: Controversy[]; // REQUIRED for dashboard detection
|
|
124
207
|
}
|
|
125
208
|
|
|
126
209
|
export interface Controversy {
|
|
127
210
|
topic: string;
|
|
128
|
-
heat_score: number;
|
|
129
|
-
divisiveness: "Low" | "Medium" | "High";
|
|
211
|
+
heat_score: number; // 0-100
|
|
212
|
+
divisiveness: "Low" | "Medium" | "High"; // Title Case
|
|
130
213
|
side_a: ControversySide;
|
|
131
214
|
side_b: ControversySide;
|
|
132
215
|
}
|
|
@@ -141,11 +224,14 @@ export interface ControversySide {
|
|
|
141
224
|
}>;
|
|
142
225
|
}
|
|
143
226
|
|
|
227
|
+
// === DISCOVERY (classified_discovery.json) ===
|
|
228
|
+
// Dashboard detects via: trending_topics
|
|
229
|
+
|
|
144
230
|
export interface DiscoveryData {
|
|
145
231
|
topic: string;
|
|
146
232
|
period: string;
|
|
147
233
|
total_posts_analyzed: number;
|
|
148
|
-
trending_topics: DiscoveryTopic[];
|
|
234
|
+
trending_topics: DiscoveryTopic[]; // REQUIRED for dashboard detection
|
|
149
235
|
}
|
|
150
236
|
|
|
151
237
|
export interface DiscoveryTopic {
|
|
@@ -154,20 +240,20 @@ export interface DiscoveryTopic {
|
|
|
154
240
|
description: string;
|
|
155
241
|
category: string;
|
|
156
242
|
engagement_score: number;
|
|
157
|
-
sentiment: "positive" | "negative" | "neutral" | "mixed";
|
|
243
|
+
sentiment: "positive" | "negative" | "neutral" | "mixed"; // lowercase!
|
|
158
244
|
key_posts: KeyPost[];
|
|
159
245
|
highlight_comments: Array<{
|
|
160
246
|
text: string;
|
|
161
247
|
author: string;
|
|
162
248
|
link: string;
|
|
163
|
-
platform: "reddit" | "x";
|
|
249
|
+
platform: "reddit" | "x"; // lowercase
|
|
164
250
|
}>;
|
|
165
251
|
}
|
|
166
252
|
|
|
167
253
|
export interface KeyPost {
|
|
168
254
|
title: string;
|
|
169
255
|
url: string;
|
|
170
|
-
platform: "reddit" | "x";
|
|
256
|
+
platform: "reddit" | "x"; // lowercase
|
|
171
257
|
engagement: number;
|
|
172
258
|
thumbnail?: string;
|
|
173
259
|
}
|