@clawhub-openlark-3793a1586a
Customer acquisition and marketing automation expert.
--- name: auto-acquisition description: Customer acquisition and marketing automation expert. --- # Customer Acquisition & Marketing Automation ## Use Cases - Developing customer acquisition strategies and growth plans - Analyzing target markets and customer profiles - Optimizing conversion funnels and improving conversion rates - Managing and optimizing marketing channels (SEO/SEM/social media/email/content marketing, etc.) - Lead generation and lead nurturing - Marketing automation workflow design and implementation - Customer acquisition cost analysis and ROI optimization ## Core Workflow ### 1. Develop Customer Acquisition Strategy ``` Acquisition Strategy = Target Market + Value Proposition + Channel Selection + Conversion Path ``` **Key Steps:** - Define the Ideal Customer Profile (ICP) - Determine the Unique Value Proposition (UVP) - Select the appropriate mix of acquisition channels - Design the complete path from awareness to conversion **Output Documents:** - Target Customer Profile Document - Value Proposition Framework - Channel Strategy Matrix - Acquisition Funnel Blueprint ### 2. Analyze Target Market **Analysis Methods:** - TAM/SAM/SOM Analysis - Competitor Acquisition Strategy Analysis - Customer Journey Mapping - Market Demand and Pain Point Discovery **Recommended Tools:** - Google Analytics / Adobe Analytics - SimilarWeb / Ahrefs (Competitor Analysis) - Hotjar / FullStory (User Behavior) - Surveys and Interviews ### 3. Optimize Conversion Funnel **Funnel Levels:** ``` Awareness → Interest → Consideration → Conversion → Loyalty ``` **Optimization Strategies:** - A/B Testing Framework - Landing Page Optimization Essentials - CTA Design and Copy Optimization - Trust Elements and Social Proof - Cart/Registration Flow Simplification **Key Metrics:** - CTR (Click-Through Rate) - CVR (Conversion Rate) - CAC (Customer Acquisition Cost) - LTV (Customer Lifetime Value) - LTV/CAC Ratio ### 4. Marketing Channel Management | Channel | Core Metrics | Optimization Focus | |---------|--------------|---------------------| | SEO | Keyword ranking, Organic traffic | Content quality, Technical SEO | | SEM | Quality Score, ROAS | Keywords, Bidding, Creatives | | Social Media | Engagement rate, Follower growth | Content strategy, Posting time | | Email Marketing | Open rate, CTR, Conversion rate | Send time, Personalization, Segmentation | | Content Marketing | Traffic, Time on page, Conversion | Content topics, SEO optimization | | PPC/Paid Ads | CTR, CPC, CAC | Audience targeting, Landing pages | ### 5. Lead Generation **Lead Acquisition Channels:** - Content Marketing (Ebooks, Whitepapers, Case Studies) - Webinars and Online Events - Free Tools/Trials - Social Media Traffic - SEO and Content Traffic **Lead Scoring Model:** ``` Lead Score = Behavioral Score + Demographic/Firmographic Score - Behavioral Score: Downloads, Page views, Registrations, Event participation, etc. - Demographic/Firmographic Score: Job title, Industry, Company size, etc. ``` ### 6. Marketing Automation **Automation Workflow Examples:** - New User Welcome Sequence - Lead Nurturing Workflow - Abandoned Cart Reminders - Churn Prediction and Win-back - Re-purchase Recommendations **Common Tools:** - HubSpot, Marketo, Pardot - Mailchimp, Klaviyo - Zapier, Make (Integromat) --- ## Common Task Templates ### Task: Launch a New Acquisition Campaign 1. Define Goals (KPIs: Sign-ups / Paid conversions / ROI) 2. Identify Target Audience 3. Select Channels and Allocate Budget 4. Create Assets and Landing Pages 5. Set Up Tracking and Attribution 6. Develop a Testing Plan ### Task: Optimize Conversion Funnel 1. Analyze Current Funnel Data 2. Identify the Biggest Drop-off Points 3. Formulate Hypotheses and Optimization Plans 4. Design A/B Tests 5. Implement and Monitor Results ### Task: Build a Lead Nurturing Workflow 1. Define User Stages and Trigger Conditions 2. Develop Content Strategy for Each Stage 3. Configure Automation Workflow 4. Set Up Scoring Rules 5. Monitor and Optimize --- ## Key Considerations - **Data-Driven**: Base all decisions on data, not intuition. - **Continuous Testing**: A/B testing is core to optimization. - **Full-Funnel Perspective**: Focus on the entire user journey, not just isolated touchpoints. - **LTV > CAC**: Ensure customer acquisition cost is lower than customer lifetime value. - **Channel Mix**: Leverage multiple channels synergistically to avoid single-channel dependency.
Extractive AI text summarizer. Automatically extracts the most important sentences from any text using a hybrid TextRank + TF-IDF algorithm.
---
name: text-summarizer
description: Extractive AI text summarizer. Automatically extracts the most important sentences from any text using a hybrid TextRank + TF-IDF algorithm.
---
# Text Summarizer
Condenses long text into a concise summary by extracting the most important sentences. Works on articles, research papers, reports, meeting notes, emails, and any long document. Zero hallucination risk since it extracts exact sentences from the original.
## Use Cases
the user pastes text or a file and asks to summarize, shorten, condense, or extract key points; the user wants to turn a long article/paper/report/notes into a brief overview; the user says 'summarize this', 'TL;DR', 'key points', 'condense', 'extract main ideas'. Supports adjustable length (short 20% / medium 30% / long 50%) and two output formats (bullet points or flowing paragraph).
## Quick Start
**Default (bullet points, medium length):**
```
summarize.py --text "<paste your text here>"
```
**Paragraph format:**
```
summarize.py --text "<text>" --format paragraph
```
**Short summary (20% of original):**
```
summarize.py --text "<text>" --length short
```
**From a file:**
```
summarize.py input.txt
summarize.py input.txt --length long --format paragraph
```
## Algorithm
See [references/algorithms.md](references/algorithms.md) for full details on the hybrid TextRank + TF-IDF approach.
**TL;DR**: The script scores every sentence by (1) TF-IDF term importance and (2) TextRank graph-based importance, then returns the top-ranked sentences. No AI generation — exact sentences from the original are extracted, so there is zero hallucination risk.
## Length Presets
| Flag | Ratio | Best for |
|---|---|---|
| `--length short` | 20% | Headlines, quick scan |
| `--length medium` | 30% | General-purpose (default) |
| `--length long` | 50% | Detailed summaries |
## Output Formats
- **`bullet`** (default): One extracted sentence per line, prefixed with `•`
- **`paragraph`**: A single flowing paragraph of extracted sentences
## What to Summarize
- Articles and blog posts
- Research papers and academic abstracts
- Reports and white papers
- Meeting notes and transcripts
- Long email threads
- Any prose document
## Limitations
- Optimized for English prose. Code, tables, and structured data are treated as plain text.
- Returns original text unchanged if the input has 2 or fewer sentences.
- Single-document only (one article at a time).
FILE:scripts/summarize.py
#!/usr/bin/env python3
"""
Extractive Text Summarizer — TextRank + TF-IDF hybrid algorithm.
Usage:
summarize.py <input_file> [--length {short|medium|long}] [--format {bullet|paragraph}]
summarize.py --text "<text>" [--length {short|medium|long}] [--format {bullet|paragraph}]
Output formats:
bullet — One sentence per line (default)
paragraph — Single flowing paragraph
Length presets:
short — 20% of original sentences
medium — 30% of original sentences
long — 50% of original sentences
"""
import sys
import argparse
import re
import math
from collections import Counter
def tokenize(text):
"""Split text into lowercase words, stripping punctuation."""
return re.findall(r"[a-zA-Z]+", text.lower())
def build_word_freq(sentences):
"""Build word frequency dictionary from sentences."""
freq = Counter()
for sent in sentences:
words = tokenize(sent)
freq.update(words)
# Normalize by max frequency
if freq:
max_freq = max(freq.values())
for word in freq:
freq[word] /= max_freq
return freq
def score_sentences(sentences, freq):
"""Score each sentence using TF-IDF-like weighting."""
scores = {}
for i, sent in enumerate(sentences):
words = tokenize(sent)
score = sum(freq.get(w, 0) for w in words)
# Bonus for sentences near the beginning (news/document convention)
position_weight = 1.0 / (i + 1)
scores[i] = score * (1 + 0.1 * position_weight)
return scores
def textrank_sentences(sentences, damping=0.85, iterations=30):
"""
TextRank algorithm for sentence importance.
Sentences are nodes; edges weighted by word overlap (Jaccard similarity).
"""
n = len(sentences)
if n == 0:
return {}
if n == 1:
return {0: 1.0}
# Tokenize all sentences
tokenized = [set(tokenize(s)) for s in sentences]
# Build adjacency matrix (edge weight = Jaccard similarity)
# Keep top-k edges per node to sparse the graph
k = min(10, n - 1)
adj = {}
for i in range(n):
similarities = []
for j in range(n):
if i == j:
continue
inter = len(tokenized[i] & tokenized[j])
union = len(tokenized[i] | tokenized[j])
if union > 0:
similarities.append((j, inter / union))
similarities.sort(key=lambda x: -x[1])
adj[i] = similarities[:k]
# Initialize scores
scores = {i: 1.0 for i in range(n)}
# TextRank iteration
for _ in range(iterations):
new_scores = {}
for i in range(n):
rank_sum = 0.0
edges = adj[i]
if edges:
total_weight = sum(sim for _, sim in edges)
for j, sim in edges:
out_edges = adj[j]
if out_edges:
out_weight = sum(s for _, s in out_edges)
if out_weight > 0:
rank_sum += damping * sim * scores[j] / out_weight
new_scores[i] = 1 - damping + rank_sum
scores = new_scores
return scores
def summarize_text(text, length_preset="medium", output_format="bullet", min_sentences=1):
"""
Main summarization function.
Args:
text: Raw input text.
length_preset: 'short' (20%), 'medium' (30%), or 'long' (50%).
output_format: 'bullet' (one sentence per line) or 'paragraph'.
min_sentences: Minimum number of sentences to return.
Returns:
Summary string.
"""
# Split into sentences using heuristics (periods, exclamation, question marks)
# that are not abbreviations
sentences = re.split(r'(?<=[.!?])\s+', text.strip())
sentences = [s.strip() for s in sentences if s.strip()]
if len(sentences) <= 2:
return text.strip()
# Determine how many sentences to extract
length_map = {"short": 0.20, "medium": 0.30, "long": 0.50}
ratio = length_map.get(length_preset, 0.30)
target_count = max(min_sentences, round(len(sentences) * ratio))
# Build word frequency
freq = build_word_freq(sentences)
# Score with TF-IDF
tfidf_scores = score_sentences(sentences, freq)
# Score with TextRank
tr_scores = textrank_sentences(sentences)
# Normalize both score sets to [0, 1] and combine
def normalize(scores_dict):
vals = list(scores_dict.values())
mn, mx = min(vals), max(vals)
if mx == mn:
return {k: 0.5 for k in scores_dict}
return {k: (v - mn) / (mx - mn) for k, v in scores_dict.items()}
norm_tfidf = normalize(tfidf_scores)
norm_tr = normalize(tr_scores)
# Weighted combination: 40% TF-IDF, 60% TextRank
combined = {i: 0.4 * norm_tfidf[i] + 0.6 * norm_tr[i] for i in range(len(sentences))}
# Pick top-N sentences, sorted by original order
ranked = sorted(combined.items(), key=lambda x: -x[1])
top_indices = sorted([idx for idx, _ in ranked[:target_count]])
summary_sentences = [sentences[i] for i in top_indices]
if output_format == "paragraph":
return " ".join(summary_sentences)
else: # bullet
return "\n".join(f"• {s}" for s in summary_sentences)
def main():
parser = argparse.ArgumentParser(description="Extractive text summarizer")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--text", metavar="TEXT", help="Text to summarize directly")
group.add_argument("input_file", nargs="?", metavar="input_file", help="File to summarize")
parser.add_argument(
"--length",
choices=["short", "medium", "long"],
default="medium",
help="Summary length (default: medium)",
)
parser.add_argument(
"--format",
dest="format",
choices=["bullet", "paragraph"],
default="bullet",
help="Output format (default: bullet)",
)
args = parser.parse_args()
if args.input_file:
try:
text = open(args.input_file, "r", encoding="utf-8").read()
except UnicodeDecodeError:
# Fallback to system encoding
text = open(args.input_file, "r", encoding="utf-8", errors="replace").read()
else:
text = args.text
result = summarize_text(text, length_preset=args.length, output_format=args.format)
print(result)
if __name__ == "__main__":
main()
FILE:references/algorithms.md
# Extractive Summarization Algorithm Reference
## Overview
This skill uses **extractive summarization** — it selects and extracts the most important sentences directly from the original text. Unlike abstractive methods, extractive summarization never invents new words or rephrases ideas, so it has **zero hallucination risk**.
## Algorithm: Hybrid TextRank + TF-IDF
The summarizer combines two well-established NLP algorithms:
### 1. TF-IDF Scoring
**TF-IDF** (Term Frequency – Inverse Document Frequency) measures how important a word is within a document.
- **TF** (Term Frequency): How often a word appears in the document, normalized by the maximum word frequency.
- **IDF** (Inverse Document Frequency): In single-document mode (as here), we treat each sentence as a mini-document. Words that appear in many sentences are penalized.
**Sentence score** = sum of TF-IDF weights for all words in the sentence.
Words unique to a sentence → high score. Common words (the, is, and) → low score.
### 2. TextRank Graph Ranking
TextRank is inspired by Google's PageRank. It treats each sentence as a node in a graph:
1. **Edge weight** between sentence *i* and *j* = Jaccard similarity of their word sets
`Jaccard(A, B) = |A ∩ B| / |A ∪ B|`
2. For each node, keep only the top-K (≤10) most similar neighbors to sparse the graph.
3. Run PageRank-style iterations (damping factor = 0.85, 30 iterations) to assign each sentence a global importance score.
Sentences that are similar to many other important sentences get ranked highest.
### 3. Hybrid Combination
Final score = `0.4 × normalized_TF-IDF + 0.6 × normalized_TextRank`
The 60/40 weighting toward TextRank reflects TextRank's ability to capture contextual importance and sentence relationships, while TF-IDF provides a complementary signal about term specificity.
## Why These Algorithms Work
| Property | TF-IDF | TextRank |
|---|---|---|
| Captures term specificity | ✅ | ❌ |
| Captures sentence relationships | ❌ | ✅ |
| Handles long documents | ✅ | ✅ |
| Deterministic | ✅ | ✅ |
| Zero hallucination | ✅ | ✅ |
## Length Presets
| Preset | Ratio | Use Case |
|---|---|---|
| short | 20% | Quick overview, headlines |
| medium | 30% | General-purpose default |
| long | 50% | Detailed summaries, when more coverage is needed |
## Limitations
- **Single-document only**: This implementation treats the input as one document. Cross-document summarization (e.g., multi-article) is not supported.
- **Language**: Optimized for English. Multilingual support (Chinese, etc.) requires a different tokenization strategy.
- **Code/structured content**: Not designed for code, tables, or structured data. Treats everything as prose.
- **Very short inputs**: Returns original text if ≤ 2 sentences are detected.
AI-powered English grammar, spelling, and style checker.
---
name: grammar-checker
description: AI-powered English grammar, spelling, and style checker.
---
# Grammar Checker
## Overview
Check and improve English text for grammar, spelling, punctuation, style, and clarity. For each issue found, explain the error and provide a corrected version.
## Use Cases
Use when the user asks to "check grammar", "fix grammar errors", "check spelling", "improve writing", "grammar checker", "check my text", "proofread", "English grammar check", or when they paste text and ask to find errors. Also use for style suggestions, clarity improvements, and punctuation corrections. Supports emails, essays, blog posts, business documents, and any English writing.
## How to Use
1. Receive the user's text
2. Analyze it using the detailed grammar categories in `references/check_categories.md`
3. For each issue found, report:
- **Category**: Grammar / Spelling / Punctuation / Style / Clarity
- **Original**: the problematic text
- **Explanation**: why it's an error
- **Correction**: the recommended fix
4. Provide a fully corrected version at the end
## Output Format
```
## 🔍 Grammar Check Report
### Errors Found: N
---
**1. [Category] — [Error Type]**
> "Original text with error"
**Why it's wrong:** Explanation
**Fix:** "Corrected text"
---
### ✏️ Full Corrected Version
[Complete corrected text]
### 📝 Summary
- Grammar issues: N
- Spelling issues: N
- Punctuation issues: N
- Style suggestions: N
- Clarity improvements: N
```
## Response Guidelines
- Be precise: quote the exact original phrase/word in the report
- Explain briefly: one clear sentence per error explaining the rule
- Correct confidently: if unsure, mark as "sounds awkward" rather than wrong
- Keep corrections conservative: don't over-edit — preserve the author's voice and meaning
- Prioritize clarity: prefer shorter, clearer sentences over complex rewrites
- For very long texts (>1000 words), summarize key patterns and provide a partial corrected version + overall feedback
FILE:references/check_categories.md
# Grammar Check Categories Reference
Detailed categories and examples for comprehensive grammar checking.
## 1. Grammar Error Detection
### Subject-Verb Agreement
- "He **go** to school" → "He **goes** to school"
- "The team **are** playing well" → depends on context (US: team = singular; UK: team = plural)
- "Each of us **have** a responsibility" → "Each of us **has** a responsibility"
- Collective nouns: "The committee **has** decided" (US) / "The committee **have** decided" (UK)
### Tense Inconsistencies
- Mixed past and present in the same paragraph without clear reason
- "She **walked** into the room and **notices** that something is wrong"
- Perfect vs. simple past: "I **have seen** the movie yesterday" → "I **saw** the movie yesterday"
### Misplaced Modifiers
- "She served sandwiches to the children on paper plates" (ambiguous — are the children on paper plates?)
- **Fix:** "She served sandwiches on paper plates to the children"
### Dangling Participles
- "Walking down the street, the trees were beautiful" (trees aren't walking)
- **Fix:** "Walking down the street, I noticed that the trees were beautiful"
### Run-on Sentences / Comma Splices
- "I love reading I also enjoy writing" → "I love reading. I also enjoy writing."
- Comma splice: "I love reading, it is my favorite hobby" → "I love reading; it is my favorite hobby."
### Incorrect Word Usage
- **affect/effect**: "The drug **affected** my mood" (verb) / "The **effect** was subtle" (noun)
- **fewer/less**: "**Fewer** items" (countable) / "**Less** sugar" (uncountable)
- **who/whom**: "**Who** do you think is calling?" / "**Whom** did you call?"
- **lay/lie**: "**Lay** the book on the table" (transitive, requires object) / "**Lie** down here" (intransitive)
- **set/sit**: "**Set** the cup down" (transitive) / "**Sit** here" (intransitive)
## 2. Spelling & Typo Correction
### Commonly Confused Homophones
| Wrong | Correct | Example |
|-------|---------|---------|
| their/there/they're | context-dependent | "They're going **there** to see **their** friends" |
| your/you're | context-dependent | "**You're** amazing — I love **your** work" |
| its/it's | context-dependent | "It's raining. The dog wagged its tail." |
| to/too/two | context-dependent | "I want to go too — I have two options" |
| than/then | context-dependent | "Better **than** before; **then** I understood" |
| accept/except | context-dependent | "I **accept** all **except** one" |
| affect/effect | context-dependent | See above |
| their/there | context-dependent | See above |
### Common Misspellings
- "definitely" (not "definately")
- "occurrence" (not "occurence")
- "separate" (not "seperate")
- "necessary" (not "neccessary")
- "embarrass" (not "embarass")
- "conscience" (not "consious")
- "judgment" (not "judgement" in US English)
- "privilege" (not "priviledge")
- "perseverance" (not "perserverance")
- "millennium" (not "milennium")
### Contractions vs. Possessives
- "it's" = "it is" (contraction)
- "its" = belonging to it (possessive, no apostrophe)
## 3. Punctuation Check
### Missing Commas
- After an introductory phrase: "After dinner, we went for a walk."
- Between coordinate clauses: "I called her, but she didn't answer."
- In a series of three or more: "apples, oranges, and bananas"
- After a non-restrictive clause: "My brother, who lives in London, is visiting."
### Comma Splices
- Two independent clauses joined by a comma only → use semicolon, period, or conjunction
- "The sun was setting, the birds were singing." → "The sun was setting; the birds were singing."
### Apostrophe Errors
- Possessive singular: "James's book" (or "James' book" in some styles)
- Possessive plural ending in -s: "the dogs' paws"
- Plural not possessive: "three cats' whiskers" (three cats — plural, plus apostrophe for possession)
- It's vs. its confusion
### Quotation Marks
- American style: periods and commas go inside quotation marks
- British style: periods may go outside if not part of the original quote
- Single quotes for nested quotations
- Punctuation with quotes: "She said 'hello'." vs. Did she say "hello"?
### Hyphenation
- Compound adjectives before nouns: "a well-known author" (but "the author is well known")
- Numbers + nouns: "a five-year-old child"
- Common compounds: "real-time", "decision-making", "cost-effective"
### Semicolon vs. Colon
- Semicolon: links two independent clauses that are related
- Colon: introduces a list, explanation, or quote
- "I have three goals: learn, grow, and succeed."
### Dash vs. Hyphen vs. Em-dash
- Hyphen: word compounds (well-known)
- Em-dash: sentence interruption — use `—` or `--`
## 4. Style Suggestions
### Passive Voice
- Passive: "The report **was written by** Sarah"
- Active: "Sarah **wrote** the report"
- Passive is acceptable when the actor is unknown, unimportant, or intentionally de-emphasized
### Overly Complex Sentences
- Sentences >30 words should be examined
- Break into shorter sentences for clarity
- One idea per sentence is ideal
### Redundant Phrases
| Redundant | Concise |
|-----------|---------|
| "past history" | "history" |
| "free gift" | "gift" |
| "unexpected surprise" | "surprise" |
| "completely eliminate" | "eliminate" |
| "true fact" | "fact" |
| "close proximity" | "proximity" |
| "repeat again" | "repeat" |
| "future plans" | "plans" |
| "basic fundamentals" | "fundamentals" |
| "advance warning" | "warning" |
### Wordiness
- "In order to" → "To"
- "Due to the fact that" → "Because"
- "At this point in time" → "Now"
- "In the event that" → "If"
- "Has the ability to" → "Can"
### Filler Words
- "very", "really", "just", "quite", "basically", "literally" (often unnecessary)
- Exception: if the word adds genuine emphasis
## 5. Clarity Improvements
### Ambiguous References
- "When John met Mary, she seemed happy" — unclear who "she" is
- **Fix:** Name the person explicitly
### Dangling Pronouns
- "They say that the exam is difficult" — who are "they"?
- "This" / "that" without clear referent
### Double Negatives
- "I don't have nothing" → "I have nothing" or "I don't have anything"
- Exception: emphatic double negatives in some contexts ("I can't not go")
### Mixed Constructions
- "The reason is because" → "The reason is that"
- "Due to the fact that" → "Because"
- "In spite of the fact that" → "Although"
### Illogical Comparisons
- "My car is faster than any other car" (correct)
- "My car is faster than any car" (illogical — it's a car itself)
- "Between you and I" → "Between you and me" (prepositions take objective pronouns)
### Parallel Structure
- Lists should maintain grammatical parallelism:
- ❌ "I like swimming, to run, and biking"
- ✅ "I like swimming, running, and biking"
## 6. Additional Checks
### Capitalization
- Proper nouns, beginnings of sentences, titles (depending on style guide)
- "internet" → "Internet" (capitalized in many style guides)
### Numbers
- Spell out one through nine; use numerals for 10 and above
- Exceptions: ages, dates, percentages, measurements
### Article Usage (for non-native speakers)
- Definite article "the": specific, known to both parties
- Indefinite article "a/an": general, first mention
- Zero article: languages, nationalities, abstract nouns
- "I went to **the park** (specific) vs. I went to **a park** (any park)"
### Preposition Usage
- Common errors: "interested **in**" (not "interested **on**")
- "different **from**" (not "different **than**")
- "compare **to/with**" (compare to = show similarity; compare with = analyze differences)
### Conjunction Consistency
- Correlative conjunctions: "both...and", "either...or", "neither...nor", "not only...but also"
- Must match: "Both the price **and** quality" (not "both the price **and** also quality")
Detect text originality and AI-generated content.
---
name: plagiarism-checker
description: Detect text originality and AI-generated content.
---
# Plagiarism Checker
Detect whether text is plagiarized or AI-generated. Provides content originality analysis to help identify copied content and machine-generated text.
## Use Cases
Use this skill when users mention "plagiarism check," "detect plagiarism," "check AI rate," "article originality," "text originality detection," "content originality degree," or request similarity/AI rate analysis for a piece of text.
## Core Script
Use `scripts/check_plagiarism.py` to perform detection:
```bash
python scripts/check_plagiarism.py --text "Text content to detect"
```
Optional parameters:
- `--text`: Text to detect (required, or use `--file`)
- `--file`: Read text from file (.txt, .md, .docx)
- `--output`: Output report path (prints to terminal by default)
**Windows Example:**
```powershell
python scripts/check_plagiarism.py --text "Your text here..."
```
## Output Format
The script returns a structured report:
```
=== Originality Detection Report ===
Originality Score: 92%
AI Generation Probability: 12%
[Paragraph Analysis]
✓ Paragraph 1: Original content, no match
⚠ Paragraph 2: 47% similarity, rewriting recommended
⚠ Paragraph 3: 31% AI generation probability
```
## References
- `references/detection-guide.md` — Detection methods, threshold standards, and best practices
- `references/report-template.md` — Report template and examples
## Workflow
1. **Collect Text**: User pastes text or uploads a file
2. **Execute Detection**: Run `check_plagiarism.py`
3. **Interpret Report**: Provide recommendations based on originality score and AI probability
4. **Provide Rewriting Suggestions**: Offer optimization advice for low-scoring paragraphs
FILE:scripts/check_plagiarism.py
#!/usr/bin/env python3
"""
Plagiarism Checker & AI Detector
Detects copied content and AI-generated text.
"""
import sys
import argparse
import re
from collections import Counter
import math
from pathlib import Path
# ── AI Detection heuristics ──────────────────────────────────────────────────
def compute_burstiness(text: str) -> float:
"""Sentence length variance — high variance = human-like."""
sentences = re.split(r'[.!?]+', text)
sentences = [s.strip() for s in sentences if len(s.strip()) > 10]
if len(sentences) < 2:
return 0.0
lengths = [len(s.split()) for s in sentences]
mean = sum(lengths) / len(lengths)
variance = sum((l - mean) ** 2 for l in lengths) / len(lengths)
return math.sqrt(variance) / max(mean, 1)
def compute_lexical_diversity(text: str) -> float:
"""Type-token ratio — human text tends to be more varied."""
words = re.findall(r'\b\w+\b', text.lower())
if not words:
return 0.0
return len(set(words)) / len(words)
def compute_avg_word_length(text: str) -> float:
"""Average word length — AI often uses slightly longer words."""
words = re.findall(r'\b\w+\b', text)
if not words:
return 0.0
return sum(len(w) for w in words) / len(words)
def ai_probability(text: str) -> float:
"""
Estimate AI-generation probability using heuristics.
Returns a float 0.0–1.0.
"""
if len(text) < 50:
return 0.5 # Too short to judge
burst = compute_burstiness(text)
ldiv = compute_lexical_diversity(text)
awl = compute_avg_word_length(text)
# Heuristic scoring
score = 0.0
# Low burstiness → higher AI probability
if burst < 4:
score += 0.3
elif burst < 8:
score += 0.15
# Low lexical diversity → higher AI probability
if ldiv < 0.45:
score += 0.3
elif ldiv < 0.55:
score += 0.15
# Unusually uniform sentence lengths
sentences = re.split(r'[.!?]+', text)
sentences = [s.strip() for s in sentences if len(s.strip()) > 10]
if len(sentences) >= 3:
word_counts = [len(s.split()) for s in sentences]
if max(word_counts) - min(word_counts) < 4:
score += 0.2
# Repeated common AI phrases
ai_phrases = [
"it's important to note", "in conclusion", "additionally",
"furthermore", "moreover", "in summary", "in today's world",
"as mentioned earlier", "on the other hand", "in other words",
"as a result", "due to the fact", "it is worth noting",
"in this regard", "ultimately"
]
phrase_count = sum(1 for phrase in ai_phrases if phrase.lower() in text.lower())
score += min(phrase_count * 0.05, 0.2)
return min(score, 1.0)
# ── Plagiarism / similarity detection ───────────────────────────────────────
def ngrams(text: str, n: int = 3):
words = re.findall(r'\b\w+\b', text.lower())
return [' '.join(words[i:i+n]) for i in range(len(words) - n + 1)]
def similarity(text1: str, text2: str) -> float:
"""Jaccard similarity between two texts based on trigrams."""
ng1 = set(ngrams(text1))
ng2 = set(ngrams(text2))
if not ng1 or not ng2:
return 0.0
inter = len(ng1 & ng2)
union = len(ng1 | ng2)
return inter / union if union > 0 else 0.0
def originality_score(text: str, database: list[str] | None = None) -> float:
"""
Compute originality score.
Without an external DB, this uses internal heuristics.
Returns 0.0–1.0 (higher = more original).
"""
if not database:
# Self-similarity check: split into halves and compare
words = re.findall(r'\b\w+\b', text.lower())
mid = len(words) // 2
if mid < 10:
return 0.8 # Too short to measure
first_half = ' '.join(words[:mid])
second_half = ' '.join(words[mid:])
internal_sim = similarity(first_half, second_half)
return max(0.0, 1.0 - internal_sim * 1.5)
else:
max_sim = max(similarity(text, ref) for ref in database)
return max(0.0, 1.0 - max_sim)
# ── Paragraph analysis ───────────────────────────────────────────────────────
def analyze_paragraphs(text: str, database: list[str] | None = None):
"""Break text into paragraphs and score each."""
paragraphs = [p.strip() for p in re.split(r'\n\s*\n', text) if p.strip()]
results = []
for i, para in enumerate(paragraphs, 1):
orig = originality_score(para, database)
ai = ai_probability(para)
if orig >= 0.85 and ai <= 0.20:
flag = "PASS"
elif orig >= 0.60 or ai <= 0.50:
flag = "WARN"
else:
flag = "FAIL"
results.append({
"index": i,
"preview": para[:60] + ("..." if len(para) > 60 else ""),
"originality": orig,
"ai_prob": ai,
"flag": flag,
})
return results
# ── Report ────────────────────────────────────────────────────────────────────
def print_report(text: str, database: list[str] | None = None):
ai = ai_probability(text)
orig = originality_score(text, database)
paras = analyze_paragraphs(text, database)
word_count = len(re.findall(r'\b\w+\b', text))
char_count = len(text)
# Risk level
if orig >= 0.85 and ai <= 0.20:
risk, emoji = "Low Risk", "🟢"
elif orig >= 0.60 or ai <= 0.50:
risk, emoji = "Medium Risk", "🟡"
elif orig >= 0.30 or ai <= 0.75:
risk, emoji = "High Risk", "🟠"
else:
risk, emoji = "Critical", "🔴"
print()
print("═" * 60)
print(" Content Originality & AI Detection Report")
print("═" * 60)
print(f"📝 Text Overview")
print(f" Word Count: {word_count}")
print(f" Character Count: {char_count}")
print(f" Paragraph Count: {len(paras)}")
print()
print(f"📊 Comprehensive Score")
print(f" Originality: {orig*100:.0f}%")
print(f" AI Generation Probability: {ai*100:.0f}%")
print(f" Risk Level: {emoji} {risk}")
print()
print("─" * 60)
print("Paragraph Analysis")
print("─" * 60)
for p in paras:
flag_icon = {"PASS": "✅", "WARN": "⚠️", "FAIL": "❌"}[p["flag"]]
print(f" {flag_icon} Paragraph {p['index']}: Originality {p['originality']*100:.0f}% | AI {p['ai_prob']*100:.0f}%")
print(f" → {p['preview']}")
print()
print("─" * 60)
print("Recommendations")
print("─" * 60)
fail_paras = [p for p in paras if p["flag"] in ("WARN", "FAIL")]
if not fail_paras:
print(" ✅ No issues found. Content is ready for use.")
else:
for p in fail_paras:
if p["ai_prob"] > 0.50:
print(f" Paragraph {p['index']}: AI generation probability is high. Recommend enriching sentence variety and adding specific examples or data.")
if p["originality"] < 0.60:
print(f" Paragraph {p['index']}: Similarity is high. Recommend adding original analysis and unique perspective.")
print()
print("═" * 60)
print("⚠️ Note: This tool is based on statistical heuristics. Results are for")
print(" reference only and should not be used as the basis for any")
print(" academic or legal decisions.")
print("═" * 60)
print()
# ── CLI ───────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(description="Plagiarism Checker & AI Detector")
parser.add_argument("--text", type=str, help="Text to check")
parser.add_argument("--file", type=str, help="File path to read (.txt, .md)")
parser.add_argument("--db", type=str, help="Reference text file (one URL/per line)")
args = parser.parse_args()
if not args.text and not args.file:
parser.print_help()
sys.exit(1)
if args.file:
path = Path(args.file)
if not path.exists():
print(f"Error: File does not exist → {path}", file=sys.stderr)
sys.exit(1)
text = path.read_text(encoding="utf-8")
else:
text = args.text
if not text.strip():
print("Error: Text is empty", file=sys.stderr)
sys.exit(1)
if len(text) < 30:
print("Error: Text too short (at least 30 characters)", file=sys.stderr)
sys.exit(1)
database = None
if args.db:
db_path = Path(args.db)
if db_path.exists():
database = [line.strip() for line in db_path.read_text(encoding="utf-8").splitlines() if line.strip()]
print_report(text, database)
if __name__ == "__main__":
main()
FILE:references/detection-guide.md
# Detection Guide
## Detection Threshold Standards
| Originality | AI Probability | Risk Level | Recommendation |
|-------------|----------------|------------|----------------|
| ≥ 85% | < 20% | 🟢 Low Risk | Pass, suitable for submission |
| 60–84% | 20–50% | 🟡 Medium Risk | Recommend rewriting high-similarity paragraphs |
| 30–59% | 50–75% | 🟠 High Risk | Requires substantial rewriting or addition of original content |
| < 30% | > 75% | 🔴 Extremely High Risk | Severe plagiarism or nearly pure AI generation |
## Detection Methods
### 1. String Matching (SimHash / n-gram)
- Segment text into n-gram phrases (n=3~5)
- Compute SimHash fingerprints
- Compare against pre-built database, calculate Hamming distance
### 2. AI Generation Detection (Statistical Features)
- **Perplexity**: The difficulty level for a language model to predict the text
- **Burstiness**: Variance in sentence length; high burstiness = more human-like
- **Vocabulary Distribution**: AI tends to use high-frequency words; human vocabulary is more dispersed
### 3. Semantic Similarity (Sentence Transformers)
- Use `all-MiniLM-L6-v2` to compute sentence vectors
- Cosine similarity > 0.85 is considered highly similar
## Best Practices
1. Text must be **at least 100 words** for statistical significance
2. **Quoted portions** will be flagged; sources must be noted in the report
3. **Technical terminology** may produce false positives (universally used academic terms)
4. **Hybrid detection** is more accurate than any single method
FILE:references/report-template.md
# Detection Report Template
## Report Structure
```
═══════════════════════════════════════════════════════════
Content Originality & AI Detection Report
═══════════════════════════════════════════════════════════
📝 Text Overview
Word Count: {word_count}
Character Count: {char_count}
Paragraph Count: {para_count}
📊 Comprehensive Score
Originality: {originality}%
AI Generation Probability: {ai_prob}%
Risk Level: {risk_emoji} {risk_level}
───────────────────────────────────────────────────────────
Paragraph Analysis
───────────────────────────────────────────────────────────
{paragraph_analysis}
───────────────────────────────────────────────────────────
Recommendations
───────────────────────────────────────────────────────────
{recommendations}
═══════════════════════════════════════════════════════════
Report Generated: {timestamp}
═══════════════════════════════════════════════════════════
```
## Example Report
```
═══════════════════════════════════════════════════════════
Content Originality & AI Detection Report
═══════════════════════════════════════════════════════════
📝 Text Overview
Word Count: 486
Character Count: 2341
Paragraph Count: 4
📊 Comprehensive Score
Originality: 78%
AI Generation Probability: 35%
Risk Level: 🟡 Medium Risk
───────────────────────────────────────────────────────────
Paragraph Analysis
───────────────────────────────────────────────────────────
✅ Paragraph 1 (0-120 words): Original content, no significant match
⚠️ Paragraph 2 (121-280 words): 42% similarity
Match Source: Web/article-123 (38%), Blog/tech-post (4%)
⚠️ Paragraph 3 (281-390 words): 51% AI probability
Features: Low burstiness, high-frequency vocabulary, mechanical sentence patterns
✅ Paragraph 4 (391-486 words): Original content, no significant match
───────────────────────────────────────────────────────────
Recommendations
───────────────────────────────────────────────────────────
1. Paragraph 2: Recommend rewriting, add personal analysis and unique perspective
2. Paragraph 3: Recommend enriching sentence variety, incorporating specific examples
3. Overall: Add more original viewpoints and firsthand experience
═══════════════════════════════════════════════════════════
Report Generated: 2026-04-13 11:10 CST
═══════════════════════════════════════════════════════════
```
## Rewriting Suggestion Template
For each high-risk paragraph, provide:
1. **Problem Description**: "This paragraph has X% similarity with a certain source"
2. **Rewriting Direction**: "Recommend re-articulating from the perspective of personal experience / cases / data"
3. **Example Phrasing**: Provide 2-3 rewriting examplesA comprehensive text analysis tool that counts words, characters, sentences, and paragraphs. Calculates reading time, speaking time, reading level (Flesch-Ki...
---
name: word-counter
description: A comprehensive text analysis tool that counts words, characters, sentences, and paragraphs. Calculates reading time, speaking time, reading level (Flesch-Kincaid), and keyword density.
---
# Word Counter
## Overview
This skill provides comprehensive text analysis including word count, character count, sentence/paragraph count, reading/speaking time estimates, readability scoring, and keyword density analysis.
## Use Cases
Use when users need to analyze text length, check word count for essays/blogs/social media posts, estimate reading time, assess readability, or analyze keyword frequency for SEO content.
## Capabilities
1. **Word Count** - Accurate word counting handling multiple spaces, line breaks, and special characters
2. **Character Count** - With and without spaces (useful for Twitter, meta descriptions)
3. **Sentence & Paragraph Count** - Track document structure
4. **Reading Time** - Based on 200 words/minute average
5. **Speaking Time** - Based on 130 words/minute natural pace
6. **Reading Level** - Flesch-Kincaid grade level estimation
7. **Keyword Density** - Top keywords ranked by frequency for SEO analysis
## Common Word Count Requirements
| Content Type | Word Count | Reading Time |
|--------------|------------|--------------|
| X (Twitter) post | 40-50 | < 1 min |
| Facebook post | 40-80 | < 1 min |
| LinkedIn post | 50-100 | < 1 min |
| Email subject line | 6-10 | < 1 min |
| Meta description | 25-30 | < 1 min |
| Short blog post | 300-600 | 2-3 min |
| Standard blog post | 1,000-1,500 | 5-7 min |
| Long-form article | 2,000-3,000 | 10-15 min |
| College essay | 500-5,000 | 3-25 min |
## Usage
### Basic Analysis
```python
from scripts.word_counter import analyze_text
result = analyze_text("Your text here...")
print(result)
```
### Command Line
```bash
python scripts/word_counter.py "Your text here"
# or
python scripts/word_counter.py --file path/to/file.txt
```
## Scripts
- `scripts/word_counter.py` - Main text analysis script
## References
- `references/formulas.md` - Detailed formulas for reading level and time calculations
FILE:scripts/word_counter.py
#!/usr/bin/env python3
"""
Word Counter - Comprehensive text analysis tool
Counts words, characters, sentences, paragraphs, calculates reading/speaking time,
reading level (Flesch-Kincaid), and keyword density.
Usage:
python word_counter.py "Your text here"
python word_counter.py --file path/to/file.txt
python word_counter.py --json "Your text here"
"""
import re
import sys
import argparse
import json
from collections import Counter
from typing import Dict, Any
def count_words(text: str) -> int:
"""Count words in text, handling multiple spaces and special characters."""
# Remove extra whitespace and split
words = text.strip().split()
return len(words)
def count_characters(text: str) -> Dict[str, int]:
"""Count characters with and without spaces."""
return {
'with_spaces': len(text),
'without_spaces': len(text.replace(' ', '').replace('\n', '').replace('\t', ''))
}
def count_sentences(text: str) -> int:
"""Count sentences based on sentence-ending punctuation."""
# Split by sentence-ending punctuation
sentences = re.split(r'[.!?]+', text)
# Filter out empty strings
sentences = [s.strip() for s in sentences if s.strip()]
return len(sentences)
def count_paragraphs(text: str) -> int:
"""Count paragraphs based on line breaks."""
# Split by double newlines or more
paragraphs = re.split(r'\n\s*\n', text.strip())
# Filter out empty paragraphs
paragraphs = [p.strip() for p in paragraphs if p.strip()]
return len(paragraphs) if paragraphs else 1
def calculate_reading_time(word_count: int, wpm: int = 200) -> Dict[str, Any]:
"""Calculate reading time based on words per minute."""
minutes = word_count / wpm
return {
'minutes': round(minutes, 2),
'seconds': round(minutes * 60, 1),
'display': format_time(minutes)
}
def calculate_speaking_time(word_count: int, wpm: int = 130) -> Dict[str, Any]:
"""Calculate speaking time based on words per minute."""
minutes = word_count / wpm
return {
'minutes': round(minutes, 2),
'seconds': round(minutes * 60, 1),
'display': format_time(minutes)
}
def format_time(minutes: float) -> str:
"""Format time in human-readable format."""
if minutes < 1:
seconds = int(minutes * 60)
return f"{seconds} sec"
elif minutes < 60:
mins = int(minutes)
secs = int((minutes - mins) * 60)
if secs > 0:
return f"{mins} min {secs} sec"
return f"{mins} min"
else:
hours = int(minutes / 60)
mins = int(minutes % 60)
if mins > 0:
return f"{hours} hr {mins} min"
return f"{hours} hr"
def calculate_flesch_kincaid(text: str, word_count: int, sentence_count: int) -> Dict[str, Any]:
"""
Calculate Flesch-Kincaid reading level.
Formula: 0.39 * (words/sentences) + 11.8 * (syllables/words) - 15.59
Grade levels:
- 6-8: General audience
- 10+: Academic writing
"""
if sentence_count == 0 or word_count == 0:
return {'grade_level': 0, 'difficulty': 'Unknown'}
# Estimate syllables (simplified algorithm)
syllable_count = estimate_syllables(text)
avg_words_per_sentence = word_count / sentence_count
avg_syllables_per_word = syllable_count / word_count
grade_level = 0.39 * avg_words_per_sentence + 11.8 * avg_syllables_per_word - 15.59
grade_level = max(0, round(grade_level, 1))
# Determine difficulty
if grade_level <= 6:
difficulty = "Easy"
elif grade_level <= 8:
difficulty = "Standard"
elif grade_level <= 12:
difficulty = "Moderate"
else:
difficulty = "Advanced"
return {
'grade_level': grade_level,
'difficulty': difficulty,
'avg_words_per_sentence': round(avg_words_per_sentence, 1),
'avg_syllables_per_word': round(avg_syllables_per_word, 2)
}
def estimate_syllables(text: str) -> int:
"""Estimate syllable count using vowel group counting."""
text = text.lower()
# Remove non-alphabetic characters
text = re.sub(r'[^a-z\s]', '', text)
words = text.split()
total_syllables = 0
for word in words:
if not word:
continue
# Count vowel groups
syllables = len(re.findall(r'[aeiouy]+', word))
# Every word has at least one syllable
syllables = max(1, syllables)
# Silent e handling (simplified)
if word.endswith('e') and syllables > 1:
syllables -= 1
total_syllables += syllables
return total_syllables
def calculate_keyword_density(text: str, top_n: int = 10) -> list:
"""Calculate keyword density (frequency of words)."""
# Convert to lowercase and extract words
words = re.findall(r'\b[a-zA-Z]{3,}\b', text.lower())
# Common stop words to exclude
stop_words = {
'the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'can', 'had', 'her', 'was',
'one', 'our', 'out', 'day', 'get', 'has', 'him', 'his', 'how', 'its', 'may', 'new',
'now', 'old', 'see', 'two', 'who', 'boy', 'did', 'she', 'use', 'her', 'way', 'many',
'oil', 'sit', 'set', 'run', 'eat', 'far', 'sea', 'eye', 'ago', 'off', 'too', 'any',
'say', 'man', 'try', 'ask', 'end', 'why', 'let', 'put', 'say', 'she', 'try', 'way',
'own', 'say', 'too', 'old', 'tell', 'very', 'when', 'come', 'here', 'just', 'like',
'long', 'make', 'over', 'such', 'take', 'than', 'them', 'well', 'were', 'will', 'with',
'have', 'this', 'that', 'from', 'they', 'know', 'want', 'been', 'good', 'much', 'some',
'time', 'very', 'when', 'come', 'here', 'just', 'like', 'long', 'make', 'over', 'such',
'take', 'than', 'them', 'well', 'were', 'what', 'would', 'there', 'their', 'said',
'each', 'which', 'about', 'could', 'other', 'after', 'first', 'never', 'these', 'think',
'where', 'being', 'every', 'great', 'might', 'shall', 'still', 'those', 'while', 'your'
}
# Filter out stop words
filtered_words = [w for w in words if w not in stop_words]
if not filtered_words:
return []
# Count word frequencies
word_counts = Counter(filtered_words)
total_words = len(filtered_words)
# Calculate density and return top N
keywords = []
for word, count in word_counts.most_common(top_n):
density = (count / total_words) * 100
keywords.append({
'word': word,
'count': count,
'density': round(density, 2)
})
return keywords
def analyze_text(text: str) -> Dict[str, Any]:
"""Perform complete text analysis."""
if not text or not text.strip():
return {
'error': 'No text provided'
}
word_count = count_words(text)
char_count = count_characters(text)
sentence_count = count_sentences(text)
paragraph_count = count_paragraphs(text)
reading_time = calculate_reading_time(word_count)
speaking_time = calculate_speaking_time(word_count)
reading_level = calculate_flesch_kincaid(text, word_count, sentence_count)
keywords = calculate_keyword_density(text)
return {
'word_count': word_count,
'character_count': char_count,
'sentence_count': sentence_count,
'paragraph_count': paragraph_count,
'reading_time': reading_time,
'speaking_time': speaking_time,
'reading_level': reading_level,
'keywords': keywords
}
def format_output(result: Dict[str, Any], use_json: bool = False) -> str:
"""Format analysis results for display."""
if use_json:
return json.dumps(result, indent=2)
if 'error' in result:
return f"Error: {result['error']}"
lines = [
"=" * 50,
"TEXT ANALYSIS RESULTS",
"=" * 50,
"",
f"Word Count: {result['word_count']}",
f"Character Count: {result['character_count']['with_spaces']} (with spaces)",
f" {result['character_count']['without_spaces']} (without spaces)",
f"Sentences: {result['sentence_count']}",
f"Paragraphs: {result['paragraph_count']}",
"",
"Time Estimates:",
f" Reading Time: {result['reading_time']['display']}",
f" Speaking Time: {result['speaking_time']['display']}",
"",
"Reading Level (Flesch-Kincaid):",
f" Grade Level: {result['reading_level']['grade_level']}",
f" Difficulty: {result['reading_level']['difficulty']}",
"",
"Top Keywords:",
]
if result['keywords']:
for i, kw in enumerate(result['keywords'][:10], 1):
lines.append(f" {i}. {kw['word']} ({kw['count']} times, {kw['density']}%)")
else:
lines.append(" No significant keywords found")
lines.extend([
"",
"=" * 50,
])
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description='Word Counter - Comprehensive text analysis tool'
)
parser.add_argument('text', nargs='?', help='Text to analyze')
parser.add_argument('--file', '-f', help='Read text from file')
parser.add_argument('--json', '-j', action='store_true', help='Output as JSON')
args = parser.parse_args()
# Get text from file or argument
if args.file:
try:
with open(args.file, 'r', encoding='utf-8') as f:
text = f.read()
except FileNotFoundError:
print(f"Error: File not found: {args.file}")
sys.exit(1)
except Exception as e:
print(f"Error reading file: {e}")
sys.exit(1)
elif args.text:
text = args.text
else:
# Read from stdin if no arguments
text = sys.stdin.read()
if not text.strip():
parser.print_help()
sys.exit(1)
# Analyze and output
result = analyze_text(text)
print(format_output(result, args.json))
if __name__ == "__main__":
main()
FILE:references/formulas.md
# Text Analysis Formulas Reference
## Reading Time Calculation
**Formula:**
```
Reading Time (minutes) = Word Count / 200
```
**Standard:**
- Average adult reading speed: 200 words per minute
- Technical/complex content: 150-180 wpm
- Easy content: 250-300 wpm
## Speaking Time Calculation
**Formula:**
```
Speaking Time (minutes) = Word Count / 130
```
**Standard:**
- Natural speaking pace: 130 words per minute
- Fast presentation: 150-160 wpm
- Slow/careful speech: 100-110 wpm
## Flesch-Kincaid Reading Level
**Formula:**
```
Grade Level = 0.39 × (Words/Sentences) + 11.8 × (Syllables/Words) - 15.59
```
**Interpretation:**
- **0-6**: Easy (elementary level)
- **6-8**: Standard (general audience)
- **8-10**: Moderate (high school level)
- **10-12**: Difficult (college level)
- **12+**: Advanced (graduate/academic)
**Target Guidelines:**
- General web content: Grade 6-8
- Mass market publications: Grade 8-10
- Academic papers: Grade 10-14
- Legal documents: Grade 12+
## Syllable Estimation Algorithm
**Method:**
1. Count vowel groups (a, e, i, o, u, y) in each word
2. Every word has at least 1 syllable
3. Subtract 1 for silent 'e' at word end (if more than 1 syllable)
**Examples:**
- "hello" → he-llo → 2 syllables
- "time" → ti-me → 1 syllable (silent e)
- "beautiful" → beau-ti-ful → 3 syllables
## Keyword Density
**Formula:**
```
Keyword Density (%) = (Keyword Count / Total Words) × 100
```
**SEO Guidelines:**
- Primary keyword: 1-2% density
- Secondary keywords: 0.5-1% density
- Avoid keyword stuffing (>3% looks spammy)
## Common Word Count Requirements
| Content Type | Words | Characters | Purpose |
|--------------|-------|------------|---------|
| Tweet/X post | 40-50 | ≤280 | Social engagement |
| Meta description | 25-30 | ≤155 | SEO snippet |
| Email subject | 6-10 | ≤60 | Open rates |
| Short blog | 300-600 | - | Quick reads |
| Standard blog | 1,000-1,500 | - | SEO articles |
| Long-form | 2,000-3,000 | - | Comprehensive guides |
| Essay | 500-5,000 | - | Academic work |
Rewrite paragraphs to sound natural and human-written, bypassing AI detectors (GPTZero, Turnitin, Originality.ai).
--- name: ai-paragraph-rewriter description: Rewrite paragraphs to sound natural and human-written, bypassing AI detectors (GPTZero, Turnitin, Originality.ai). --- # AI Paragraph Rewriter Rewrite AI-generated or mechanical-sounding paragraphs into natural, human-like prose that passes all major AI content detectors. ## Use Cases Trigger when user asks to paraphrase, reword, rewrite paragraphs, humanize AI text, bypass AI detection, make text undetectable, or remove AI writing patterns. ## What This Skill Does Transforms text that reads like it was generated by AI into content that: - Has varied sentence structure and length - Uses natural, conversational patterns - Avoids telltale AI markers (over-structured lists, repetitive transitions, formulaic openings/closings) - Preserves facts, arguments, and key points ## Rewriting Modes Choose the right mode based on how much the text needs to change: ### Light Subtle changes — keeps structure, swaps weak phrases, adjusts word choices. Use when the original is close to human but has minor AI artifacts. ### Medium Balanced rewrite — restructures some sentences, varies rhythm, removes obvious AI patterns while preserving meaning. Best for most use cases. ### Bypass Maximum change — breaks original structure, rewrites from scratch, adds natural human quirks. Use when content is clearly AI-generated and needs to pass strict detectors. ## Step-by-Step Process ### Step 1: Identify AI Patterns Before rewriting, scan the text for common AI markers: - **Formulaic openings**: "In conclusion...", "Furthermore...", "It is important to note..." - **Over-structured lists**: Everything as numbered/bulleted points - **Repetitive transitions**: "Additionally", "Moreover", "In addition to this" - **Passive voice overuse** - **Perfect symmetry**: Same sentence length throughout - **Buzzword density**: "Leverage", "utilize", "cutting-edge", "paradigm" - **Lack of texture**: No anecdotes, colloquialisms, or personal voice ### Step 2: Apply Rewrites by Mode #### Light Rewrites - Replace formulaic transition words with natural alternatives - Vary sentence beginnings (start with adverbs, subjects, or brief interjections) - Swap 1-2 generic words per sentence - Add or remove one qualifier/adverb #### Medium Rewrites - Restructure 30-50% of sentences (reorder clauses, split long sentences, combine short ones) - Replace 30-50% of words with contextually appropriate synonyms - Add natural rhythm variation (short-long-short pattern) - Introduce 1-2 colloquial or conversational touches - Remove most passive voice #### Bypass Rewrites - Rewrite every sentence from scratch without looking at the original structure - Introduce intentional imperfection: slightly informal phrasing, partial statements, rhetorical questions - Vary paragraph rhythm dramatically (1-sentence paragraph, then 4-sentence block, then 2) - Add hedging, qualifications, and "um" equivalent phrases - Use first-person perspective where appropriate - Include 1-2 concrete details or examples if the topic allows ### Step 3: Quality Check After rewriting, verify: - ✅ Meaning preserved (facts, claims, arguments intact) - ✅ No grammatical errors - ✅ Natural flow when read aloud - ✅ No obvious synonym-swaps (e.g., "utilize" → "use" should feel organic) - ✅ Human-sounding rhythm and variation ## Prompt Template When the user provides text to rewrite, respond with: ``` **Mode Selected:** [Light / Medium / Bypass] **Original:** [User's text] **Rewritten:** [Rewritten text] **What changed:** - [Brief explanation of key changes] ``` ## Tips for Maximum Effectiveness - **The more mechanical the original, the more aggressive the rewrite needed** - Bypass mode works best when you rewrite completely fresh rather than editing line-by-line - Always read the result aloud — if it sounds stilted, it will be flagged - Vary paragraph length intentionally; AI content tends to have uniform paragraph lengths - Add texture: human writing has texture — slight tangents, personal voice, varied formality ## What NOT to Do - ❌ Don't just synonym-swap (AI detectors catch this) - ❌ Don't keep the same structure with different words - ❌ Don't over-correct — adding too many human markers looks just as suspicious - ❌ Don't preserve all the original's transition words (they're a major AI tell)
AI paraphrasing and de-AI tool.
--- name: ai-paraphraser description: AI paraphrasing and de-AI tool. --- # AI Paraphraser Rewrite AI-generated content into natural, human writing style, bypassing AI detectors like GPTZero, Turnitin, Originality.ai, and others. ## Use Cases Use this skill when users mention intentions such as "rewrite," "paraphrase," "de-AI," "make text pass AI detection," "humanize," "eliminate AI traces," "polish text," "bypass AI detection," or "reduce article similarity." ## Core Positioning This is not a simple synonym replacement tool. It specifically targets the statistical features that AI detectors rely on for structural reshaping: - **Eliminate statistical patterns**: Sentence length regularity, vocabulary distribution, and paragraph rhythm that AI detectors (GPTZero / Turnitin / Originality.ai / Copyleaks) depend on - **Preserve original meaning**: Facts, arguments, data, and core viewpoints remain completely unchanged; only the expression changes - **Produce unpredictability**: Each rewrite yields different results with no risk of duplicate content ## Paraphrasing Modes | Mode | Applicable Scenarios | Degree of Change | |------|---------------------|------------------| | **Light** | Minor adjustments, suitable for users with already decent writing | Synonym replacement + minor word order adjustments | | **Medium** | Most paraphrasing needs, default recommendation | Sentence restructuring + paragraph reorganization + introduction of natural rhythm | | **Aggressive** | High-risk detection scenarios, heavily AI-flavored source text | Thorough sentence fragmentation + forced diversification + injection of human writing characteristics | ## Paraphrasing Workflow ### Step 1: Determine Mode Select the paraphrasing mode based on user requirements and source text characteristics: - User explicitly specifies mode → Execute as specified - User does not specify → Assess the AI flavor concentration of the source text, start with Medium - Source text extremely short (<50 words) → Suggest Light mode to avoid semantic distortion - Source text extremely long (>2000 words) → Process in segments, 300-500 words per segment ### Step 2: Analyze Source Text Structure Quickly scan the source text before paraphrasing to identify: - **High-frequency AI sentence patterns**: `In conclusion...` `Furthermore...` `It is worth noting...` `Moreover...` - **Excessively regular structure**: Each sentence of similar length, each paragraph starting with the same connective word - **Non-informative filler words**: `In today's rapidly evolving world...` `It goes without saying that...` - **Core information points**: Facts, data, arguments (these must be preserved) ### Step 3: Execute Paraphrasing **General Principles (applicable to all modes):** 1. **Sentence variety**: Alternate between active / passive / inverted / short / long sentences 2. **Vocabulary replacement**: Replace non-keywords with synonyms; preserve core terms 3. **Break regular rhythm**: Eliminate the pattern of each paragraph starting with a fixed connective 4. **Remove AI filler words**: Delete meaningless opening and concluding sentences 5. **Reorganize word order**: Rearrange information, not simply replace words **Light Mode Additional Rules:** - Only replace high-frequency AI vocabulary (furthermore → also / moreover → what's more) - Make minimal word order adjustments - Maintain original paragraph structure **Medium Mode Additional Rules:** - Comprehensively reorganize sentence structures; adjacent sentences should not repeat the same structure - Order within paragraphs can be adjusted - Introduce imperfections found in genuine human writing (occasional splitting of long compound sentences is acceptable) - Naturally vary paragraph length **Aggressive Mode Additional Rules:** - Convert active sentences to passive, passive to active - Break long sentences into short ones, then combine some short sentences - Delete all obvious AI structural words - Add colloquial expressions or slightly irregular phrasing where appropriate - Reference the human writing characteristics checklist in `references/human-patterns.md` ### Step 4: Quality Check After completing the paraphrase, quickly verify: - [ ] **Meaning unchanged**: Are core arguments, facts, and data preserved? - [ ] **No obvious AI features**: Do words like `Furthermore` `In conclusion` `Moreover` remain? - [ ] **Smooth and natural**: Does it read like a human wrote it? Are there any awkward parts? - [ ] **No duplicate content**: Are there identifiable similarities with the source text? ## Common AI Detection Trigger Words (Be Sure to Replace) | Common AI Word | Suggested Replacement | |---------------|----------------------| | Furthermore | Also, Besides, What's more | | Moreover | In addition, On top of that | | In conclusion | All in all, To sum up, Overall | | It is worth noting that | Notably, Interestingly, In fact | | First and foremost | Above all, Mainly | | As mentioned earlier | As noted, Regarding this | | In today's world | Currently, These days | | It goes without saying | Of course, Naturally | | There are several | A few / Some / Several | | This essay will discuss | This piece explores / This looks at | ## Segmented Paraphrasing Strategy (Long Texts) When the source text exceeds 500 words, process in segments: 1. Split by natural paragraphs (do not force cuts by word count) 2. Paraphrase each segment independently while maintaining logical connections between segments 3. Finally, read through the entire text to ensure overall fluency 4. Check whether transitions between paragraphs are natural See `references/human-patterns.md` for details. ## Paraphrasing Quality Standards **Qualified Output:** - Semantic equivalence: Does not alter the core meaning of the source text - Grammatically correct: No subject-verb disagreement, tense confusion, or other errors - Natural and fluent: Reads as if written by an educated human - No AI traces: Contains no high-frequency AI vocabulary or regular sentence patterns **Rewrite if Unqualified:** - Significant semantic deviation → Paraphrase again - Detection risk remains high → Switch to a stronger mode and rewrite FILE:references/human-patterns.md # Human Writing Characteristics Checklist — Aggressive Mode Specific When performing Aggressive paraphrasing, refer to the following checklist to inject human writing characteristics into the text. --- ## 1. Sentence Structure Variety (Most Important) The fatal characteristic of AI-generated text: **all sentences are nearly the same length**. | Typical AI Pattern | Human Characteristic | |-------------------|---------------------| | Every sentence 15-25 words, balanced length | Long sentences (40+ words) + short sentences (5 words) alternating | | Compound sentences are all `Although..., ...` | Mix: `Because`, `Since`, `Since...`, `..., so ...`, `..., yet ...` | | Every paragraph's first sentence is a topic sentence | Occasionally start with scene-setting / examples / questions | | Never uses sentence openings other than "there be" | Occasionally use inversion: `Only in recent years...` `Such changes include...` | --- ## 2. Vocabulary Diversity **AI Signature Words (Must Replace):** - Additionally / Furthermore / Moreover / Nonetheless - It is important to note that - In order to / In this regard / With respect to - The aforementioned / The following / As illustrated - Consequently / Subsequently / Accordingly - Significantly / Particularly / Especially - It should be noted that / It is evident that **Replacement Library:** | AI Word | Replacement | |---------|-------------| | Additionally | Also / Besides / On top of that | | Furthermore | Plus / And / What's more | | Moreover | To make matters worse / Even more | | Consequently | So / That's why / As a result | | Subsequently | After that / Then / Later | | In order to | To / So as to | | Significant | Big / Major / Key / Core | | Particularly | Above all / Most importantly | | Essential | Must-have / Vital / Crucial | | Demonstrate | Show / Prove / Illustrate | | Facilitate | Help / Enable / Allow | --- ## 3. Paragraph Rhythm **Typical AI Paragraph Structure:** `Topic sentence → Supporting 1 → Supporting 2 → Concluding sentence` **Injecting Human Characteristics:** - In every 3-4 paragraphs, have 1 that breaks this structure - Option: Give an example first → then introduce the point - Option: Raise a question first → then explain the reason - Option: Present data first → then interpret the meaning - Paragraph length: Alternate between 200 words, 50 words, 300 words (do not be uniformly neat) --- ## 4. Natural Use of Transition Words AI's transition words are **excessively regular**—the first word of almost every paragraph is a transition word. Positions of transition words in human writing: - Mid-sentence: `This, however, was not the case.` - End of sentence: `The results were clear enough.` - Mid-paragraph (not at the start): `That said, there are limitations.` - Occasionally use no transition at all, jump directly **Alternative Transition Library:** | Meaning | Common AI Word | More Natural Choice | |---------|---------------|---------------------| | Progression | Furthermore | On top of that, It turns out | | Contrast | However | Then again, But in reality | | Example | For example | Say, Take X, One case in point | | Cause | Because | The reason is, It stems from | | Result | Therefore | And that's why, So, The upshot is | | Conclusion | In conclusion | All in all, So to speak | --- ## 5. "Imperfections" in Human Writing Moderately inject the following characteristics to make the text more authentic: - **Slight hesitancy**: `seems to`, `appears to`, `tends to` - **Colloquialisms**: `a lot of` (instead of `numerous`), `things` (instead of `factors`) - **Ellipsis**: `...and so on.` `and stuff like that.` - **Emphatic sentences**: `What really matters is...` `Here's the thing...` - **Rhetorical questions**: `So what does this mean for us?` > ⚠️ Use in moderation; too much becomes informal. Use with caution in academic texts. --- ## 6. Quick Check (Mandatory After Aggressive Paraphrasing) ``` [ ] Is the word count different for each paragraph? (If any paragraphs have the same word count → Rewrite) [ ] Do any Furthermore / Moreover / Additionally remain? [ ] Are there more than 3 sentences starting with "This..." at the beginning? [ ] Does any "It is important to note that" phrasing remain? [ ] Is there at least one inverted sentence or emphatic sentence? [ ] Does it have a sense of "breath" (alternating long and short) when read aloud? ``` If any item is "No" → Targeted revision. FILE:references/modes-guide.md # Paraphrasing Modes Explained with Examples --- ## Light Mode — Minimal Changes **Applies to:** Source text is of decent quality and only needs removal of minor AI traces. ### Typical Changes - Replace high-frequency AI vocabulary (furthermore → also) - Adjust word order - Maintain original paragraph structure and sentence sequence ### Example **Original (Before Light):** > In today's rapidly evolving digital landscape, artificial intelligence has become increasingly prevalent. Furthermore, AI technologies have demonstrated significant potential across various industries. **After Light:** > In today's digital world, artificial intelligence has become more and more common. Also, AI technologies have shown major potential across many industries. --- ## Medium Mode — Comprehensive Reorganization (Default Recommendation) **Applies to:** Most paraphrasing needs where AI traces are evident and reorganization is required. ### Typical Changes - Sentence restructuring (splitting long sentences, merging short ones) - Adjusting order within paragraphs - Eliminating regular sentence rhythm patterns - Removing meaningless opening sentences ### Example **Original (Before Medium):** > Artificial intelligence is transforming the healthcare industry. It offers numerous benefits. Doctors can use AI to diagnose diseases more accurately. Patients receive better treatment. The technology also reduces costs. In conclusion, AI is proving invaluable in medicine. **After Medium:** > Healthcare is being reshaped by artificial intelligence. Think about it: doctors now have tools that help them catch diseases earlier, patients are getting more personalized care, and hospitals are finding ways to cut costs at the same time. The results speak for themselves — AI is proving genuinely valuable across the medical field. --- ## Aggressive Mode — Thorough Fragmentation **Applies to:** Source text is heavily AI-flavored, or the target detector is extremely strict. ### Typical Changes - Active ↔ Passive voice interchange - Paragraph fragmentation and reorganization - Removal of all high-frequency AI vocabulary - Injection of irregular human writing characteristics - Introduction of colloquialisms, emphatic sentences, and other human traits ### Example **Original (Before Aggressive):** > The adoption of renewable energy sources is essential for addressing climate change. Furthermore, transitioning to clean energy can reduce greenhouse gas emissions. Moreover, renewable energy creates new economic opportunities. In addition to environmental benefits, this shift supports job growth in emerging sectors. Consequently, governments should prioritize investments in solar and wind infrastructure. **After Aggressive:** > Climate change is a big problem — there's no getting around that. The question is what we actually do about it. Switching to renewables isn't just good for the planet; it also brings real economic wins. Solar and wind aren't just buzzwords either — they're driving real job growth in areas that need it most. And here's the thing: the tech is already there. What we need now is the political will to back it. --- ## Quick Decision Guide ``` User specified Light? → Yes → Light, execute directly → No ↓ Source text < 50 words? → Yes → Suggest Light, explain it's too short for deep paraphrasing → No ↓ What is the target platform? → Turnitin (Academic) → Start with Medium, Aggressive is safer → GPTZero → Medium is usually sufficient → Originality.ai → Aggressive recommended → General / Unknown → Medium as default Source text extremely AI-flavored (e.g., obvious three-part structure, every paragraph topic+support+conclusion)? → Yes → Aggressive → No → Medium ``` --- ## Special Scenarios **Academic Paper Paraphrasing:** - Preserve all data, citations, and methodological descriptions - Light / Medium primarily; Aggressive only for high-risk sections - Avoid overly colloquial expressions **Marketing Copy Paraphrasing:** - Both Medium / Aggressive are suitable - May retain brand tone and voice - Avoid excessive colloquialism **Social Media / Post Paraphrasing:** - Aggressive is usually most appropriate - Can introduce more irregular human characteristics - Ensure core information points are preserved
Turnitin AI Detection Checker - Check if text would be flagged by Turnitin's AI detection before submitting.
---
name: turnitin-ai-checker
description: Turnitin AI Detection Checker - Check if text would be flagged by Turnitin's AI detection before submitting.
---
# Turnitin AI Checker
## Overview
This skill helps users check if their text would be flagged by Turnitin's AI detection system before submitting academic work. It provides AI detection scoring, detailed analysis of AI patterns, and text humanization to help content pass detection.
## Use Cases
Use when users want to check AI detection scores, analyze text for AI patterns, or humanize content to pass Turnitin detection. Triggers include "Turnitin", "AI checker", "AI detection", "check AI score", "humanize text", "AI detector", "check if AI wrote this", "detect AI content", "is this AI-generated", "GPTZero alternative", "Turnitin alternative", "analyze text for AI patterns".
## What Is Turnitin AI Detection?
Turnitin is the world's most widely used academic integrity platform, deployed by over 15,000 institutions across 140+ countries. In 2023, Turnitin added AI writing detection alongside its plagiarism checking suite.
Unlike standalone tools like GPTZero, Turnitin is embedded directly into Learning Management Systems such as Canvas, Blackboard, Moodle, and Google Classroom. When you submit an assignment through your school's LMS, Turnitin scans it automatically.
### Turnitin AI Writing Report Scores
- **AI-generated text score**: Percentage of text likely written by AI
- **AI-paraphrased text score**: Percentage of text that was AI-generated then paraphrased
- **Detection threshold**: Turnitin flags submissions at 20% AI or above
- **Below 20%**: No highlights shown to instructors
Since August 2025, the system also detects text run through bypasser or paraphrasing tools. The February 2026 model update improved detection recall.
## Core Capabilities
### 1. AI Detection Analysis
Analyze text to estimate how Turnitin would score it:
- **Perplexity analysis**: Measures how predictable the text is (lower perplexity = more AI-like)
- **Burstiness detection**: Analyzes sentence length variation (AI tends to be more uniform)
- **Readability scoring**: Checks complexity patterns typical of AI text
- **AI fingerprint detection**: Identifies common AI writing patterns
### 2. AI Score Reporting
Generate a comprehensive report with:
- Overall AI probability percentage
- Breakdown by paragraph/section
- Specific AI patterns detected
- Risk assessment (Safe / Warning / High Risk)
### 3. Text Humanization
Rewrite AI-detected text to appear more human-written:
- **Academic mode**: Preserves scholarly tone, citations, and technical vocabulary
- **Natural variation**: Introduces human-like sentence length variation
- **Personal touches**: Adds subjective elements and unique phrasing
- **Citation preservation**: Maintains all references and academic formatting
## Workflow
### Check Turnitin AI Score
1. **Receive text**: Accept essay, research paper, or any academic text
2. **Analyze**: Run multiple detection methods (perplexity, burstiness, patterns)
3. **Calculate score**: Estimate Turnitin AI percentage
4. **Report results**: Show score and risk level
5. **Offer humanization**: If score > 20%, suggest humanization
### Humanize Text
1. **Analyze flagged sections**: Identify high-AI segments
2. **Apply transformations**:
- Vary sentence lengths (add short punchy sentences, occasional long complex ones)
- Replace formal AI phrases with natural alternatives
- Add personal opinions or subjective language where appropriate
- Introduce minor grammatical variations humans make
- Break up overly structured paragraphs
3. **Preserve**: Citations, technical terms, academic tone
4. **Verify**: Re-check humanized text to ensure it passes detection
## Detection Methods Used
### Perplexity Analysis
- Measures how "surprised" a language model is by the text
- AI-generated text typically has lower perplexity (more predictable)
- Human writing has higher perplexity (more creative/unpredictable)
### Burstiness Detection
- Analyzes variation in sentence length and structure
- AI tends to produce consistent sentence patterns
- Human writing has natural "bursts" of variation
### AI Pattern Recognition
- Detects common AI phrases and structures
- Identifies overly formal or generic language
- Spots repetitive transitions and conclusions
### Readability Metrics
- Flesch Reading Ease score
- Flesch-Kincaid Grade Level
- Sentence complexity analysis
## Usage Examples
**Example 1: Check Essay**
```
User: "Check this essay for Turnitin AI detection"
→ Analyze text
→ Report: "AI Score: 35% (High Risk). Flagged sections: introduction and conclusion"
→ Offer humanization
```
**Example 2: Humanize Content**
```
User: "My paper scored 40% AI, help me fix it"
→ Identify problematic sections
→ Humanize while preserving academic tone
→ Re-check: "New AI Score: 12% (Safe)"
```
**Example 3: Pre-submission Check**
```
User: "I'm about to submit my thesis, check it first"
→ Full analysis
→ Report: "AI Score: 8% (Safe). No action needed."
```
## Important Notes
- This tool provides an **estimate** based on similar detection methods, not official Turnitin results
- Actual Turnitin scores may vary slightly
- Always review humanized text for accuracy and meaning preservation
- Academic integrity is the user's responsibility - this tool helps avoid false positives, not bypass legitimate detection
## Resources
- `references/detection_methods.md` - Detailed technical documentation on AI detection algorithms
FILE:scripts/ai_checker.py
#!/usr/bin/env python3
"""
Turnitin AI Checker - Core detection algorithms
Analyzes text for AI-generated patterns similar to Turnitin's detection methods.
"""
import re
import math
import json
import sys
from typing import Dict, List, Tuple
from collections import Counter
# Common AI writing patterns
AI_PHRASES = [
"it is important to note",
"it should be noted",
"it is worth mentioning",
"it is essential to understand",
"it is crucial to recognize",
"in conclusion",
"to summarize",
"to conclude",
"in summary",
"furthermore",
"moreover",
"in addition",
"additionally",
"consequently",
"therefore",
"thus",
"as a result",
"hence",
"for example",
"for instance",
"in other words",
"to put it simply",
"in today's world",
"in recent years",
"with the development of",
"with the advancement of",
"due to the fact that",
"in order to",
"in terms of",
"with regard to",
"regarding",
"concerning",
"not only",
"but also",
"on the other hand",
"however",
"nevertheless",
"nonetheless",
"although",
"even though",
"despite the fact that",
]
# Formal words often overused by AI
FORMAL_WORDS = [
"utilize", "utilizes", "utilized", "utilizing",
"demonstrate", "demonstrates", "demonstrated", "demonstrating",
"indicate", "indicates", "indicated", "indicating",
"significant", "significantly",
"substantial", "substantially",
"effective", "effectively",
"appropriate", "appropriately",
"relevant", "relevance",
"numerous",
"various",
"several",
"multiple",
]
def count_syllables(word: str) -> int:
"""Estimate syllable count for a word."""
word = word.lower()
vowels = "aeiouy"
syllable_count = 0
prev_was_vowel = False
for char in word:
is_vowel = char in vowels
if is_vowel and not prev_was_vowel:
syllable_count += 1
prev_was_vowel = is_vowel
if word.endswith("e"):
syllable_count -= 1
if word.endswith("le") and len(word) > 2 and word[-3] not in vowels:
syllable_count += 1
if syllable_count == 0:
syllable_count = 1
return syllable_count
def split_sentences(text: str) -> List[str]:
"""Split text into sentences."""
# Simple sentence splitting
sentences = re.split(r'(?<=[.!?])\s+', text)
return [s.strip() for s in sentences if s.strip()]
def calculate_burstiness(sentences: List[str]) -> float:
"""
Calculate burstiness score based on sentence length variation.
Returns score 0-1, where higher = more human-like (more variation).
"""
if len(sentences) < 2:
return 0.5
lengths = [len(s.split()) for s in sentences]
mean_len = sum(lengths) / len(lengths)
if mean_len == 0:
return 0.5
# Calculate standard deviation
variance = sum((l - mean_len) ** 2 for l in lengths) / len(lengths)
std_dev = math.sqrt(variance)
# Coefficient of variation
cv = std_dev / mean_len
# Normalize to 0-1 range (typical CV for text is 0.2-0.8)
burstiness = min(max(cv / 0.6, 0), 1)
return burstiness
def detect_ai_patterns(text: str) -> Dict:
"""Detect common AI writing patterns."""
text_lower = text.lower()
words = text_lower.split()
word_count = len(words)
# Count AI phrases
ai_phrase_count = 0
found_phrases = []
for phrase in AI_PHRASES:
count = text_lower.count(phrase)
if count > 0:
ai_phrase_count += count
found_phrases.append((phrase, count))
# Count formal words
formal_word_count = sum(1 for word in words if word in FORMAL_WORDS)
# Calculate scores per 100 words
ai_phrase_density = (ai_phrase_count / word_count * 100) if word_count > 0 else 0
formal_word_density = (formal_word_count / word_count * 100) if word_count > 0 else 0
# Pattern score (0-100)
pattern_score = min((ai_phrase_density * 5) + (formal_word_density * 2), 100)
return {
"ai_phrase_count": ai_phrase_count,
"ai_phrase_density": round(ai_phrase_density, 2),
"formal_word_count": formal_word_count,
"formal_word_density": round(formal_word_density, 2),
"found_phrases": found_phrases[:10], # Top 10
"pattern_score": round(pattern_score, 2)
}
def calculate_readability(text: str) -> Dict:
"""Calculate readability metrics."""
sentences = split_sentences(text)
words = text.split()
if len(sentences) == 0 or len(words) == 0:
return {"flesch_ease": 0, "flesch_kincaid": 0, "avg_sentence_length": 0}
syllable_count = sum(count_syllables(w) for w in words)
word_count = len(words)
sentence_count = len(sentences)
avg_sentence_length = word_count / sentence_count
avg_syllables_per_word = syllable_count / word_count
# Flesch Reading Ease
flesch_ease = 206.835 - (1.015 * avg_sentence_length) - (84.6 * avg_syllables_per_word)
# Flesch-Kincaid Grade Level
flesch_kincaid = (0.39 * avg_sentence_length) + (11.8 * avg_syllables_per_word) - 15.59
return {
"flesch_ease": round(flesch_ease, 2),
"flesch_kincaid": round(flesch_kincaid, 2),
"avg_sentence_length": round(avg_sentence_length, 2),
"avg_syllables_per_word": round(avg_syllables_per_word, 2),
"word_count": word_count,
"sentence_count": sentence_count
}
def calculate_perplexity_proxy(text: str) -> float:
"""
Calculate a perplexity proxy score.
Since we don't have access to a full language model, we use heuristics.
"""
words = text.lower().split()
if len(words) < 10:
return 50
# Calculate word repetition patterns
word_counts = Counter(words)
total_words = len(words)
unique_words = len(word_counts)
# Type-token ratio (vocabulary diversity)
ttr = unique_words / total_words if total_words > 0 else 0
# Common word ratio (function words are predictable)
common_words = {"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "by", "is", "are", "was", "were", "be", "been", "have", "has", "had", "do", "does", "did", "will", "would", "could", "should", "may", "might", "can", "this", "that", "these", "those", "it", "they", "them", "their", "there", "then", "than", "as", "if", "so", "such", "when", "where", "why", "how", "all", "any", "both", "each", "more", "most", "other", "some", "very", "what", "which", "who", "whom", "whose", "from", "up", "about", "into", "through", "during", "before", "after", "above", "below", "between", "among", "within", "without", "against", "under", "over", "again", "further", "once", "here", "now", "also", "only", "own", "same", "few", "more", "most", "other", "some", "such", "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "but", "if", "or", "because", "until", "while", "although", "though", "unless", "whether", "since", "although", "even", "provided", "whereas"}
common_count = sum(1 for w in words if w in common_words)
common_ratio = common_count / total_words if total_words > 0 else 0
# Repetitive phrase detection
bigrams = [f"{words[i]} {words[i+1]}" for i in range(len(words)-1)]
bigram_counts = Counter(bigrams)
max_bigram_freq = max(bigram_counts.values()) if bigram_counts else 0
repetition_score = min(max_bigram_freq / (total_words / 20), 1) if total_words > 20 else 0
# Combine factors (lower = more AI-like)
# AI tends to have: lower TTR, moderate common word ratio, some repetition
perplexity_proxy = 100 - (ttr * 30) - (common_ratio * 20) + (repetition_score * 20)
return min(max(perplexity_proxy, 0), 100)
def analyze_text(text: str) -> Dict:
"""
Main analysis function that combines all detection methods.
Returns comprehensive AI detection report.
"""
if not text or len(text.strip()) < 50:
return {
"error": "Text too short for analysis (minimum 50 characters)",
"ai_score": 0,
"risk_level": "Unknown"
}
sentences = split_sentences(text)
# Calculate individual components
burstiness = calculate_burstiness(sentences)
pattern_data = detect_ai_patterns(text)
readability = calculate_readability(text)
perplexity_proxy = calculate_perplexity_proxy(text)
# Weighted AI score calculation
# Burstiness: lower = more AI (invert)
burstiness_score = (1 - burstiness) * 100
# Perplexity proxy: lower = more AI
perplexity_score = 100 - perplexity_proxy
# Pattern score: higher = more AI
pattern_score = pattern_data["pattern_score"]
# Readability variance: AI tends to be consistent
# Use Flesch-Kincaid as a consistency indicator
fk_score = min(max((readability["flesch_kincaid"] - 8) * 5, 0), 100)
# Weighted combination
ai_score = (
perplexity_score * 0.30 + # 30% - predictability
burstiness_score * 0.25 + # 25% - variation
pattern_score * 0.30 + # 30% - AI patterns
fk_score * 0.15 # 15% - grade level consistency
)
ai_score = min(max(ai_score, 0), 100)
# Determine risk level
if ai_score < 20:
risk_level = "Safe"
risk_description = "No action needed. Your text is unlikely to be flagged."
elif ai_score < 40:
risk_level = "Warning"
risk_description = "Consider reviewing. Some sections may trigger flags."
elif ai_score < 60:
risk_level = "Moderate Risk"
risk_description = "Humanization recommended to reduce detection risk."
else:
risk_level = "High Risk"
risk_description = "Strong humanization recommended before submission."
return {
"ai_score": round(ai_score, 1),
"risk_level": risk_level,
"risk_description": risk_description,
"components": {
"perplexity_proxy": round(perplexity_proxy, 1),
"burstiness": round(burstiness * 100, 1),
"pattern_score": round(pattern_score, 1),
"readability_grade": round(readability["flesch_kincaid"], 1)
},
"pattern_analysis": pattern_data,
"readability": readability,
"threshold_note": "Turnitin flags submissions at 20% AI or above"
}
def analyze_by_paragraphs(text: str) -> List[Dict]:
"""Analyze text paragraph by paragraph."""
paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()]
results = []
for i, paragraph in enumerate(paragraphs, 1):
if len(paragraph) >= 100:
analysis = analyze_text(paragraph)
results.append({
"paragraph": i,
"preview": paragraph[:100] + "..." if len(paragraph) > 100 else paragraph,
"ai_score": analysis.get("ai_score", 0),
"risk_level": analysis.get("risk_level", "Unknown")
})
return results
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python ai_checker.py '<text>'")
print(" or: python ai_checker.py --file <path>")
sys.exit(1)
if sys.argv[1] == "--file":
with open(sys.argv[2], 'r', encoding='utf-8') as f:
text = f.read()
else:
text = sys.argv[1]
result = analyze_text(text)
print(json.dumps(result, indent=2, ensure_ascii=False))
FILE:scripts/humanize.py
#!/usr/bin/env python3
"""
Text Humanizer - Transform AI-generated text to appear more human-written.
Preserves academic tone while introducing natural variation.
"""
import re
import random
import sys
from typing import List, Dict
# Replacement mappings
FORMAL_TO_CASUAL = {
"utilize": "use",
"utilizes": "uses",
"utilized": "used",
"utilizing": "using",
"demonstrate": "show",
"demonstrates": "shows",
"demonstrated": "showed",
"demonstrating": "showing",
"indicate": "show",
"indicates": "shows",
"indicated": "showed",
"indicating": "showing",
"furthermore": "plus",
"moreover": "what's more",
"consequently": "so",
"therefore": "that's why",
"thus": "so",
"hence": "so",
"in order to": "to",
"due to the fact that": "because",
"in spite of": "despite",
"with regard to": "about",
"in terms of": "when it comes to",
"at this point in time": "now",
"in the event that": "if",
"for the purpose of": "for",
"in the near future": "soon",
"a large number of": "many",
"a significant number of": "many",
"a considerable amount of": "much",
"it is important to note": "worth noting",
"it should be noted": "note that",
"it is worth mentioning": "interestingly",
"it is essential to understand": "understand that",
"it is crucial to recognize": "recognize that",
}
TRANSITION_REPLACEMENTS = {
"in conclusion": ["to wrap up", "so", "all in all", "looking back"],
"to summarize": ["to sum up", "in short", "basically"],
"to conclude": ["to wrap up", "so", "all in all"],
"in summary": ["to sum up", "in short", "basically"],
"for example": ["for instance", "like", "take"],
"for instance": ["for example", "like", "say"],
"in other words": ["put another way", "basically", "meaning"],
"to put it simply": ["simply put", "basically", "in simple terms"],
"on the other hand": ["but then", "conversely", "at the same time"],
"however": ["but", "yet", "still", "though"],
"nevertheless": ["even so", "still", "yet"],
"nonetheless": ["even so", "still", "yet"],
"although": ["even though", "while"],
"even though": ["although", "while"],
}
def vary_sentence_length(sentences: List[str]) -> List[str]:
"""Vary sentence lengths by combining or splitting sentences."""
varied = []
i = 0
while i < len(sentences):
sentence = sentences[i]
word_count = len(sentence.split())
# Occasionally combine short sentences
if word_count < 8 and i < len(sentences) - 1 and random.random() < 0.3:
next_sentence = sentences[i + 1]
if len(next_sentence.split()) < 15:
combined = sentence.rstrip('.') + ', and ' + next_sentence[0].lower() + next_sentence[1:]
varied.append(combined)
i += 2
continue
# Occasionally split long sentences
if word_count > 25 and ', ' in sentence and random.random() < 0.3:
parts = sentence.rsplit(', ', 1)
if len(parts) == 2:
varied.append(parts[0] + '.')
varied.append(parts[1][0].upper() + parts[1][1:])
i += 1
continue
varied.append(sentence)
i += 1
return varied
def add_contractions(text: str) -> str:
"""Add contractions to make text more natural."""
contractions = [
("it is", "it's"),
("it was", "it was"), # Keep sometimes
("that is", "that's"),
("there is", "there's"),
("there are", "there are"), # Keep sometimes
("they are", "they're"),
("we are", "we're"),
("you are", "you're"),
("I am", "I'm"),
("do not", "don't"),
("does not", "doesn't"),
("did not", "didn't"),
("will not", "won't"),
("would not", "wouldn't"),
("could not", "couldn't"),
("should not", "shouldn't"),
("cannot", "can't"),
("is not", "isn't"),
("are not", "aren't"),
("was not", "wasn't"),
("were not", "weren't"),
("has not", "hasn't"),
("have not", "haven't"),
("had not", "hadn't"),
]
for formal, contraction in contractions:
# Replace about 60% of occurrences
pattern = re.compile(r'\b' + formal + r'\b', re.IGNORECASE)
def replace_with_chance(match):
if random.random() < 0.6:
# Preserve capitalization
matched = match.group()
if matched[0].isupper():
return contraction.capitalize()
return contraction
return match.group()
text = pattern.sub(replace_with_chance, text)
return text
def replace_formal_phrases(text: str) -> str:
"""Replace formal phrases with more natural alternatives."""
# Replace formal words
for formal, casual in FORMAL_TO_CASUAL.items():
pattern = re.compile(r'\b' + re.escape(formal) + r'\b', re.IGNORECASE)
def replace_with_casual(match):
matched = match.group()
if matched[0].isupper():
return casual.capitalize()
return casual
text = pattern.sub(replace_with_casual, text)
# Replace transitions with varied alternatives
for formal, alternatives in TRANSITION_REPLACEMENTS.items():
pattern = re.compile(r'\b' + re.escape(formal) + r'\b', re.IGNORECASE)
def replace_with_alternative(match):
chosen = random.choice(alternatives)
matched = match.group()
if matched[0].isupper():
return chosen.capitalize()
return chosen
text = pattern.sub(replace_with_alternative, text)
return text
def add_personal_voice(text: str) -> str:
"""Add personal voice elements where appropriate."""
sentences = re.split(r'(?<=[.!?])\s+', text)
modified = []
personal_starters = [
"I think ",
"In my view, ",
"From my perspective, ",
"I believe ",
"It seems to me that ",
]
for i, sentence in enumerate(sentences):
# Occasionally add personal voice to statements
if (i > 0 and i % 5 == 0 and
not sentence.lower().startswith(("the", "this", "these", "those", "it")) and
random.random() < 0.3):
# Don't modify if already has personal voice
if not any(p in sentence.lower() for p in ["i think", "i believe", "my view"]):
starter = random.choice(personal_starters)
sentence = starter + sentence[0].lower() + sentence[1:]
modified.append(sentence)
return ' '.join(modified)
def add_rhetorical_elements(text: str) -> str:
"""Add rhetorical questions and natural speech patterns."""
sentences = re.split(r'(?<=[.!?])\s+', text)
modified = []
rhetorical_starters = [
"So, ",
"Now, ",
"Well, ",
"You see, ",
"Look, ",
]
for i, sentence in enumerate(sentences):
# Occasionally add rhetorical starters
if i > 0 and i % 4 == 0 and random.random() < 0.2:
if not sentence.startswith(("But", "And", "Or", "So", "However")):
starter = random.choice(rhetorical_starters)
sentence = starter + sentence[0].lower() + sentence[1:]
modified.append(sentence)
return ' '.join(modified)
def vary_punctuation(text: str) -> str:
"""Vary punctuation usage to feel more natural."""
# Occasionally use em-dashes
text = re.sub(r'\s*\(\s*', ' — ', text)
text = re.sub(r'\s*\)\s*', ' — ', text)
# Reduce overuse of semicolons
text = re.sub(r';\s*', '. ', text)
return text
def break_structured_lists(text: str) -> str:
"""Break up overly structured list patterns."""
# Replace "First... Second... Third..." patterns
text = re.sub(r'\bFirst(?:ly)?,?\s*', 'To start with, ', text, flags=re.IGNORECASE)
text = re.sub(r'\bSecond(?:ly)?,?\s*', 'Next, ', text, flags=re.IGNORECASE)
text = re.sub(r'\bThird(?:ly)?,?\s*', 'Then, ', text, flags=re.IGNORECASE)
text = re.sub(r'\bFinally,?\s*', 'Lastly, ', text, flags=re.IGNORECASE)
return text
def humanize_text(text: str, academic_mode: bool = True) -> str:
"""
Main humanization function.
Args:
text: The text to humanize
academic_mode: If True, preserve academic tone; if False, more casual
Returns:
Humanized text
"""
# Split into sentences
sentences = re.split(r'(?<=[.!?])\s+', text)
# Apply transformations
sentences = vary_sentence_length(sentences)
text = ' '.join(sentences)
text = replace_formal_phrases(text)
text = add_contractions(text)
text = break_structured_lists(text)
if not academic_mode:
text = add_personal_voice(text)
text = add_rhetorical_elements(text)
else:
# Light personal touches for academic mode
text = add_rhetorical_elements(text)
text = vary_punctuation(text)
# Clean up any double spaces
text = re.sub(r'\s+', ' ', text)
text = re.sub(r'\s+([.,;!?])', r'\1', text)
return text.strip()
def humanize_by_sections(text: str, high_ai_sections: List[Dict] = None) -> str:
"""
Humanize specific sections that have high AI scores.
If no sections specified, humanize entire text.
"""
if not high_ai_sections:
return humanize_text(text)
paragraphs = [p.strip() for p in text.split('\n\n') if p.strip()]
modified_paragraphs = []
for i, paragraph in enumerate(paragraphs, 1):
# Check if this paragraph should be humanized
should_humanize = any(
s.get("paragraph") == i and s.get("ai_score", 0) > 30
for s in high_ai_sections
)
if should_humanize:
modified_paragraphs.append(humanize_text(paragraph))
else:
modified_paragraphs.append(paragraph)
return '\n\n'.join(modified_paragraphs)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python humanize.py '<text>' [academic|casual]")
print(" or: python humanize.py --file <path> [academic|casual]")
sys.exit(1)
mode = "academic"
if len(sys.argv) > 2:
mode = sys.argv[2] if sys.argv[2] in ["academic", "casual"] else "academic"
if sys.argv[1] == "--file":
file_path = sys.argv[2]
if len(sys.argv) > 3:
mode = sys.argv[3] if sys.argv[3] in ["academic", "casual"] else "academic"
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
else:
text = sys.argv[1]
academic_mode = (mode == "academic")
result = humanize_text(text, academic_mode=academic_mode)
print(result)
FILE:references/detection_methods.md
# AI Detection Methods Reference
## Perplexity Analysis
### What is Perplexity?
Perplexity measures how well a probability distribution or probability model predicts a sample. In NLP, it quantifies how "surprised" a language model is by text.
- **Lower perplexity** = Text is more predictable = Likely AI-generated
- **Higher perplexity** = Text is less predictable = Likely human-written
### Calculation
```
Perplexity = exp(-1/N * Σ log P(wi | w1...wi-1))
```
Where:
- N = number of tokens
- P(wi | w1...wi-1) = probability of token given previous context
### Implementation Approach
1. Use a pre-trained language model (e.g., GPT-2, RoBERTa)
2. Calculate log probabilities for each token
3. Average and exponentiate
4. Compare against thresholds:
- Perplexity < 20: High AI probability
- Perplexity 20-50: Moderate AI probability
- Perplexity > 50: Low AI probability
## Burstiness Detection
### What is Burstiness?
Burstiness measures the variation in sentence length and structure. AI-generated text tends to be more uniform, while human writing has natural variation.
### Metrics
1. **Sentence Length Variance**
- Calculate standard deviation of sentence lengths
- Lower variance = more AI-like
2. **Sentence Length Distribution**
- AI: Often clustered around mean
- Human: Long tail distribution with outliers
3. **Punctuation Burstiness**
- Variance in comma usage per sentence
- Variance in clause complexity
### Implementation
```python
def calculate_burstiness(sentences):
lengths = [len(s.split()) for s in sentences]
mean_len = np.mean(lengths)
std_len = np.std(lengths)
# Coefficient of variation
cv = std_len / mean_len if mean_len > 0 else 0
# Burstiness score (0-1, higher = more human-like)
burstiness = min(cv / 0.5, 1.0)
return burstiness
```
## AI Pattern Recognition
### Common AI Writing Patterns
1. **Repetitive Transitions**
- "Furthermore", "Moreover", "In addition"
- Overused at paragraph starts
2. **Generic Conclusions**
- "In conclusion", "To summarize"
- Formulaic ending patterns
3. **Hedging Language**
- "It is important to note"
- "It should be noted that"
- "It is worth mentioning"
4. **List-like Structures**
- Overly organized bullet points
- Parallel structure that feels mechanical
5. **Lack of Personal Voice**
- No opinions or subjective statements
- Absence of "I think", "In my experience"
### Pattern Detection Implementation
```python
AI_PHRASES = [
"it is important to note",
"it should be noted",
"it is worth mentioning",
"in conclusion",
"to summarize",
"furthermore",
"moreover",
"in addition",
"additionally",
"consequently",
"therefore",
"thus",
"as a result",
"for example",
"for instance",
"in other words",
"to put it simply",
"in today's world",
"in recent years",
"with the development of",
]
def detect_ai_patterns(text):
text_lower = text.lower()
pattern_count = sum(1 for phrase in AI_PHRASES if phrase in text_lower)
# Normalize by text length
return min(pattern_count / (len(text.split()) / 100), 1.0)
```
## Readability Metrics
### Flesch Reading Ease
```
206.835 - (1.015 × ASL) - (84.6 × ASW)
```
Where:
- ASL = Average sentence length (words/sentences)
- ASW = Average syllables per word
### Flesch-Kincaid Grade Level
```
(0.39 × ASL) + (11.8 × ASW) - 15.59
```
### AI vs Human Patterns
- **AI text**: Often consistently in 12-16 grade level range
- **Human text**: More variation, occasional simple/complex sections
## Combined Scoring Algorithm
### Weighted Average Approach
```python
def calculate_ai_score(text):
# Individual component scores (0-100, higher = more AI-like)
perplexity_score = analyze_perplexity(text) # 30% weight
burstiness_score = 100 - calculate_burstiness(text) * 100 # 25% weight
pattern_score = detect_ai_patterns(text) * 100 # 25% weight
readability_variance = analyze_readability_variance(text) # 20% weight
# Weighted combination
ai_score = (
perplexity_score * 0.30 +
burstiness_score * 0.25 +
pattern_score * 0.25 +
readability_variance * 0.20
)
return min(max(ai_score, 0), 100)
```
### Risk Levels
- **0-20%**: Safe - No action needed
- **20-40%**: Warning - Consider review
- **40-60%**: Moderate Risk - Humanization recommended
- **60-100%**: High Risk - Humanization strongly recommended
## Humanization Techniques
### 1. Sentence Length Variation
**Before (AI-like):**
> "The research methodology employed a mixed-methods approach. This approach allowed for comprehensive data collection. The data was analyzed using statistical software."
**After (Humanized):**
> "We went with a mixed-methods approach for this research. Why? It gave us the full picture. After collecting everything, we ran the numbers through statistical software."
### 2. Personal Voice Addition
**Before:**
> "It is important to note that the results may vary."
**After:**
> "From my experience, results can really vary depending on the context."
### 3. Breaking Formulaic Structure
**Before:**
> "In conclusion, this study has demonstrated three key findings. First... Second... Third..."
**After:**
> "So what did we actually find? Three things stood out. The first was..."
### 4. Natural Transitions
Replace formal transitions with natural flow:
- "Furthermore" → "Plus" or "Also"
- "Moreover" → "What's more"
- "Consequently" → "So" or "That meant"
- "Therefore" → "That's why"
### 5. Minor Imperfections
Humans naturally include:
- Occasional sentence fragments
- Varying punctuation usage
- Personal asides
- Rhetorical questions
AI Detection Tool - Detect AI-generated text with multiple analysis methods including perplexity analysis, burstiness detection, readability scoring, and AI...
---
name: detector-ai
description: AI Detection Tool - Detect AI-generated text with multiple analysis methods including perplexity analysis, burstiness detection, readability scoring, and AI fingerprint detection.
---
# Detector AI
AI Detection Tool that analyzes text to determine if it was written by AI (ChatGPT, Claude, Gemini, etc.) or humans.
## Use Cases
Use when users want to check if text was written by ChatGPT, Claude, Gemini, or other AI writing tools. Trigger phrases include "AI detector", "check if AI wrote this", "detect AI content", "is this AI-generated", "GPTZero alternative", "Turnitin alternative", "analyze text for AI patterns".
## Overview
This skill provides comprehensive AI content detection using multiple analysis methods:
1. **Perplexity Analysis** - Measures text predictability (core method used by GPTZero)
2. **Burstiness Detection** - Analyzes sentence length variation patterns
3. **Readability Scoring** - Detects suspiciously consistent readability (AI typically produces Grade 8-10 text)
4. **AI Fingerprint Detection** - Identifies tell-tale AI patterns (overused transitions, generic openers, repetitive n-grams)
## How to Use
When a user wants to analyze text for AI detection:
1. **Get the text** - Ask the user to paste the text they want to analyze
2. **Run the analysis** - Execute the detection script with the text
3. **Interpret results** - Explain the findings in plain language
### Example Usage
```
User: "Can you check if this text is AI-generated?"
[User provides text]
You: Run the AI detector analysis and provide:
- Overall AI probability score
- Perplexity score and interpretation
- Burstiness analysis
- Readability assessment
- Detected AI fingerprints (if any)
- Human-like vs AI-like characteristics
```
## Analysis Methods Explained
### Perplexity Analysis
- **What it measures**: How predictable the text is
- **AI text**: Low perplexity (high predictability) - the model chooses the most likely next words
- **Human text**: Higher perplexity - humans use more varied and surprising word choices
- **Interpretation**: Lower perplexity suggests AI authorship
### Burstiness Detection
- **What it measures**: Sentence length variation
- **Human writing**: Natural "bursts" - mixing short punchy sentences with longer complex ones
- **AI writing**: Unnaturally uniform sentence patterns
- **Interpretation**: High burstiness suggests human authorship
### Readability Scoring
- **What it measures**: Text complexity (Flesch-Kincaid Grade Level)
- **AI text**: Often locked in narrow range (Grade 8-10)
- **Human text**: More varied readability depending on context and author
- **Interpretation**: Suspiciously consistent mid-range readability suggests AI
### AI Fingerprint Detection
Identifies specific patterns common in AI-generated text:
- Overused transitions: "Furthermore", "Moreover", "Additionally", "In conclusion"
- Generic openers: "In today's world", "It is important to note"
- Repetitive n-gram sequences
- Formulaic paragraph structures
- Lack of personal anecdotes or unique perspectives
## Interpreting Results
### AI Probability Score
- **0-30%**: Likely human-written
- **30-60%**: Uncertain - mixed signals
- **60-100%**: Likely AI-generated
### Confidence Levels
- **High confidence**: Multiple indicators align
- **Medium confidence**: Some indicators suggest AI, others are neutral
- **Low confidence**: Inconclusive results
## Limitations
- No AI detector is 100% accurate
- Human-written text can sometimes trigger AI flags
- Edited AI text may evade detection
- Results should be used as guidance, not definitive proof
## Resources
### scripts/
- `detect_ai.py` - Main detection script that runs all analysis methods
### references/
- `ai_patterns.md` - Comprehensive list of AI writing patterns and fingerprints
FILE:scripts/detect_ai.py
#!/usr/bin/env python3
"""
AI Content Detector
Analyzes text to detect AI-generated content using multiple methods.
"""
import re
import math
import sys
import io
from collections import Counter
from typing import Dict, List, Tuple
# Ensure UTF-8 output on Windows
if sys.platform == 'win32':
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
class AIDetector:
"""Main AI detection class with multiple analysis methods."""
# Common AI transition words and phrases
AI_TRANSITIONS = [
'furthermore', 'moreover', 'additionally', 'consequently', 'therefore',
'thus', 'hence', 'in conclusion', 'to summarize', 'in summary',
'on the other hand', 'in contrast', 'similarly', 'likewise',
'firstly', 'secondly', 'thirdly', 'finally', 'lastly',
'it is important to note', 'it should be noted', 'it is worth noting',
'in today\'s world', 'in the modern world', 'in recent years',
'with the advent of', 'due to the fact that', 'in order to'
]
# Generic AI openers
AI_OPENERS = [
'in today\'s', 'in the modern', 'in recent years', 'with the development',
'as we all know', 'it is widely known', 'it is universally accepted',
'in this essay', 'this essay will', 'this paper will'
]
def __init__(self, text: str):
self.text = text
self.sentences = self._split_sentences(text)
self.words = self._extract_words(text)
def _split_sentences(self, text: str) -> List[str]:
"""Split text into sentences (supports English and Chinese)."""
# Split by English sentence endings and Chinese punctuation
sentences = re.split(r'[.!?。!?]+', text)
return [s.strip() for s in sentences if s.strip()]
def _extract_words(self, text: str) -> List[str]:
"""Extract words from text (supports English and Chinese)."""
# Extract English words
english_words = re.findall(r'\b[a-zA-Z]+\b', text.lower())
# Extract Chinese characters/words (treat each char as a word for simplicity)
chinese_chars = re.findall(r'[\u4e00-\u9fff]', text)
return english_words + chinese_chars
def calculate_perplexity(self) -> Dict:
"""
Calculate perplexity using n-gram analysis.
Lower perplexity = more predictable = likely AI.
"""
if len(self.words) < 3:
return {"score": 0, "interpretation": "Insufficient text"}
# Calculate bigram probabilities
bigrams = [(self.words[i], self.words[i+1]) for i in range(len(self.words)-1)]
bigram_counts = Counter(bigrams)
word_counts = Counter(self.words)
# Calculate perplexity
total_log_prob = 0
for bigram in bigrams:
# Laplace smoothing
prob = (bigram_counts[bigram] + 1) / (word_counts[bigram[0]] + len(word_counts))
total_log_prob += math.log2(prob)
avg_log_prob = total_log_prob / len(bigrams)
perplexity = 2 ** (-avg_log_prob)
# Normalize to 0-100 scale (typical range: 50-300)
normalized = max(0, min(100, (300 - perplexity) / 2.5))
interpretation = ""
if normalized > 70:
interpretation = "Low perplexity - highly predictable text (AI-like)"
elif normalized > 40:
interpretation = "Medium perplexity - some predictability"
else:
interpretation = "High perplexity - varied and surprising (Human-like)"
return {
"score": round(normalized, 1),
"raw_perplexity": round(perplexity, 2),
"interpretation": interpretation
}
def calculate_burstiness(self) -> Dict:
"""
Calculate sentence length variation (burstiness).
Higher burstiness = more varied = likely human.
"""
if len(self.sentences) < 2:
return {"score": 0, "interpretation": "Insufficient sentences"}
sentence_lengths = [len(s.split()) for s in self.sentences]
if len(set(sentence_lengths)) == 1:
return {"score": 0, "interpretation": "Uniform sentence lengths (Highly AI-like)"}
mean_length = sum(sentence_lengths) / len(sentence_lengths)
variance = sum((x - mean_length) ** 2 for x in sentence_lengths) / len(sentence_lengths)
std_dev = math.sqrt(variance)
# Coefficient of variation (burstiness measure)
if mean_length > 0:
cv = (std_dev / mean_length) * 100
else:
cv = 0
# Normalize to 0-100
normalized = min(100, cv * 2)
interpretation = ""
if normalized > 70:
interpretation = "High burstiness - varied sentence lengths (Human-like)"
elif normalized > 40:
interpretation = "Medium burstiness - some variation"
else:
interpretation = "Low burstiness - uniform patterns (AI-like)"
return {
"score": round(normalized, 1),
"coefficient_of_variation": round(cv, 2),
"avg_sentence_length": round(mean_length, 1),
"interpretation": interpretation
}
def calculate_readability(self) -> Dict:
"""
Calculate Flesch-Kincaid readability score.
AI text often clusters in Grade 8-10 range.
"""
if len(self.sentences) == 0 or len(self.words) == 0:
return {"score": 0, "flesch_kincaid_grade": 0, "interpretation": "Insufficient text"}
# Count syllables (approximation)
def count_syllables(word: str) -> int:
word = word.lower()
vowels = 'aeiouy'
syllables = 0
prev_was_vowel = False
for char in word:
is_vowel = char in vowels
if is_vowel and not prev_was_vowel:
syllables += 1
prev_was_vowel = is_vowel
if word.endswith('e'):
syllables -= 1
return max(1, syllables)
total_syllables = sum(count_syllables(w) for w in self.words)
# Flesch-Kincaid Grade Level
avg_sentence_length = len(self.words) / len(self.sentences)
avg_syllables_per_word = total_syllables / len(self.words)
fk_grade = (0.39 * avg_sentence_length) + (11.8 * avg_syllables_per_word) - 15.59
fk_grade = max(0, fk_grade)
# Check if in suspicious AI range (Grade 6-12 is common for AI)
in_ai_range = 6 <= fk_grade <= 12
# Score based on how "suspiciously" typical the readability is
if in_ai_range:
# Closer to 8-10 is more suspicious
if 8 <= fk_grade <= 10:
score = 80 # Highly suspicious
interpretation = f"Grade {fk_grade:.1f} - Suspiciously typical AI readability range"
else:
score = 60 # Moderately suspicious
interpretation = f"Grade {fk_grade:.1f} - Within common AI readability range"
else:
score = 30 # Less suspicious
interpretation = f"Grade {fk_grade:.1f} - Outside typical AI readability range"
return {
"score": score,
"flesch_kincaid_grade": round(fk_grade, 1),
"avg_sentence_length": round(avg_sentence_length, 1),
"avg_syllables_per_word": round(avg_syllables_per_word, 2),
"interpretation": interpretation
}
def detect_ai_fingerprints(self) -> Dict:
"""
Detect specific AI writing patterns and fingerprints.
"""
text_lower = self.text.lower()
# Count AI transitions
transition_count = 0
found_transitions = []
for transition in self.AI_TRANSITIONS:
count = text_lower.count(transition)
if count > 0:
transition_count += count
found_transitions.append(f"'{transition}' ({count}x)")
# Count generic openers
opener_count = 0
found_openers = []
for opener in self.AI_OPENERS:
if text_lower.startswith(opener) or f". {opener}" in text_lower:
opener_count += 1
found_openers.append(opener)
# Check for repetitive n-grams (3-grams)
trigrams = [tuple(self.words[i:i+3]) for i in range(len(self.words)-2)]
trigram_counts = Counter(trigrams)
repetitive_trigrams = [(tg, count) for tg, count in trigram_counts.items() if count > 2]
# Calculate score
score = 0
details = []
# Transition word density
if len(self.words) > 0:
transition_density = transition_count / len(self.words) * 100
if transition_density > 2:
score += 30
details.append(f"High transition word density ({transition_density:.1f}%)")
elif transition_density > 1:
score += 15
details.append(f"Moderate transition word density ({transition_density:.1f}%)")
# Generic openers
if opener_count > 0:
score += min(25, opener_count * 10)
details.append(f"Found {opener_count} generic AI opener(s)")
# Repetitive patterns
if repetitive_trigrams:
score += min(20, len(repetitive_trigrams) * 5)
details.append(f"Found {len(repetitive_trigrams)} repetitive 3-gram pattern(s)")
# Check for formulaic structure
paragraph_starts = [p.strip()[:30].lower() for p in self.text.split('\n\n') if p.strip()]
formulaic_starts = sum(1 for p in paragraph_starts if any(
p.startswith(w) for w in ['the', 'this', 'in', 'it', 'there']
))
if len(paragraph_starts) > 2 and formulaic_starts / len(paragraph_starts) > 0.7:
score += 15
details.append("Formulaic paragraph structure detected")
interpretation = ""
if score > 60:
interpretation = "Strong AI fingerprints detected"
elif score > 30:
interpretation = "Some AI patterns detected"
else:
interpretation = "Few or no AI fingerprints"
return {
"score": min(100, score),
"transition_count": transition_count,
"found_transitions": found_transitions[:5], # Top 5
"opener_count": opener_count,
"found_openers": found_openers,
"repetitive_patterns": len(repetitive_trigrams),
"details": details,
"interpretation": interpretation
}
def analyze(self) -> Dict:
"""Run all analyses and return comprehensive results."""
perplexity = self.calculate_perplexity()
burstiness = self.calculate_burstiness()
readability = self.calculate_readability()
fingerprints = self.detect_ai_fingerprints()
# Calculate overall AI probability
# Weight: perplexity (30%), burstiness (20%), readability (20%), fingerprints (30%)
# Note: For perplexity, lower is more AI-like, so we invert
perplexity_contribution = perplexity["score"] * 0.30
burstiness_contribution = (100 - burstiness["score"]) * 0.20 # Invert: low burstiness = AI
readability_contribution = readability["score"] * 0.20
fingerprint_contribution = fingerprints["score"] * 0.30
overall_score = perplexity_contribution + burstiness_contribution + readability_contribution + fingerprint_contribution
# Determine verdict
if overall_score > 60:
verdict = "Likely AI-generated"
confidence = "High" if overall_score > 75 else "Medium"
elif overall_score > 35:
verdict = "Uncertain - Mixed signals"
confidence = "Low"
else:
verdict = "Likely human-written"
confidence = "High" if overall_score < 20 else "Medium"
return {
"overall_ai_probability": round(overall_score, 1),
"verdict": verdict,
"confidence": confidence,
"text_stats": {
"word_count": len(self.words),
"sentence_count": len(self.sentences),
"avg_word_length": round(sum(len(w) for w in self.words) / max(1, len(self.words)), 1)
},
"perplexity": perplexity,
"burstiness": burstiness,
"readability": readability,
"ai_fingerprints": fingerprints
}
def print_results(results: Dict):
"""Print analysis results in a formatted way."""
print("=" * 60)
print("AI CONTENT DETECTION RESULTS")
print("=" * 60)
print()
# Overall verdict
prob = results["overall_ai_probability"]
verdict = results["verdict"]
confidence = results["confidence"]
print(f"[STATS] OVERALL AI PROBABILITY: {prob}%")
print(f"[TEXT] VERDICT: {verdict}")
print(f"[TARGET] CONFIDENCE: {confidence}")
print()
# Text stats
stats = results["text_stats"]
print(f"[TREND] TEXT STATISTICS:")
print(f" Words: {stats['word_count']}")
print(f" Sentences: {stats['sentence_count']}")
print(f" Avg word length: {stats['avg_word_length']} chars")
print()
# Perplexity
p = results["perplexity"]
print(f"[CALC] PERPLEXITY ANALYSIS:")
print(f" Score: {p['score']}/100")
if p.get('raw_perplexity') is not None:
print(f" Raw perplexity: {p['raw_perplexity']}")
else:
print(f" Raw perplexity: N/A")
print(f" -> {p['interpretation']}")
print()
# Burstiness
b = results["burstiness"]
print(f"[RULE] BURSTINESS DETECTION:")
print(f" Score: {b['score']}/100")
if b.get('coefficient_of_variation') is not None:
print(f" Variation coefficient: {b['coefficient_of_variation']}%")
print(f" Avg sentence length: {b['avg_sentence_length']} words")
else:
print(f" Variation coefficient: N/A")
print(f" Avg sentence length: N/A")
print(f" -> {b['interpretation']}")
print()
# Readability
r = results["readability"]
print(f"[BOOK] READABILITY SCORING:")
print(f" AI-suspicion score: {r['score']}/100")
print(f" Flesch-Kincaid Grade: {r['flesch_kincaid_grade']}")
print(f" -> {r['interpretation']}")
print()
# AI Fingerprints
f = results["ai_fingerprints"]
print(f"[SEARCH] AI FINGERPRINT DETECTION:")
print(f" Score: {f['score']}/100")
print(f" Transition words found: {f['transition_count']}")
print(f" Generic openers found: {f['opener_count']}")
print(f" Repetitive patterns: {f['repetitive_patterns']}")
if f.get('found_transitions'):
print(f" Top transitions: {', '.join(f['found_transitions'][:3])}")
else:
print(f" Top transitions: (none detected)")
if f.get('details'):
print(f" Details: {'; '.join(f['details'])}")
else:
print(f" Details: (none)")
print(f" -> {f['interpretation']}")
print()
print("=" * 60)
print("[!] DISCLAIMER: AI detection is not 100% accurate.")
print(" Results should be used as guidance, not definitive proof.")
print("=" * 60)
def main():
"""Main entry point."""
import json
# Check for output format argument
output_json = '--json' in sys.argv
if output_json:
sys.argv.remove('--json')
# Read text from stdin or command line argument
if len(sys.argv) > 1:
# Read from file
file_path = sys.argv[1]
try:
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
except Exception as e:
print(f"Error reading file: {e}")
sys.exit(1)
else:
# Read from stdin
print("Enter text to analyze (Ctrl+D/Ctrl+Z when done):", file=sys.stderr)
text = sys.stdin.read()
if not text.strip():
print("Error: No text provided.")
print("Usage: python detect_ai.py [file_path] [--json]", file=sys.stderr)
sys.exit(1)
# Run analysis
detector = AIDetector(text)
results = detector.analyze()
# Print results - use JSON if requested
if output_json:
print(json.dumps(results, ensure_ascii=False, indent=2))
else:
print_results(results)
if __name__ == "__main__":
main()
FILE:references/ai_patterns.md
# AI Writing Patterns Reference
This document catalogs common patterns and fingerprints found in AI-generated text.
## Common AI Transition Words and Phrases
AI models tend to overuse certain transitional phrases:
### Formal Transitions
- Furthermore
- Moreover
- Additionally
- Consequently
- Therefore
- Thus
- Hence
- Nevertheless
- Nonetheless
- In addition
### Structural Transitions
- In conclusion
- To summarize
- In summary
- To conclude
- In closing
- Overall
- All in all
### Comparative Transitions
- On the other hand
- In contrast
- Conversely
- Similarly
- Likewise
- In comparison
- By comparison
### Sequential Transitions
- Firstly, secondly, thirdly...
- First, second, third...
- Finally
- Lastly
- Subsequently
- Next
- Then
## Generic Openers
AI text often begins with formulaic introductions:
### Context-setting Openers
- "In today's world..."
- "In the modern world..."
- "In recent years..."
- "With the development of..."
- "As technology advances..."
- "In the digital age..."
### Universal Truth Openers
- "As we all know..."
- "It is widely known that..."
- "It is universally accepted that..."
- "It is a well-known fact that..."
- "Everyone knows that..."
### Essay-style Openers
- "In this essay..."
- "This essay will..."
- "This paper will..."
- "The purpose of this..."
- "This article discusses..."
## Hedging Language
AI tends to use cautious, non-committal language:
### Uncertainty Markers
- "It is important to note..."
- "It should be noted..."
- "It is worth noting..."
- "One might argue..."
- "Some may say..."
- "It could be argued..."
### Qualifiers
- "Generally speaking..."
- "In most cases..."
- "Typically..."
- "Usually..."
- "Often..."
- "For the most part..."
## Repetitive Patterns
### N-gram Repetition
AI text may repeat certain word combinations:
- "the importance of"
- "it is important"
- "in order to"
- "due to the fact that"
- "the fact that"
### Structural Repetition
- Similar sentence beginnings across paragraphs
- Parallel structure overuse
- Repeated phrase patterns
## Formulaic Structures
### Five-Paragraph Essay Pattern
1. Introduction with thesis statement
2. Body paragraph with topic sentence
3. Body paragraph with topic sentence
4. Body paragraph with topic sentence
5. Conclusion restating thesis
### Problem-Solution Pattern
1. State the problem
2. Discuss causes
3. Propose solutions
4. Conclude with benefits
### Compare-Contrast Pattern
1. Introduction
2. Point A similarities
3. Point B differences
4. Overall comparison
5. Conclusion
## Lack of Human Elements
AI text often lacks:
### Personal Elements
- Personal anecdotes
- First-person experiences
- Specific memories
- Emotional reactions
- Individual opinions
### Contextual Specifics
- Regional references
- Cultural nuances
- Current slang
- Local knowledge
- Temporal references ("yesterday", "last week")
### Idiosyncrasies
- Typos or spelling variations
- Grammatical quirks
- Unique phrasings
- Personal abbreviations
- Inconsistent capitalization
## Readability Patterns
### AI-typical Characteristics
- Consistent sentence length (often 15-25 words)
- Grade 8-10 readability (Flesch-Kincaid)
- Limited vocabulary variation
- Predictable word choices
- Lack of complex or obscure terminology
### Human-typical Characteristics
- Variable sentence length
- Wider readability range
- Diverse vocabulary
- Surprising word choices
- Use of jargon or specialized terms
## Detection Tips
### Red Flags (High AI Probability)
1. Multiple transition words in close proximity
2. Generic opening sentences
3. Perfect grammar throughout
4. Consistent paragraph length
5. Lack of personal voice
6. Overly balanced arguments
7. Predictable structure
### Green Flags (Likely Human)
1. Personal stories or experiences
2. Variable sentence structures
3. Occasional grammatical quirks
4. Specific, concrete details
5. Emotional language
6. Unique perspectives
7. Idiomatic expressions
## Limitations
Remember that:
- Human writers can adopt formal styles
- AI text can be edited to sound human
- Professional writing often follows patterns
- Non-native speakers may write "AI-like" text
- Results should be interpreted with caution
Identify and eliminate traces of AI-generated text, making writing sound more natural and human.
---
name: humanizer-ai
description: Identify and eliminate traces of AI-generated text, making writing sound more natural and human.
---
# Humanizer AI
Identify and eliminate traces of AI-generated text, making writing sound natural and human.
## Use Cases
Use this skill when users mention "de-AI," "humanize," "make it not sound like AI wrote it," "eliminate AI writing traces," "polish text," or request humanization of text. Also applies to cleaning up residual AI chat tone ("Hope this helps," "Certainly!") or replacing high-frequency AI vocabulary.
## Process
1. **Scan for Patterns** — Check text against AI patterns listed in `references/patterns.md`
2. **Rewrite Point by Point** — Replace each problematic expression with a natural alternative while preserving core meaning
3. **Inject Soul** — Not just remove AI patterns, but give the writing a human voice and rhythm
## Output Format
1. Revision summary (brief explanation of what was changed)
2. Rewritten text
## Soul First
Merely removing AI traces isn't enough—lifeless text stands out just as much. Good writing has a person behind it.
### Typical Signs of Soulless Writing:
- Every sentence has exactly the same length and structure
- Only neutral statements, no perspective
- No acknowledgment of uncertainty or mixed feelings
- Avoids "I" when it could be used
- No humor, no edge
- Reads like a press release or Wikipedia
### Ways to Add Soul:
**Have an opinion** — Don't just state facts; react to them. "I honestly don't know what to make of this" is more real than neutrally listing pros and cons.
**Vary the rhythm** — Short sentences hit hard. Long ones take their time. Alternate between them.
**Acknowledge complexity** — Real people have mixed feelings. "It's impressive but also kind of unsettling" is more human than "It's impressive."
**Use "I" appropriately** — First person isn't unprofessional; it's honest. "I've been thinking about..." or "One question that gets me is..." both suggest a real person wrestling with ideas.
**Allow some mess** — Perfect structure looks algorithmic. Occasional asides, half-formed thoughts—these are human signatures.
### Soulless vs. With Soul
**Soulless but "clean":**
> The experiment produced interesting results. The agent generated 3 million lines of code. Some developers were impressed, others skeptical. The implications remain unclear.
**Alive:**
> I honestly don't know what to make of this. Three million lines of code, generated while humans slept. Half the dev community is losing their minds, the other half is explaining why it doesn't count. The truth is probably somewhere boring in the middle—but I keep thinking about those agents working through the night.
## Quick Reference: Most Common Patterns
| # | Pattern | Problem Words | Rewrite Direction |
|---|---------|---------------|-------------------|
| 7 | AI high-frequency words | Additionally, crucial, pivotal, showcase, vibrant, landscape, underscore, testament... | Replace with everyday vocabulary |
| 1 | Overstating significance | serves as a testament, pivotal moment, underscores the importance... | State facts directly |
| 3 | -ing pseudo-analysis | highlighting, ensuring, reflecting, symbolizing, contributing to... | Replace with concrete description |
| 8 | Copula substitutes | serves as, stands as, boasts, features... | Just use is/are/has |
| 9 | Negative parallelism | It's not just about... it's... / Not only... but... | Get to the point directly |
| 10 | Rule of three | Three-item lists (innovation, inspiration, and industry insights) | Combine or simplify |
| 22 | Filler words | In order to, due to the fact that, at this point in time... | Use simpler phrasing |
| 13 | Em dash abuse | AI uses excessive em dashes for "impact" | Replace with commas or periods |
See `references/patterns.md` for detailed patterns and all examples.
FILE:references/patterns.md
# AI Writing Patterns Detailed Reference
## Content Patterns
### 1. Overstating Significance, Legacy, and Broader Trends
**Keywords:** stands as, serves as, is a testament/reminder, vital/significant/crucial/pivotal/key role, underscores/highlights its importance, reflects broader, symbolizing its ongoing, contributing to the, setting the stage for, marking/shaping the, represents/marks a shift, key turning point, evolving landscape, focal point, indelible mark, deeply rooted
**Problem:** LLMs inflate significance by adding statements that "an aspect represents/contributes to a larger theme."
**Before:**
> The Statistical Institute of Catalonia was officially established in 1989, marking a pivotal moment in the evolution of regional statistics in Spain. This initiative was part of a broader movement across Spain to decentralize administrative functions and enhance regional governance.
**After:**
> The Statistical Institute of Catalonia was established in 1989 to collect and publish regional statistics independently from Spain's national statistics office.
### 2. Overstating Notability and Media Coverage
**Keywords:** independent coverage, local/regional/national media outlets, written by a leading expert, active social media presence
**Problem:** LLMs overcompensate by asserting notability and listing sources without context.
**Before:**
> Her views have been cited in The New York Times, BBC, Financial Times, and The Hindu. She maintains an active social media presence with over 500,000 followers.
**After:**
> In a 2024 New York Times interview, she argued that AI regulation should focus on outcomes rather than methods.
### 3. Shallow -ing Analysis
**Keywords:** highlighting, underscoring, emphasizing, ensuring, reflecting, symbolizing, contributing to, cultivating, fostering, encompassing, showcasing
**Problem:** AI appends present participle phrases to sentences to create a false sense of depth.
**Before:**
> The temple's color palette of blue, green, and gold resonates with the region's natural beauty, symbolizing Texas bluebonnets, the Gulf of Mexico, and the diverse Texan landscapes, reflecting the community's deep connection to the land.
**After:**
> The temple uses blue, green, and gold colors. The architect said these were chosen to reference local bluebonnets and the Gulf coast.
### 4. Promotional/Advertising Language
**Keywords:** boasts a, vibrant, rich (figurative), profound, enhancing its, showcasing, exemplifies, commitment to, natural beauty, nestled, in the heart of, groundbreaking (figurative), renowned, breathtaking, must-visit, stunning
**Problem:** LLMs struggle to maintain a neutral tone, especially on "cultural heritage" topics.
**Before:**
> Nestled within the breathtaking region of Gonder in Ethiopia, Alamata Raya Kobo stands as a vibrant town with a rich cultural heritage and stunning natural beauty.
**After:**
> Alamata Raya Kobo is a town in the Gonder region of Ethiopia, known for its weekly market and 18th-century church.
### 5. Vague Attribution and Weasel Words
**Keywords:** Industry reports, Observers have cited, Experts argue, Some critics argue, several sources/publications (when actually citing very few)
**Problem:** AI attributes views to vague authorities without specific sources.
**Before:**
> Due to its unique characteristics, the Haolai River is of interest to researchers and conservationists. Experts believe it plays a crucial role in the regional ecosystem.
**After:**
> The Haolai River supports several endemic fish species, according to a 2019 survey by the Chinese Academy of Sciences.
### 6. Formulaic "Challenges and Outlook" Section
**Keywords:** Despite its... faces several challenges..., Despite these challenges, Challenges and Legacy, Future Outlook
**Problem:** Many LLM-generated texts contain a formulaic "Challenges" section.
**Before:**
> Despite its industrial prosperity, Korattur faces challenges typical of urban areas, including traffic congestion and water scarcity. Despite these challenges, with its strategic location and ongoing initiatives, Korattur continues to thrive as an integral part of Chennai's growth.
**After:**
> Traffic congestion increased after 2015 when three new IT parks opened. The municipal corporation began a stormwater drainage project in 2022 to address recurring floods.
## Language and Grammar Patterns
### 7. Overused "AI Vocabulary"
**High-frequency AI words:** Additionally, align with, crucial, delve, emphasizing, enduring, enhance, fostering, garner, highlight (verb), interplay, intricate/intricacies, key (adjective), landscape (abstract noun), pivotal, showcase, tapestry (abstract noun), testament, underscore (verb), valuable, vibrant
**Problem:** These words appear with extremely high frequency in post-2023 texts, often co-occurring.
**Before:**
> Additionally, a distinctive feature of Somali cuisine is the incorporation of camel meat. An enduring testament to Italian colonial influence is the widespread adoption of pasta in the local culinary landscape, showcasing how these dishes have integrated into the traditional diet.
**After:**
> Somali cuisine also includes camel meat, which is considered a delicacy. Pasta dishes, introduced during Italian colonization, remain common, especially in the south.
### 8. Avoiding is/are (Copula Substitution)
**Keywords:** serves as, stands as, marks, represents [a], boasts, features, offers [a]
**Problem:** LLMs use wordy constructions in place of simple copulas.
**Before:**
> Gallery 825 serves as LAAA's exhibition space for contemporary art. The gallery features four separate spaces and boasts over 3,000 square feet.
**After:**
> Gallery 825 is LAAA's exhibition space for contemporary art. The gallery has four rooms totaling 3,000 square feet.
### 9. Negative Parallelism
**Keywords:** Not only...but..., It's not just about... it's...
**Problem:** These constructions are overused in AI writing.
**Before:**
> It's not just about the beat riding under the vocals; it's part of the aggression and atmosphere. It's not merely a song, it's a statement.
**After:**
> The heavy beat adds to the aggressive tone.
### 10. Rule of Three
**Problem:** AI forces points into three-item groupings to appear comprehensive.
**Before:**
> The event features keynote sessions, panel discussions, and networking opportunities. Attendees can expect innovation, inspiration, and industry insights.
**After:**
> The event includes talks and panels. There's also time for informal networking between sessions.
### 11. Excessive Synonym Substitution (Elegant Variation)
**Problem:** AI has repetition penalty coding that leads to excessive synonym substitution.
**Before:**
> The protagonist faces many challenges. The main character must overcome obstacles. The central figure eventually triumphs. The hero returns home.
**After:**
> The protagonist faces many challenges but eventually triumphs and returns home.
### 12. False Ranges
**Problem:** AI uses "from X to Y" constructions where X and Y are not on the same meaningful scale.
**Before:**
> Our journey through the universe has taken us from the singularity of the Big Bang to the grand cosmic web, from the birth and death of stars to the enigmatic dance of dark matter.
**After:**
> The book covers the Big Bang, star formation, and current theories about dark matter.
## Stylistic Patterns
### 13. Em Dash Abuse
**Problem:** AI uses em dashes more frequently than humans to mimic "punchy" sales copy style.
**Before:**
> The term is primarily promoted by Dutch institutions—not by the people themselves. You don't say "Netherlands, Europe" as an address—yet this mislabeling continues—even in official documents.
**After:**
> The term is primarily promoted by Dutch institutions, not by the people themselves. You don't say "Netherlands, Europe" as an address, yet this mislabeling continues in official documents.
### 14. Bold Abuse
**Problem:** AI mechanically bolds phrases for emphasis.
**Before:**
> It blends **OKRs (Objectives and Key Results)**, **KPIs (Key Performance Indicators)**, and visual strategy tools such as the **Business Model Canvas (BMC)** and **Balanced Scorecard (BSC)**.
**After:**
> It blends OKRs, KPIs, and visual strategy tools like the Business Model Canvas and Balanced Scorecard.
### 15. Vertical Lists with Inline Headers
**Problem:** AI outputs list items starting with bold headers followed by colons.
**Before:**
> - **User Experience:** The user experience has been significantly improved with a new interface.
> - **Performance:** Performance has been enhanced through optimized algorithms.
> - **Security:** Security has been strengthened with end-to-end encryption.
**After:**
> The update improves the interface, speeds up load times through optimized algorithms, and adds end-to-end encryption.
### 16. Title Case in Headings
**Problem:** AI capitalizes every major word in headings.
**Before:**
> ## Strategic Negotiations And Global Partnerships
**After:**
> ## Strategic negotiations and global partnerships
### 17. Emojis
**Problem:** AI often decorates headings or bullet points with emojis.
**Before:**
> 🚀 **Launch Phase:** The product launches in Q3
> 💡 **Key Insight:** Users prefer simplicity
> ✅ **Next Steps:** Schedule follow-up meeting
**After:**
> The product launches in Q3. User research showed a preference for simplicity. Next step: schedule a follow-up meeting.
### 18. Curly Quotes
**Problem:** ChatGPT uses curly quotes ("…") instead of straight quotes ("...").
**Before:**
> He said "the project is on track" but others disagreed.
**After:**
> He said "the project is on track" but others disagreed.
## Communication Patterns
### 19. Residual Collaborative Chat Tone
**Keywords:** I hope this helps, Of course!, Certainly!, You're absolutely right!, Would you like..., let me know, here is a...
**Problem:** Text written as chatbot communication is pasted as formal content.
**Before:**
> Here is an overview of the French Revolution. I hope this helps! Let me know if you'd like me to expand on any section.
**After:**
> The French Revolution began in 1789 when financial crisis and food shortages led to widespread unrest.
### 20. Knowledge Cutoff Disclaimers
**Keywords:** as of [date], Up to my last training update, While specific details are limited/scarce..., based on available information...
**Problem:** AI disclaimers about incomplete information are left in the text.
**Before:**
> While specific details about the company's founding are not extensively documented in readily available sources, it appears to have been established sometime in the 1990s.
**After:**
> The company was founded in 1994, according to its registration documents.
### 21. Sycophantic/Servile Tone
**Problem:** Excessively positive, ingratiating language.
**Before:**
> Great question! You're absolutely right that this is a complex topic. That's an excellent point about the economic factors.
**After:**
> The economic factors you mentioned are relevant here.
## Filler Words and Vague Expressions
### 22. Filler Phrases
| Original | Rewrite |
|----------|---------|
| In order to achieve this goal | To achieve this |
| Due to the fact that it was raining | Because it was raining |
| At this point in time | Now |
| In the event that you need help | If you need help |
| The system has the ability to process | The system can process |
| It is important to note that the data shows | The data shows |
### 23. Overly Hedge Words
**Problem:** Excessive qualification of statements.
**Before:**
> It could potentially possibly be argued that the policy might have some effect on outcomes.
**After:**
> The policy may affect outcomes.
### 24. Generic Positive Conclusions
**Problem:** Vaguely optimistic endings.
**Before:**
> The future looks bright for the company. Exciting times lie ahead as they continue their journey toward excellence. This represents a major step in the right direction.
**After:**
> The company plans to open two more locations next year.Use the favicons Node.js library to generate multi-platform website icons (Favicons).
---
name: favicons
description: Use the favicons Node.js library to generate multi-platform website icons (Favicons).
---
# Favicons
Generate cross-platform website icons using the Node.js `favicons` library.
## Use Cases
Use this skill when the user needs to generate website icons, create a PWA icon set for a website, generate app icons for different platforms (iOS, Android, Windows), or produce a complete icon package including HTML tags and manifest files.
## Installing Dependencies
Ensure `favicons` is installed in the project before execution:
```bash
npm install favicons
```
## Quick Start
```javascript
import { favicons } from "favicons";
const response = await favicons(source, configuration);
```
## Workflow
1. **Confirm Source Image**: Requires a clear app icon source image (recommended 512x512 or larger, supports PNG/SVG)
2. **Configure Options**: Set app name, icon path, platform toggles, etc., as needed
3. **Execute Generation**: Run the script to generate icon files
4. **Output Files**: Obtain image files, configuration files, and HTML tags
## Executing Icon Generation
Use the bundled script to generate icons:
```bash
node <skill-path>/scripts/generate_favicons.js <source-image> <output-directory> <config-JSON>
```
### Example
```bash
# Basic usage
node scripts/generate_favicons.js ./logo.png ./dist
# Full configuration
node scripts/generate_favicons.js ./logo.png ./dist '{
"appName": "My App",
"appShortName": "App",
"background": "#2196F3",
"icons": {"android": true, "appleIcon": true, "windows": true}
}'
```
## Configuration Reference
For detailed configuration options, refer to [config_reference.md](references/config_reference.md).
### Common Configuration
| Option | Description |
| :--- | :--- |
| `appName` | Application name |
| `appShortName` | Application short name (displayed on desktop) |
| `path` | Icon deployment path prefix |
| `background` | Icon background color |
| `icons.android` | Generate Android icons |
| `icons.appleIcon` | Generate Apple Touch icons |
| `icons.favicons` | Generate generic favicons |
### Disabling Specific Platforms
```javascript
{
icons: {
android: false, // Skip Android icons
appleStartup: false, // Skip Apple startup images
yandex: false // Skip Yandex icons
}
}
```
## Output Files
The generated directory contains:
- **Image Files**: PNG icons of various sizes
- **Configuration Files**: `manifest.json`, `browserconfig.xml`
- **HTML Tag File**: `favicon-tags.html` (can be directly copied into `<head>`)
## FAQ
**Why are some icons missing?**
Some icons (such as macOS SVG, Windows tile silhouette effects) require additional module support; the project will follow up continuously.
**Generation failed?**
- Ensure the source image exists and is in the correct format
- Check that Node.js version >= 14
- Ensure the `favicons` package is installed correctly
FILE:scripts/generate_favicons.js
/**
* Favicons Generator - Generate website icons using the favicons library
*
* Usage:
* node generate_favicons.js <source-image-path> <output-directory> [config-JSON]
*
* Example:
* node generate_favicons.js ./logo.png ./dist '{"appName":"My App"}'
*/
const { favicons } = require('favicons');
const fs = require('fs').promises;
const path = require('path');
async function main() {
const args = process.argv.slice(2);
if (args.length < 2) {
console.error('Usage: node generate_favicons.js <source-image-path> <output-directory> [config-JSON]');
process.exit(1);
}
const source = args[0];
const dest = args[1];
const htmlBasename = 'favicon-tags.html';
// Default configuration
const config = args[2] ? JSON.parse(args[2]) : {};
// Ensure output directory exists
await fs.mkdir(dest, { recursive: true });
console.log(`🔍 Source image: source`);
console.log(`📁 Output directory: dest`);
console.log('');
try {
const response = await favicons(source, {
path: '/', // Path where icons will be stored on the server
appName: config.appName || null,
appShortName: config.appShortName || null,
appDescription: config.appDescription || null,
developerName: config.developerName || null,
developerURL: config.developerURL || null,
background: config.background || '#fff',
theme_color: config.theme_color || '#fff',
icons: {
android: config.android !== undefined ? config.android : true,
appleIcon: config.appleIcon !== undefined ? config.appleIcon : true,
appleStartup: config.appleStartup !== undefined ? config.appleStartup : false,
favicons: config.favicons !== undefined ? config.favicons : true,
windows: config.windows !== undefined ? config.windows : true,
yandex: config.yandex !== undefined ? config.yandex : false,
},
...config
});
// Save image files
console.log('🖼️ Generating image files...');
await Promise.all(
response.images.map(async (image) => {
const filePath = path.join(dest, image.name);
await fs.writeFile(filePath, image.contents);
console.log(` ✅ image.name`);
})
);
// Save configuration files
console.log('\n📄 Generating configuration files...');
await Promise.all(
response.files.map(async (file) => {
const filePath = path.join(dest, file.name);
await fs.writeFile(filePath, file.contents);
console.log(` ✅ file.name`);
})
);
// Save HTML tags
console.log('\n🏷️ Generating HTML tag file...');
await fs.writeFile(
path.join(dest, htmlBasename),
response.html.join('\n')
);
console.log(` ✅ htmlBasename`);
// Summary statistics
console.log('\n📊 Summary statistics:');
console.log(` Image files: response.images.length`);
console.log(` Configuration files: response.files.length`);
console.log(` HTML tags: response.html.length`);
console.log('\n✅ Icon generation complete!');
} catch (error) {
console.error(`\n❌ Error: error.message`);
process.exit(1);
}
}
main();
FILE:references/config_reference.md
# Favicons Configuration Reference
## Complete Configuration Options
| Option | Type/Default | Description |
| :--- | :--- | :--- |
| `path` | `string` | Path where icons will be stored on the server |
| `appName` | `string`| null` | Application name |
| `appShortName` | `string`| null` | Application short name; falls back to `appName` if not set |
| `appDescription` | `string`| null` | Application description |
| `developerName` | `string`| null` | Developer name |
| `developerURL` | `string`| null` | Developer URL |
| `dir` | `"auto"` | Text direction (`auto`, `ltr`, `rtl`) |
| `lang` | `"en-US"` | Language setting |
| `background` | `"#fff"` | Background color for flattened icons |
| `theme_color` | `"#fff"` | Theme color |
| `appleStatusBarStyle` | `"black-translucent"` | iOS status bar style |
| `display` | `"standalone"` | Preferred display mode |
| `orientation` | `"any"` | Default screen orientation |
| `scope` | `"/"` | Navigation scope of the application |
| `start_url` | `"/?homescreen=1"` | Start URL when launched from device |
| `version` | `"1.0"` | Application version number |
| `pixel_art` | `false` | Whether to preserve sharp edges for pixel art |
| `manifestMaskable` | `false` | Whether to generate maskable icons |
| `loadManifestWithCredentials` | `false` | Whether to request manifest file with credentials |
## Icon Platform Toggles
| Option | Type | Description |
| :--- | :--- | :--- |
| `android` | `boolean` or object | Android home screen icons |
| `appleIcon` | `boolean` or object | Apple Touch icons |
| `appleStartup` | `boolean` or object | Apple startup images |
| `favicons` | `boolean` or object | Generic favicons |
| `windows` | `boolean` or object | Windows 8 tile icons |
| `yandex` | `boolean` or object | Yandex browser icons |
Options supported by platform objects:
- `offset`: Percentage offset
- `background`: Background handling method
## Shortcuts Configuration
```javascript
shortcuts: [
{
name: "View Inbox",
short_name: "Inbox",
description: "View inbox messages",
url: "/inbox",
icon: "test/inbox_shortcut.png"
}
]
```
## Output File Manifest
### response.images
Array of image file buffers to be written:
- **Android**: 9 sizes ranging from `android-chrome-36x36.png` to `android-chrome-512x512.png`
- **Apple Icon**: 13 files ranging from `apple-touch-icon-57x57.png` to `apple-touch-icon-1024x1024.png`
- **Apple Startup Images**: 30 sizes covering resolutions for various iPhone/iPad generations
- **Favicons**: `favicon-16x16.png`, `favicon-32x32.png`, `favicon-48x48.png`, `favicon.ico`
- **Windows**: 5 sizes ranging from `mstile-70x70.png` to `mstile-310x310.png`
- **Yandex**: `yandex-browser-50x50.png`
### response.files
Configuration files to be written:
- `manifest.json` - Web App Manifest
- `browserconfig.xml` - Windows tile configuration
### response.html
Array of tag strings to be inserted into the HTML `<head>`
## Accessing Default Configuration Programmatically
```javascript
import { config } from 'favicons';
// Access default configuration
console.log(config);
```Vercel CLI skill for deploying and managing Vercel projects from the terminal.
---
name: vercel-cli
description: Vercel CLI skill for deploying and managing Vercel projects from the terminal.
metadata: {"openclaw":{"emoji":"▲"}}
---
# Vercel CLI
Vercel CLI skill for deploying and managing Vercel projects from the terminal. Use when the user wants to deploy, list, inspect, rollback, or manage Vercel deployments; configure domains, SSL certificates, environment variables; manage teams or view usage; or needs help with `vercel` CLI commands.
## Environment Setup
**Install Vercel CLI:**
```bash
pnpm i -g vercel
```
**Update:**
```bash
pnpm i -g vercel@latest
```
**Verify Version:**
```bash
vercel --version
```
## Authentication
**Interactive Login:**
```bash
vercel login
```
**CI/CD Environment (Recommended):**
1. Create an access token on the [Tokens page](https://vercel.com/account/tokens)
2. Set the `VERCEL_TOKEN` environment variable
> Prefer using the `VERCEL_TOKEN` environment variable over the `--token` flag to avoid exposing the token in process lists or logs.
## Core Workflows
### Deployment
```bash
vercel # Deploy to preview environment
vercel deploy --prod # Deploy to production environment
vercel build # Build locally
vercel dev # Develop locally simulating Vercel environment
```
### Project Linking
```bash
vercel init # Initialize from official template
vercel link # Link local directory to Vercel project
vercel pull # Pull remote environment variables to local
```
### Deployment Management
```bash
vercel list [project] # List recent deployments
vercel inspect [url/id] # View deployment details (add --logs for build logs)
vercel logs [url] # View runtime logs (--follow for real-time tracking)
vercel promote [url/id] # Promote specified deployment to production
vercel redeploy [url/id] # Rebuild and redeploy
vercel rollback # Rollback production environment
vercel remove [url] # Remove deployment or project
vercel bisect # Bisect to locate problematic deployment
```
### Domains and Certificates
```bash
vercel alias set [url] [domain] # Set custom domain
vercel alias rm [domain] # Remove domain alias
vercel domains ls # List domains
vercel domains add [domain] # Add domain
vercel certs ls # List SSL certificates
vercel certs issue [domain] # Issue certificate for domain
```
### Environment Variables
```bash
vercel env ls # List environment variables
vercel env add [name] [env] # Add (env optional: production/preview/development)
vercel env rm [name] [env] # Remove environment variable
vercel env pull [file] # Pull to local file
```
### Account and Teams
```bash
vercel whoami # Current logged-in username
vercel teams list # List teams
vercel switch [team] # Switch team
vercel usage # View usage and billing
```
### Advanced Tools
```bash
vercel api [endpoint] # Make authenticated API request (Beta)
vercel curl [path] # HTTP request (Beta)
vercel cache purge # Purge CDN cache
vercel blob # Vercel Blob storage operations
vercel integration # Manage integrations
vercel mcp # MCP client configuration
```
## Key Notes
- Most commands support `--help` for detailed parameters: `vercel help [command]`
- `vercel` is equivalent to `vercel deploy`
- `--prod` / `--production` flag deploys to production environment
- `--follow` for `logs` command enables real-time log tracking
- Use `VERCEL_TOKEN` environment variable for automated authentication; do not expose token on the command line
## Reference Documentation
- REST API: https://vercel.com/docs/rest-api
- Create Token: https://vercel.com/account/tokens
- See `references/commands.md` for detailed command parameter descriptions
FILE:references/commands.md
# Vercel CLI Command Reference
## Project Initialization and Deployment
### vercel init
Initialize a sample project from the official template library.
```bash
vercel init [template-name]
```
### vercel / vercel deploy
Deploy the current project. Deploys to preview environment by default.
```bash
vercel [path] [options]
vercel deploy [path] [options]
```
Common options:
- `--prod` / `--production`: Deploy to production environment
- `--token <token>`: Specify authentication token (not recommended; prefer `VERCEL_TOKEN` environment variable)
- `--yes`: Skip all confirmation prompts
- `--force`: Force rebuild
### vercel build
Build the project locally (simulates Vercel build environment).
```bash
vercel build [options]
```
Common options:
- `--prod`: Build production environment version
- `--token <token>`: Authentication token
### vercel dev
Simulate Vercel deployment environment locally for development and testing.
```bash
vercel dev [port]
```
Default port is 3000.
### vercel link
Link the local directory to a Vercel project.
```bash
vercel link [options]
```
### vercel pull
Pull remote environment variables and project settings to local.
```bash
vercel pull [options]
```
Common options:
- `--environment production|preview|development`: Specify environment
- `--yes`: Automatically overwrite local variables with same name
---
## Deployment and Version Management
### vercel list
List deployment records for the current account/team.
```bash
vercel list [project] [options]
```
Common options:
- `--limit <number>`: Limit number of results returned (default 20)
### vercel inspect
View detailed information for a specified deployment.
```bash
vercel inspect <url|id> [options]
```
Common options:
- `--logs`: Display build and runtime logs
- `--wait`: Wait for deployment to complete before output
### vercel logs
View runtime logs for a deployment.
```bash
vercel logs <url> [options]
```
Common options:
- `--follow` / `-f`: Real-time tracking of new logs
- `--limit <number>`: Limit number of entries returned
### vercel promote
Promote a specified preview deployment to the current production deployment.
```bash
vercel promote <url|id> [options]
```
### vercel redeploy
Rebuild and redeploy based on an existing deployment.
```bash
vercel redeploy <url|id> [options]
```
Common options:
- `--prod`: Also deploy to production environment
### vercel rollback
Roll back the production environment to the previous stable deployment.
```bash
vercel rollback [options]
```
### vercel remove
Remove a specified deployment or project.
```bash
vercel remove <url|id|project> [options]
```
Note: Deleting a project is permanent.
### vercel bisect
Quickly locate the problematic deployment using binary search.
```bash
vercel bisect [options]
```
Requires specifying "good" and "bad" deployment versions.
---
## Domain and Certificate Management
### vercel alias set
Set a custom domain alias for a deployment.
```bash
vercel alias set <url> <domain> [options]
```
### vercel alias rm
Remove a domain alias.
```bash
vercel alias rm <domain> [options]
```
### vercel domains ls
List all domains under the account.
```bash
vercel domains ls [options]
```
### vercel domains add
Add a domain to a specified project.
```bash
vercel domains add <domain> [project] [options]
```
Common options:
- `--delegated`: Delegate DNS management to Vercel
- `--renew`: Auto-renew
### vercel domains buy
Purchase a domain directly through the CLI.
```bash
vercel domains buy <domain> [options]
```
### vercel dns ls
View DNS records for a domain.
```bash
vercel dns ls [domain] [options]
```
### vercel certs ls
List all SSL certificates under the account.
```bash
vercel certs ls [options]
```
### vercel certs issue
Issue a new SSL certificate for a domain.
```bash
vercel certs issue <domain> [options]
```
---
## Environment Variable Management
### vercel env ls
List environment variables for the project.
```bash
vercel env ls [options]
```
### vercel env add
Add an environment variable.
```bash
vercel env add <name> [env] [options]
```
Parameters:
- `name`: Variable name
- `env`: Optional `production`, `preview`, or `development` (adds to all three environments if not specified)
Common options:
- `-e <value>` / `--environment <env>`: Specify target environment
- `--encrypt`: Encrypted storage (default)
### vercel env rm
Remove an environment variable.
```bash
vercel env rm <name> [env] [options]
```
### vercel env pull
Pull environment variables to a local `.env` file.
```bash
vercel env pull [file] [options]
```
Generates `.env.local` by default.
### vercel env update
Update the value of an existing environment variable.
```bash
vercel env update <name> [env] [options]
```
### vercel target list
Manage custom deployment targets.
```bash
vercel target list [options]
```
---
## Team and Account Management
### vercel whoami
Display the username of the currently logged-in account.
```bash
vercel whoami
```
### vercel teams list
List all teams the current user belongs to.
```bash
vercel teams list [options]
```
### vercel switch
Switch the team context for current operations.
```bash
vercel switch [team] [options]
```
### vercel usage
View usage and billing statistics for the current account.
```bash
vercel usage [options]
```
Common options:
- `--month <YYYY-MM>`: View specified month
### vercel contract
View contract commitment information.
```bash
vercel contract
```
---
## Cache and Storage
### vercel cache purge
Purge CDN or data cache.
```bash
vercel cache purge [options]
```
Common options:
- `--team <team>`: Specify team
- `--token <token>`: Authentication token
### vercel blob
Interact with Vercel Blob storage.
```bash
vercel blob [subcommand]
```
Subcommands:
- `vercel blob ls`: List blobs
- `vercel blob rm <url>`: Remove blob
- `vercel blob url <key>`: Get blob URL
---
## Other Utilities
### vercel api
Make authenticated Vercel API requests (Beta).
```bash
vercel api <endpoint> [options]
```
Common options:
- `--method GET|POST|PATCH|DELETE`: HTTP method
- `--body <json>`: Request body
### vercel curl
Make HTTP requests to deployments bypassing protection mechanisms (Beta).
```bash
vercel curl <path> [options]
```
### vercel integration
Manage marketplace integrations and resource configurations.
```bash
vercel integration [subcommand]
```
### vercel mcp
Set up MCP (Model Context Protocol) client configuration.
```bash
vercel mcp [options]
```
### vercel webhooks
Manage webhooks (Beta).
```bash
vercel webhooks [subcommand]
```
### vercel project ls
Manage projects.
```bash
vercel project ls [options]
```
### vercel redirects list
List redirect rules for the project.
```bash
vercel redirects list [options]
```
### vercel telemetry
Enable or disable telemetry data collection.
```bash
vercel telemetry [enable|disable]
```
### vercel buy
Purchase credits, plugins, subscriptions, or domains via CLI.
```bash
vercel buy [item] [options]
```
### vercel help
Get command help.
```bash
vercel help [command]
```Use MarkItDown to convert various files (PDF, Word, Excel, PPT, images, audio, HTML, CSV, JSON, etc.) to Markdown format for LLM processing and text analysis...
---
name: microsoft-markitdown
description: Use MarkItDown to convert various files (PDF, Word, Excel, PPT, images, audio, HTML, CSV, JSON, etc.) to Markdown format for LLM processing and text analysis. Also supports content extraction from ZIP archives, YouTube videos, and EPUB e-books.
---
# Microsoft MarkItDown
A Python tool for converting various file types to Markdown format.
## Use Cases
Use this skill when users mention scenarios like "convert file to Markdown," "extract document content," "file to Markdown," or "extract text from PDF/Word/Excel."
## Installation
```bash
pip install 'markitdown[all]'
```
Optional dependency group installations (to save space):
| Tag | Description |
|------|-------------|
| `[pptx]` | PowerPoint files |
| `[docx]` | Word files |
| `[xlsx]` | Excel files |
| `[xls]` | Legacy Excel files |
| `[pdf]` | PDF files |
| `[outlook]` | Outlook emails |
| `[az-doc-intel]` | Azure Document Intelligence |
| `[audio-transcription]` | Audio transcription (wav/mp3) |
| `[youtube-transcription]` | YouTube video transcription |
## Command Line Usage
```bash
# Basic usage: output to stdout
markitdown path-to-file.pdf > document.md
# Specify output file
markitdown path-to-file.pdf -o document.md
# Pipe input
cat path-to-file.pdf | markitdown
# Use Azure Document Intelligence
markitdown path-to-file.pdf -o document.md -d -e "<document_intelligence_endpoint>"
# List installed plugins
markitdown --list-plugins
# Enable plugins
markitdown --use-plugins path-to-file.pdf
```
## Python API Usage
```python
from markitdown import MarkItDown
md = MarkItDown(enable_plugins=False) # True to enable plugins
result = md.convert("test.xlsx")
print(result.text_content)
```
### With LLM Image Description (Only supports pptx and image files)
```python
from markitdown import MarkItDown
from openai import OpenAI
client = OpenAI()
md = MarkItDown(llm_client=client, llm_model="gpt-4o", llm_prompt="optional custom prompt")
result = md.convert("example.jpg")
print(result.text_content)
```
### With Azure Document Intelligence
```python
from markitdown import MarkItDown
md = MarkItDown(docintel_endpoint="<document_intelligence_endpoint>")
result = md.convert("test.pdf")
print(result.text_content)
```
### Using markitdown-ocr Plugin (OCR for Images Embedded in PDF/DOCX/PPTX/XLSX)
```python
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(
enable_plugins=True,
llm_client=OpenAI(),
llm_model="gpt-4o",
)
result = md.convert("document_with_images.pdf")
print(result.text_content)
```
## Supported Formats Overview
| Format | Extensions | Dependency Tag |
|--------|------------|----------------|
| PDF | .pdf | `[pdf]` |
| PowerPoint | .pptx | `[pptx]` |
| Word | .docx | `[docx]` |
| Excel | .xlsx / .xls | `[xlsx]` / `[xls]` |
| Images | .jpg/.png etc. | Built-in (OCR requires `[audio-transcription]` + LLM) |
| Audio | .mp3/.wav | `[audio-transcription]` |
| HTML | .html | Built-in |
| CSV/JSON/XML | .csv/.json/.xml | Built-in |
| ZIP | .zip | Built-in (iterates contents) |
| YouTube | URL | `[youtube-transcription]` |
| EPUB | .epub | Built-in |
| Outlook | .msg | `[outlook]` |
## Agent Execution Workflow
When a user requests file conversion:
1. **Confirm Input File**: Obtain the file path.
2. **Install Dependencies**: Check if markitdown is installed and suggest installing corresponding dependencies based on the file type if needed.
3. **Execute Conversion**:
- Command line: `markitdown <file> -o <output.md>`
- Or Python API.
4. **Return Result**: Output the Markdown content or the saved file path.
## Notes
- Python 3.10+ is required.
- Using a virtual environment is recommended to avoid dependency conflicts.
- The OCR plugin requires an LLM API Key (e.g., OpenAI).
- Azure Document Intelligence requires an Azure account configuration.Apache ECharts charting skill.
---
name: apache-echarts
description: Apache ECharts charting skill.
metadata:
{
"openclaw":
{
"emoji": "📊",
"homepage": "https://echarts.apache.org/"
}
}
---
# ECharts Skill
Generate high-quality interactive visual HTML chart pages based on user-provided two-dimensional data or time series data. Automatically select the most appropriate chart type, supporting 20+ chart types including bar charts, line charts, pie charts, scatter plots, maps, etc. Supports one-click PNG image export.
## Trigger Scenarios
- Draw a chart
- Generate a chart
- Use ECharts
- Visualize data
- Plot the data
## Workflow
1. **Analyze Data**: Identify data type (categorical/time series/numeric/geographic)
2. **Select Chart**: Recommend the most suitable chart type based on data structure
3. **Generate HTML**: Generate a complete interactive HTML file based on ECharts 5.x CDN
## CDN Import
Always use ECharts 5.x CDN (no download required):
```html
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
```
## Standard HTML Template
The generated HTML contains a chart rendering area.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chart Title</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<style>
body { font-family: -apple-system, sans-serif; padding: 24px; background: #f0f2f5; }
.container { max-width: 1200px; margin: 0 auto; }
.chart-title { text-align: center; font-size: 22px; font-weight: 600; color: #1f2329; margin-bottom: 16px; }
#chart { width: 100%; height: 480px; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.toast {
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
padding: 10px 20px; background: rgba(30,35,41,0.9); color: #fff;
border-radius: 8px; font-size: 14px; pointer-events: none;
opacity: 0; transition: opacity 0.3s; z-index: 9999;
}
.toast.show { opacity: 1; }
</style>
</head>
<body>
<div class="container">
<div class="chart-title">Chart Title</div>
<div id="chart"></div>
</div>
<div class="toast" id="toast"></div>
<script>
var chart = echarts.init(document.getElementById('chart'));
var option = {
// ... user's chart configuration ...
// === Export tool (appended directly to option) ===
toolbox: {
right: 16,
top: 0,
feature: {
saveAsImage: {
type: 'png',
pixelRatio: 2, // 2=high definition, can be set to 3 for ultra HD
title: 'Export PNG Image',
name: 'chart' // Download file name
}
}
}
};
chart.setOption(option);
window.addEventListener('resize', function() { chart.resize(); });
// Listen for export completion event, show toast notification
chart.on('download', function() {
var t = document.getElementById('toast');
t.textContent = 'Image saved'; t.classList.add('show');
setTimeout(function() { t.classList.remove('show'); }, 2000);
});
</script>
</body>
</html>
```
## Chart Type Selection
| Data Scenario | Recommended Chart | series.type |
|---------|---------|------------|
| Compare categorical data | Bar chart | bar |
| Trends over time | Line chart | line |
| Part-to-whole proportion | Pie chart | pie |
| Relationship between two variables | Scatter plot | scatter |
| Multi-series trend comparison | Multi-line chart | line |
| Geographic distribution | Map | map |
| Distribution density | Heatmap | heatmap |
| Level/progress | Gauge | gauge |
| Relationships/flows | Sankey/Radar | sankey / radar |
| Mixed scenarios | Combo chart | multiple series |
## Core Configuration
```js
var option = {
title: { text: 'Title', subtext: 'Subtitle', left: 'center' },
tooltip: { trigger: 'axis' },
legend: { data: ['Series Name'], top: 30 },
grid: { left: '10%', right: '10%', bottom: '15%', containLabel: true },
xAxis: { type: 'category', data: ['x-axis data'] },
yAxis: { type: 'value' },
series: [{ name: 'Sales', type: 'bar', data: [5, 20, 36] }]
};
```
## Complete Examples for Common Charts
### Bar Chart
```js
xAxis: { type: 'category', data: ['Shirts','Sweaters','Chiffon','Pants','Heels','Socks'] },
yAxis: { type: 'value' },
series: [{ name: 'Sales', type: 'bar', data: [5, 20, 36, 10, 10, 20] }]
```
### Line Chart
```js
xAxis: { type: 'category', data: ['Jan','Feb','Mar','Apr','May'], boundaryGap: false },
series: [
{ name: 'Revenue', type: 'line', data: [12, 25, 18, 30, 42], smooth: true },
{ name: 'Expenses', type: 'line', data: [8, 15, 12, 20, 28], smooth: true }
]
```
### Pie Chart
```js
series: [{
type: 'pie', radius: '55%',
data: [
{ value: 335, name: 'Direct Visit' },
{ value: 310, name: 'Email Marketing' },
{ value: 234, name: 'Affiliate Ads' },
{ value: 135, name: 'Search Engine' }
],
label: { show: true, formatter: '{b}: {d}%' }
}]
```
### Scatter Plot
```js
xAxis: { type: 'value', name: 'Height (cm)' },
yAxis: { type: 'value', name: 'Weight (kg)' },
series: [{ type: 'scatter', symbolSize: 12, data: [[172,68],[168,62],[177,75],[159,55],[180,82]] }]
```
## Export Functionality (toolbox.saveAsImage)
ECharts has built-in export capability. Simply add the following configuration to your option to see the export icon in the top-right corner of the chart:
```js
toolbox: {
right: 16, // Distance from right edge
top: 0, // Distance from top edge
feature: {
saveAsImage: {
type: 'png', // or 'jpeg'
pixelRatio: 2, // Pixel density: 1=standard 2=high definition 3=ultra high
title: 'Export PNG Image',
name: 'chart' // Download file name (without extension)
}
}
}
```
**Show a notification after export:**
```js
chart.on('download', function() {
// Show Toast "Image saved"
});
```
**Console API:**
```js
window.__echarts_export__.getPngUrl(2); // Get PNG dataURL
window.__echarts_export__.resize(); // Trigger redraw
```
## Style Themes
```js
echarts.init(dom, 'dark'); // Dark theme
echarts.init(dom, 'light'); // Light theme (default)
```
Custom color palette: `color: ['#5470C6','#91CC75','#FAC858','#EE6666','#73C0DE','#3BA272','#FC8452','#9A60B4']`
## Output File
Generate a complete .html file, save it to the workspace, including:
- ECharts 5.x CDN import (no local files required)
- Built-in export icon in the top-right corner of the chart (toolbox.saveAsImage)
- Toast notification after export completion
- Responsive resizing (window.resize)
- `window.__echarts_export__` console API
For detailed API and examples, see [references/api.md](references/api.md)
FILE:references/api.md
# ECharts API Reference
## Global Configuration Options
| Option | Type | Default | Description |
|-------|------|-------|------|
| backgroundColor | string | 'transparent' | Canvas background color |
| animation | boolean | true | Enable animation |
| animationDuration | number | 1000 | Animation duration (ms) |
| animationEasing | string | 'cubicOut' | Easing function |
## title
```js
title: {
text: 'Main Title',
subtext: 'Subtitle',
left: 'center',
textStyle: { color: '#333', fontSize: 18, fontWeight: 'bold' }
}
```
## tooltip
```js
tooltip: {
trigger: 'axis',
axisPointer: { type: 'line' },
backgroundColor: 'rgba(50,50,50,0.9)',
textStyle: { color: '#fff' }
}
```
## legend
```js
legend: { data: ['Series A','Series B'], left: 'right', orient: 'vertical' }
```
## grid
```js
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }
```
## xAxis / yAxis
```js
xAxis: {
type: 'category',
data: ['Mon','Tue','Wed'],
name: 'X Axis Name',
axisLine: { lineStyle: { color: '#333' } },
splitLine: { show: false }
}
```
## dataZoom
```js
dataZoom: [
{ type: 'slider', start: 0, end: 100 },
{ type: 'inside', start: 0, end: 100 }
]
```
## visualMap
```js
visualMap: {
min: 0, max: 100,
calculable: true,
inRange: { color: ['#50a3ba','#eac736','#d94e5d'] },
right: 0, top: 'middle'
}
```
## series Types
### bar
```js
series: [{
type: 'bar',
data: [5, 20, 36],
barWidth: '50%',
itemStyle: {
color: new echarts.graphic.LinearGradient(0,0,0,1,[
{ offset: 0, color: '#83bff6' },
{ offset: 1, color: '#188df0' }
]),
borderRadius: [4,4,0,0]
}
}]
```
### line
```js
series: [{
type: 'line',
data: [5, 20, 36],
smooth: 0.3,
lineStyle: { width: 2 },
areaStyle: { color: 'rgba(84,112,198,0.2)' },
symbol: 'circle', symbolSize: 6
}]
```
### pie
```js
series: [{
type: 'pie',
radius: '55%',
center: ['50%','60%'],
data: [{ value: 335, name: 'Direct' }],
label: { show: true, formatter: '{b}: {d}%' }
}]
```
### scatter
```js
series: [{
type: 'scatter',
data: [[172,68],[168,62],[177,75]],
symbolSize: 12,
itemStyle: { color: 'rgba(84,112,198,0.5)' }
}]
```
### gauge
```js
series: [{
type: 'gauge',
startAngle: 180, endAngle: 0,
min: 0, max: 100, splitNumber: 8,
axisLine: { lineStyle: { width: 6, color: [[0.25,'#91CC75'],[0.5,'#FAC858'],[1,'#d94e5d']] } },
pointer: { width: 5, length: '70%' },
detail: { formatter: '{value}%', fontSize: 28, offsetCenter: [0,'70%'] },
data: [{ value: 67, name: 'Completion Rate' }]
}]
```
## echarts.init
```js
var chart = echarts.init(document.getElementById('main'));
var chart = echarts.init(dom, 'dark');
var chart = echarts.init(dom, null, { renderer: 'svg' });
```
## Common Methods
```js
chart.setOption(option);
chart.resize();
chart.getDataURL({ type: 'png', pixelRatio: 2 });
chart.clear();
chart.dispose();
echarts.connect('myGroup');
```
## Gradient Configuration
```js
new echarts.graphic.LinearGradient(0,0,0,1,[
{ offset: 0, color: '#83bff6' },
{ offset: 1, color: '#188df0' }
]);
```
## Official References
- Official Documentation: https://echarts.apache.org/handbook/en/get-started/
- Configuration Manual: https://echarts.apache.org/en/option.html
- Examples Gallery: https://echarts.apache.org/examples/en/index.html
FILE:assets/template.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; padding: 24px; background: #f0f2f5; }
.container { max-width: 1200px; margin: 0 auto; }
.chart-title { text-align: center; font-size: 22px; font-weight: 600; color: #1f2329; margin-bottom: 16px; }
#chart { width: 100%; height: {{HEIGHT}}; background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.toast {
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
padding: 10px 20px; background: rgba(30,35,41,0.9); color: #fff;
border-radius: 8px; font-size: 14px; pointer-events: none;
opacity: 0; transition: opacity 0.3s; z-index: 9999;
}
.toast.show { opacity: 1; }
</style>
</head>
<body>
<div class="container">
<div class="chart-title">{{TITLE}}</div>
<div id="chart"></div>
</div>
<div class="toast" id="toast"></div>
<script>
var chartDom = document.getElementById('chart');
var rendererType = (window.__ECHARTS_RENDERER__ || 'canvas');
var chart = echarts.init(chartDom, null, { renderer: rendererType });
// Merge toolbox.saveAsImage into user option (avoid overwriting user config)
var userOption = {{OPTION}};
var option = (function() {
// If user option already has toolbox, append saveAsImage instead of overwriting
if (userOption.toolbox) {
userOption.toolbox.feature = Object.assign(
{},
userOption.toolbox.feature,
{
saveAsImage: Object.assign(
{ type: 'png', pixelRatio: 2, name: document.title || 'chart' },
userOption.toolbox.feature ? userOption.toolbox.feature.saveAsImage : {}
)
}
);
return userOption;
}
// Default append toolbox.saveAsImage
return Object.assign({}, userOption, {
toolbox: {
right: 20,
top: 0,
feature: {
saveAsImage: {
type: 'png',
pixelRatio: 2,
name: document.title || 'chart',
title: 'Export PNG Image',
icon: 'path://M12 2H5a2 2 0 0 0-2 2v3h2V4h7v3h2V4a2 2 0 0 0-2-2zM5 20v-3h2v3H5zm12 0h-7v-3h7v3zm0-6h-2v-3h2v3zm0-6H5v-3h12v3z'
}
}
}
});
})();
chart.setOption(option);
window.addEventListener('resize', function() { chart.resize(); });
// Listen for saveAsImage completion event, show toast notification
chart.on('download', function() {
showToast('PNG image saved');
});
function showToast(msg) {
var t = document.getElementById('toast');
t.textContent = msg; t.classList.add('show');
setTimeout(function() { t.classList.remove('show'); }, 2000);
}
// window API for console invocation
window.__echarts_export__ = {
getPngUrl: function(pixelRatio) {
return chart.getDataURL({ type: 'png', pixelRatio: pixelRatio || 2, backgroundColor: '#fff' });
},
resize: function() { chart.resize(); }
};
</script>
</body>
</html>
```Chart.js charting skill. Used to generate visual charts such as line charts, bar charts, pie charts, radar charts, scatter plots, etc.
---
name: chartjs
description: Chart.js charting skill. Used to generate visual charts such as line charts, bar charts, pie charts, radar charts, scatter plots, etc.
---
# Chart.js
Chart.js is a popular open-source charting library supporting 8 chart types, rendered via Canvas with responsive design.
## Trigger Scenarios
- User requests to create/generate/draw a chart
- User mentions Chart.js or data visualization
- User requests to visualize data with a chart
- User uploads data and requests visualization
## Installation
**npm:**
```bash
npm install chart.js
```
**CDN (Script Tag):**
```html
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
```
**Webpack/Rollup (recommended for tree-shaking):**
```javascript
import Chart from 'chart.js/auto'; // Full features, no manual registration needed
```
## Chart Types and Required Components
Each chart type has minimal dependencies; importing on demand optimizes bundle size:
| Chart Type | Controller | Element | Default Scale |
|---------|-----------|---------|-----------|
| Bar | BarController | BarElement | CategoryScale(x) + LinearScale(y) |
| Line | LineController | LineElement + PointElement | CategoryScale(x) + LinearScale(y) |
| Pie | PieController | ArcElement | — |
| Doughnut | DoughnutController | ArcElement | — |
| PolarArea | PolarAreaController | ArcElement | RadialLinearScale |
| Radar | RadarController | LineElement + PointElement | RadialLinearScale |
| Scatter | ScatterController | PointElement | LinearScale(x/y) |
| Bubble | BubbleController | PointElement | LinearScale(x/y) |
## Basic Usage
**HTML:**
```html
<div style="max-width: 600px">
<canvas id="myChart"></canvas>
</div>
```
**JavaScript:**
```javascript
const ctx = document.getElementById('myChart');
new Chart(ctx, {
type: 'bar', // Chart type
data: {
labels: ['January', 'February', 'March'],
datasets: [{
label: 'Sales (10k)',
data: [12, 19, 3],
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
```
## Common Configurations
### Responsive (auto-adapts to container width)
```javascript
options: {
responsive: true,
maintainAspectRatio: false
}
```
### Fill Line Chart (Area)
```javascript
datasets: [{
fill: true, // or 'origin'/'start'/'end'
tension: 0.4 // Curve smoothness 0-1
}]
```
### Multiple Datasets
```javascript
datasets: [
{ label: '2023', data: [1, 2, 3], borderColor: 'red' },
{ label: '2024', data: [3, 2, 1], borderColor: 'blue' }
]
```
### Quick Color Settings
```javascript
backgroundColor: [
'rgba(255, 99, 132, 0.5)',
'rgba(54, 162, 235, 0.5)',
]
```
## Interaction Events
Click to get data point values (requires helpers import):
```javascript
import Chart from 'chart.js/auto';
import { getRelativePosition } from 'chart.js/helpers';
options: {
onClick: (e) => {
const pos = getRelativePosition(e, chart);
const x = chart.scales.x.getValueForPixel(pos.x);
const y = chart.scales.y.getValueForPixel(pos.y);
console.log(x, y);
}
}
```
## Time Scale
Requires a date adapter (e.g., chartjs-adapter-moment):
```javascript
import moment from 'moment';
import 'chartjs-adapter-moment';
// Then configure scales with type: 'time'
```
## Output Methods
After generation, there are two output paths:
1. **Render directly in an HTML page** — Generate a complete HTML file containing canvas + Chart.js CDN, open with a browser
2. **Screenshot/PDF** — Take a screenshot using the browser tool, or generate an image file using puppeteer/canvas
**Tip:** Generating HTML is the simplest and most reliable output method; let Chart.js handle responsive layout itself.
## More References
For detailed API and examples, see `references/api.md`.
FILE:references/api.md
# Chart.js API Reference
## Table of Contents
- [Data Structure](#data-structure)
- [Axes](#axes)
- [Colors & Styling](#colors--styling)
- [Animation](#animation)
- [Plugins](#plugins)
---
## Data Structure
### Basic Structure
```javascript
{
type: 'bar', // Chart type
data: {
labels: [], // X-axis labels
datasets: [{
label: '', // Dataset name
data: [], // Data array
// ...style properties
}]
},
options: {} // Configuration
}
```
### Data Formats
**Line/Bar Charts:**
```javascript
data: [12, 19, 3, 5, 2, 3] // Numeric array
```
**Scatter Chart (x, y):**
```javascript
data: [{ x: 10, y: 20 }, { x: 15, y: 10 }]
```
**Bubble Chart (x, y, r):**
```javascript
data: [{ x: 10, y: 20, r: 5 }]
```
---
## Axes
### Cartesian Scales (x/y)
**CategoryScale (default x-axis):**
```javascript
scales: {
x: { type: 'category', labels: ['January','February','March'] }
}
```
**LinearScale (default y-axis):**
```javascript
scales: {
y: {
type: 'linear',
beginAtZero: true,
min: 0,
max: 100,
ticks: { stepSize: 10 }
}
}
```
**LogarithmicScale:**
```javascript
scales: {
y: { type: 'logarithmic' }
}
```
**TimeScale:**
```javascript
scales: {
x: {
type: 'time',
time: { unit: 'day', displayFormat: 'MMM D' }
}
}
```
### Radial Scales (Radar/Polar Area)
**RadialLinearScale:**
```javascript
scales: {
r: {
angleLines: { display: true },
ticks: { display: false },
pointLabels: { font: { size: 14 } }
}
}
```
### Tick Configuration
```javascript
ticks: {
color: '#666',
font: { size: 12, family: 'Arial' },
callback: (value) => value + 'k', // Format display value
maxTicksLimit: 10
}
```
### Axis Titles
```javascript
scales: {
x: {
title: { display: true, text: 'Month', color: '#333' }
},
y: {
title: { display: true, text: 'Sales (10k)', color: '#333' }
}
}
```
---
## Colors & Styling
### Dataset Styles
```javascript
datasets: [{
// Fill color
backgroundColor: 'rgba(54, 162, 235, 0.5)',
// Border color
borderColor: 'rgb(54, 162, 235)',
// Border width
borderWidth: 2,
// Hover color
hoverBackgroundColor: 'rgba(54, 162, 235, 1)',
// Hover border color
hoverBorderColor: '#fff',
// Point radius (line chart)
pointRadius: 4,
// Point hover radius
pointHoverRadius: 6,
// Point style: 'circle','rect','rectRot','cross','crossRot','star','line','dash'
pointStyle: 'circle',
}]
```
### Gradients
```javascript
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(255, 99, 132, 0.5)');
gradient.addColorStop(1, 'rgba(255, 99, 132, 0)');
data: { datasets: [{ backgroundColor: gradient }] }
```
### Border Radius (Bar)
```javascript
datasets: [{
borderRadius: 5, // All corners
borderSkipped: false, // or 'left'/'right'/'top'/'bottom'
}]
```
### Grid Background
```javascript
options: {
scales: {
x: { grid: { display: false } },
y: { grid: { color: '#eee' } }
}
}
```
---
## Animation
### Global Animation Configuration
```javascript
options: {
animation: {
duration: 1000, // Animation duration ms
easing: 'easeOutQuart' // Easing function
}
}
```
### Easing Function Options
`'linear'` | `'easeInQuad'` | `'easeOutQuad'` | `'easeInOutQuad'` | `'easeInCubic'` | `'easeOutCubic'` | `'easeInOutCubic'` | `'easeInQuart'` | `'easeOutQuart'` | `'easeInOutQuart'` | `'easeInQuint'` | `'easeOutQuint'` | `'easeInOutQuint'` | `'easeInSine'` | `'easeOutSine'` | `'easeInOutSine'` | `'easeInExpo'` | `'easeOutExpo'` | `'easeInOutExpo'` | `'easeInCirc'` | `'easeOutCirc'` | `'easeInOutCirc'` | `'easeInElastic'` | `'easeOutElastic'` | `'easeInOutElastic'` | `'easeInBack'` | `'easeOutBack'` | `'easeInOutBack'` | `'easeInBounce'` | `'easeOutBounce'` | `'easeInOutBounce'`
### Disable Animation
```javascript
animation: false
// or
animation: { duration: 0 }
```
### Delayed Loading
```javascript
animation: {
delay: (context) => context.dataIndex * 100 // Delay each data point sequentially
}
```
---
## Plugins
### Built-in Plugins (Register as needed)
```javascript
import {
Chart,
BarController, BarElement,
LineController, LineElement, PointElement,
PieController, ArcElement,
CategoryScale, LinearScale,
Tooltip, Legend, Filler
} from 'chart.js';
Chart.register(
BarController, BarElement,
LineController, LineElement, PointElement,
PieController, ArcElement,
CategoryScale, LinearScale,
Tooltip, Legend, Filler
);
```
### Plugin List
| Plugin | Purpose |
|-----|------|
| Decimation | Data decimation, reduces points |
| Filler | Fill line chart area |
| Legend | Legend display |
| SubTitle | Subtitle |
| Title | Title |
| Tooltip | Hover tooltip |
### Title Configuration
```javascript
options: {
plugins: {
title: {
display: true,
text: 'Monthly Sales Report',
color: '#333',
font: { size: 18, weight: 'bold' },
padding: { top: 10, bottom: 30 }
}
}
}
```
### Legend Configuration
```javascript
options: {
plugins: {
legend: {
display: true,
position: 'top', // 'top'/'bottom'/'left'/'right'
labels: {
color: '#333',
font: { size: 14 },
usePointStyle: true // Use points instead of color blocks
}
}
}
}
```
### Tooltip Configuration
```javascript
options: {
plugins: {
tooltip: {
enabled: true,
mode: 'index', // 'point'/'nearest'/'dataset'/'index'
intersect: false,
callbacks: {
label: (context) => `context.dataset.label: context.raw`
}
}
}
}
```
---
## Complete Example
### Gradient Filled Line Chart
```javascript
const ctx = document.getElementById('myChart').getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(75, 192, 192, 0.4)');
gradient.addColorStop(1, 'rgba(75, 192, 192, 0)');
new Chart(ctx, {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May'],
datasets: [{
label: 'User Growth',
data: [30, 45, 62, 78, 95],
fill: true,
backgroundColor: gradient,
borderColor: 'rgb(75, 192, 192)',
tension: 0.4
}]
},
options: {
responsive: true,
plugins: {
legend: { display: true },
tooltip: { mode: 'index', intersect: false }
},
scales: {
y: { beginAtZero: false }
}
}
});
```Use Microsoft Edge online TTS service to convert text to speech. Supports command line and module invocation, no API key required.
---
name: microsoft-edge-tts
description: Use Microsoft Edge online TTS service to convert text to speech. Supports command line and module invocation, no API key required.
---
# Microsoft Edge TTS
Use Microsoft Edge's online TTS service to convert text to speech without requiring an API key. Use this skill when users need to convert text to speech, generate audio files, or read content aloud.
## Trigger Conditions
Trigger this skill when the user mentions any of the following keywords:
- TTS
- Speech synthesis
- Text-to-speech
- text-to-speech
- Read aloud
- edge-tts
## Quick Start
### Command Line Usage
```bash
# Basic usage
npx node-edge-tts -t 'Hello World'
# Specify output file
npx node-edge-tts -t 'Hello World' -f './output.mp3'
# Specify voice and language
npx node-edge-tts -t 'Hello world' -v 'en-US-AriaNeural' -l 'en-US'
# Adjust speaking rate and pitch
npx node-edge-tts -t 'Hello World' -r '+10%' --pitch '-5%'
# Generate subtitle file
npx node-edge-tts -t 'Hello World' -s
```
### Module Invocation
```javascript
const { EdgeTTS } = require('node-edge-tts')
// or
import { EdgeTTS } from 'node-edge-tts'
const tts = new EdgeTTS()
await tts.ttsPromise('Hello World', './output.mp3')
```
## Full Parameters
| Parameter | Short | Description | Default |
|------|------|------|--------|
| `--text` | `-t` | Text to convert (required) | - |
| `--filepath` | `-f` | Output file path | `./output.mp3` |
| `--voice` | `-v` | Voice name | `zh-CN-XiaoyiNeural` |
| `--lang` | `-l` | Language code | `zh-CN` |
| `--outputFormat` | `-o` | Output format | `audio-24khz-48kbitrate-mono-mp3` |
| `--rate` | `-r` | Speaking rate | `default` |
| `--pitch` | | Pitch | `default` |
| `--volume` | | Volume | `default` |
| `--saveSubtitles` | `-s` | Save subtitles | `false` |
| `--proxy` | `-p` | Proxy settings | - |
| `--timeout` | | Timeout (ms) | `10000` |
## Advanced Configuration
```javascript
const tts = new EdgeTTS({
voice: 'zh-CN-XiaoxiaoNeural',
lang: 'zh-CN',
outputFormat: 'audio-24khz-96kbitrate-mono-mp3',
saveSubtitles: true,
proxy: 'http://localhost:7890',
pitch: '-10%',
rate: '+10%',
volume: '-50%',
timeout: 10000
})
await tts.ttsPromise('Text to convert', './output.mp3')
```
## Available Voices
- **Chinese**: `zh-CN-XiaoyiNeural`, `zh-CN-XiaoxiaoNeural`, `zh-CN-YunjianNeural`, `zh-CN-YunxiNeural`, `zh-CN-YunxiaNeural`
- **English**: `en-US-AriaNeural`, `en-US-GuyNeural`, `en-US-JennyNeural`
- **Japanese**: `ja-JP-KeitaNeural`, `ja-JP-NanamiNeural`
- **More**: Refer to [Microsoft Voice Support Documentation](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)
## Subtitle Format
Enabling `-s` generates a `.json` subtitle file with the same name:
```json
[
{ "part": "Hello", "start": 100, "end": 500 },
{ "part": "World", "start": 500, "end": 900 }
]
```
Time units are in milliseconds, `part` is the text segment.
## Common Scenarios
### 1. Quick Speech Generation
```bash
npx node-edge-tts -t 'Welcome to speech synthesis'
```
### 2. Long Text Segmentation
For very long texts, it is recommended to process in segments and then merge.
### 3. Multilingual Mixed
```bash
# Chinese
npx node-edge-tts -t 'Hello World' -v 'zh-CN-XiaoxiaoNeural'
# English
npx node-edge-tts -t 'Hello World' -v 'en-US-AriaNeural'
```
## Important Notes
1. **No API Key Required**: Directly uses Microsoft Edge's free online service
2. **Network Dependent**: Requires internet connection
3. **Rate Limiting**: Frequent calls may be restricted; it is recommended to control call frequency appropriately
4. **Proxy Support**: If encountering network issues, set a proxy via the `-p` parameterCreate a new OpenClaw agent with a workspace directory and SOUL.md configuration. Use when you need to create a new agent, set up an agent workspace, configu...
--- name: agent-creation description: Create a new OpenClaw agent with a workspace directory and SOUL.md configuration. Use when you need to create a new agent, set up an agent workspace, configure SOUL.md, or initialize agent memory structure. --- # Agent Creation Skill This skill is used to create a new OpenClaw agent with the correct workspace structure. ## Trigger Conditions This skill is automatically activated when users mention keywords such as "create agent", "new agent", "agent add", "configure agent", "set up agent identity", etc. ## Creation Process ### Step 1: Generate Agent Information Generate the following information based on the user's input: | Item | Description | |--------|------| | **Agent Name** | Unique identifier, lowercase English, hyphen-separated | | **Identity Name** | Friendly name visible to users | | **SOUL.md** | Defines the agent's personality, communication style, and boundaries; affects interaction style | ### Step 2: Create Agent Using Commands ```bash openclaw agents add <agent-name> --workspace ~/.openclaw/workspace-<agent-name> openclaw agents set-identity --agent <agent-name> --name "<identity-name>" ``` Optional parameters: - `--model <model-id>`: Specify a default model for this agent ### Step 3: Replace SOUL.md File After successfully creating the agent via the command, replace the `SOUL.md` file content in the agent directory. `SOUL.md` Template: ```markdown # SOUL.md — <identity-name>(<agent-name>) ## Identity <agent identity description> ## Core Responsibilities - <responsibility 1> - <responsibility 2> - <responsibility 3> ## Capability Boundaries - <boundary 1> - <boundary 2> ## Workflow - <workflow step 1> - <workflow step 2> ## Response Style - <style element 1> - <style element 2> ## Self-Introduction When users ask questions like "Who are you?" or "What can you do?", respond in this style: "<self-introduction template>" ``` ### Step 4: Set Up Memory Structure Create a `memory/YYYY-MM-DD.md` file in the agent directory. ## Important Notes - **Agent Naming**: Use lowercase letters and hyphens; avoid spaces and special characters - **SOUL.md Required**: Every agent must have this file - **Directory Location**: Place uniformly under `~/.openclaw/workspace-<agent-name>` ## Example Create a customer service assistant agent that is professional, patient, and good at communication
Automatically accesses Xiaohongshu's Explore page via browser automation, inputs keywords into the search bar, and collects the list of related keywords from...
--- name: xiaohongshu-keyword-collector description: Automatically accesses Xiaohongshu's Explore page via browser automation, inputs keywords into the search bar, and collects the list of related keywords from the auto-suggest dropdown. --- # Xiaohongshu Keyword Collector ## Feature Overview This skill uses browser automation tools to access the Xiaohongshu Explore page, input keywords into the search bar, and collect the list of related keywords suggested by the search box's auto-complete feature. No API required; it's purely browser-based operation. ## Trigger Conditions Trigger this skill when the user mentions any of the following keywords: - 小红书关键词 - 收集小红书关键词 - 小红书搜索建议 - 小红书热搜词 - 小红书 SEO - 小红书话题 - Xiaohongshu keywords - Collect Xiaohongshu keywords - Xiaohongshu search suggestions - Xiaohongshu trending keywords - Xiaohongshu SEO - Xiaohongshu topics ## Use Cases - Users need to obtain Xiaohongshu search suggestion terms - Keyword research and trending topic discovery - SEO optimization and content topic selection - Keyword mining for competitor analysis ## Workflow ### 1. Open Xiaohongshu Explore Page Use the browser tool to navigate to the Xiaohongshu Explore page: ``` URL: https://www.xiaohongshu.com/explore ``` ### 2. Locate the Search Bar Find the search input field on the page, typically located at the top of the page. ### 3. Input Keywords Fill the user-provided keywords into the search bar. **Do not press Enter or click the search button.** ### 4. Collect Suggested Keywords Wait for the auto-suggest dropdown to appear, then collect all keyword suggestions displayed in the dropdown. ### 5. Output Results Organize the collected keyword list and present it to the user. ## Operation Examples ### Example 1: Collecting Suggestions for a Single Keyword User request: "Help me collect Xiaohongshu search suggestions for 'skincare'" Execution steps: 1. Open https://www.xiaohongshu.com/explore 2. Input "skincare" into the search box 3. Wait for the suggestion dropdown to appear 4. Collect all suggested keywords 5. Return the keyword list ### Example 2: Batch Collecting for Multiple Keywords User request: "Help me collect Xiaohongshu search suggestions for the three keywords 'weight loss', 'fitness', and 'yoga'" Execution steps: 1. Repeat the process for each keyword 2. Consolidate all collected results 3. Optional: Remove duplicates and organize by category ## Important Notes - **Do not click the search button**: Only input keywords and collect suggestions - **Allow time to load**: The suggestion dropdown may take 1-2 seconds to load; ensure sufficient wait time - **Login status**: Some content may require login to view complete suggestions - **Anti-crawling mechanisms**: If encountering captchas or restrictions, prompt the user to handle manually ## Output Format Output format for collecting suggestions for a single keyword: ``` Keyword: [Input Keyword] Search Suggestions: 1. Suggestion 1 2. Suggestion 2 3. Suggestion 3 ... ``` Output format for batch collecting multiple keywords: ``` Keyword: [Keyword 1 from batch] Search Suggestions: 1. Suggestion 1 2. Suggestion 2 3. Suggestion 3 ... Keyword: [Keyword 2 from batch] Search Suggestions: 1. Suggestion 1 2. Suggestion 2 3. Suggestion 3 ... ``` ## Tool Usage This skill relies on the `browser` tool for browser automation. Ensure the browser tool is available. ## No Resources Required This skill does not require additional scripts, reference materials, or resource files; it relies entirely on browser automation operations.
Quickly generate static websites using VitePress. Supports installing dependencies, initializing projects, local preview, building, and deployment.
---
name: vitepress-generator
description: Quickly generate static websites using VitePress. Supports installing dependencies, initializing projects, local preview, building, and deployment.
---
# VitePress Static Website Generator
## Feature Overview
Quickly generate static websites using VitePress. Supports installing dependencies, initializing projects, local preview, building, and deployment.
## Trigger Scenarios
- User mentions "static website", "documentation site", "generate website", "build documentation", "create blog", "VitePress", "vitepress", "vuepress", "documentation site", "technical documentation", "project documentation", "personal blog", etc.
## Quick Start
When users need to create a static website, follow the process below:
### 1. Check Environment
First, confirm that the user has Node.js installed:
```bash
node -v
npm -v
```
If not installed, prompt the user to install Node.js first (v18+ recommended).
### 2. Create Project Directory
```bash
mkdir <project-name>
cd <project-name>
npm init -y
```
### 3. Install VitePress
```bash
npm add -D vitepress
```
### 4. Initialize Project Structure
Create the basic directory structure:
```
<project-name>/
├── docs/
│ ├── .vitepress/
│ │ └── config.mts
│ ├── index.md
│ └── guide/
│ └── getting-started.md
├── package.json
└── README.md
```
### 5. Configure Scripts
Add the following to `package.json`:
```json
{
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
}
}
```
### 6. Local Preview
```bash
npm run docs:dev
```
Default access: http://localhost:5173
### 7. Build
```bash
npm run docs:build
```
Output directory: `docs/.vitepress/dist/`
## Complete Configuration Reference
For detailed configuration options, see [references/config-guide.md](references/config-guide.md)
## Theme Customization
For custom themes and styles, see [references/theme-customization.md](references/theme-customization.md)
## Deployment Guide
For deployment to different platforms, see [references/deployment.md](references/deployment.md)
## Quick Command Reference
| Command | Description |
|------|------|
| `npm run docs:dev` | Start local development server |
| `npm run docs:build` | Build production version |
| `npm run docs:preview` | Preview build results |
## Important Notes
1. **Node.js Version**: Requires v18 or higher
2. **Port Usage**: Development server uses port 5173 by default
3. **Build Output**: Build artifacts are located in `docs/.vitepress/dist/` directory
4. **Config Files**: Supports `.mts`, `.ts`, `.mjs`, `.js` formats
FILE:scripts/init-vitepress-site.sh
#!/bin/bash
# VitePress site initialization script
# Usage: ./init-vitepress-site.sh <project-name>
set -e
PROJECT_NAME=-my-vitepress-site
echo "🚀 Creating VitePress project: $PROJECT_NAME"
# Create project directory
mkdir -p "$PROJECT_NAME"
cd "$PROJECT_NAME"
# Initialize npm project
echo "📦 Initializing npm project..."
npm init -y
# Install VitePress
echo "⬇️ Installing VitePress..."
npm add -D vitepress
# Create directory structure
echo "📁 Creating directory structure..."
mkdir -p docs/.vitepress
mkdir -p docs/guide
# Create configuration file
cat > docs/.vitepress/config.mts << 'CONFIG'
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'My Site',
description: 'A static website built with VitePress',
themeConfig: {
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/getting-started' }
],
sidebar: {
'/guide/': [
{
text: 'Guide',
items: [
{ text: 'Quick Start', link: '/guide/getting-started' }
]
}
]
},
socialLinks: [
{ icon: 'github', link: 'https://github.com' }
]
}
})
CONFIG
# Create home page
cat > docs/index.md << 'INDEX'
---
layout: home
hero:
name: My Site
text: Built with VitePress
tagline: Fast, simple, and powerful static site generator
actions:
- theme: brand
text: Quick Start
link: /guide/getting-started
- theme: alt
text: View on GitHub
link: https://github.com
features:
- icon: ⚡️
title: 'Fast'
details: Blazing fast development experience powered by Vite
- icon: 📝
title: 'Simple'
details: Focus on content with Markdown
- icon: 🎨
title: 'Customizable'
details: Flexible theme and style customization
---
INDEX
# Create guide page
cat > docs/guide/getting-started.md << 'GUIDE'
# Quick Start
Welcome to VitePress!
## What is VitePress
VitePress is a static site generator built on top of Vite and Vue, designed specifically for technical documentation.
## Key Features
- ⚡️ **Blazing Fast**: Hot reload powered by Vite
- 📝 **Markdown First**: Focus on content creation
- 🎨 **Theme System**: Easily customizable appearance
- 📱 **Responsive**: Perfect mobile experience
## Next Steps
- Check out the [Configuration Guide](/config) for more settings
- Learn how to customize the appearance in [Theme Customization](/theme)
GUIDE
# Update package.json with scripts
echo "📝 Configuring scripts..."
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.scripts = pkg.scripts || {};
pkg.scripts['docs:dev'] = 'vitepress dev docs';
pkg.scripts['docs:build'] = 'vitepress build docs';
pkg.scripts['docs:preview'] = 'vitepress preview docs';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
"
# Create README
cat > README.md << 'README'
# My VitePress Site
A static website built with [VitePress](https://vitepress.dev).
## Quick Start
```bash
# Install dependencies
npm install
# Start local development
npm run docs:dev
# Build for production
npm run docs:build
# Preview the build
npm run docs:preview
```
## Directory Structure
```
.
├── docs/
│ ├── .vitepress/ # VitePress configuration
│ ├── index.md # Home page
│ └── guide/ # Documentation pages
├── package.json
└── README.md
```
## Deployment
Build artifacts are located in `docs/.vitepress/dist/` and can be deployed to any static hosting service.
See Deployment Guide for more details.
README
echo ""
echo "✅ Project created successfully!"
echo ""
echo "📂 Project location: $(pwd)"
echo ""
echo "🚀 Next steps:"
echo " cd $PROJECT_NAME"
echo " npm run docs:dev"
echo ""
echo "📖 Visit http://localhost:4173 to preview your site"
FILE:references/config-guide.md
# VitePress Configuration Guide
## Basic Configuration (config.mts)
```typescript
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'My Site',
description: 'Site description',
head: [
['link', { rel: 'icon', href: '/favicon.ico' }]
],
themeConfig: {
// Top navigation
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/getting-started' }
],
// Sidebar
sidebar: {
'/guide/': [
{
text: 'Guide',
items: [
{ text: 'Quick Start', link: '/guide/getting-started' }
]
}
]
},
// Social links
socialLinks: [
{ icon: 'github', link: 'https://github.com/your-repo' }
]
}
})
```
## Configuration Options
### Site Configuration
| Option | Description | Example |
|--------|------|------|
| `title` | Site title | 'My Docs' |
| `description` | Site description | 'Technical documentation site' |
| `head` | HTML head tags | Add favicon, meta, etc. |
### Theme Configuration
| Option | Description |
|--------|------|
| `nav` | Top navigation menu |
| `sidebar` | Sidebar navigation |
| `socialLinks` | Social link icons |
| `footer` | Footer configuration |
## Multilingual Configuration
```typescript
export default defineConfig({
locales: {
root: {
label: '简体中文',
lang: 'zh-CN',
title: '我的文档'
},
en: {
label: 'English',
lang: 'en',
title: 'My Docs',
link: '/en/'
}
}
})
```
## Custom Head Tags
```typescript
head: [
['meta', { name: 'keywords', content: 'keywords' }],
['meta', { property: 'og:type', content: 'website' }],
['link', { rel: 'stylesheet', href: '/custom.css' }]
]
```
FILE:references/deployment.md
# VitePress Deployment Guide
## Build Output
After building, the output directory is: `docs/.vitepress/dist/`
This is a pure static website that can be deployed to any static hosting service.
## GitHub Pages
### Using GitHub Actions
Create `.github/workflows/deploy.yml`:
```yaml
name: Deploy VitePress
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci
- run: npm run docs:build
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: { secrets.GITHUB_TOKEN}
publish_dir: docs/.vitepress/dist
```
### Manual Deployment
```bash
npm run docs:build
cd docs/.vitepress/dist
git init
git add -A
git commit -m 'deploy'
git push -f [email protected]:username/repo.git main:gh-pages
```
## Vercel
1. Connect your GitHub repository
2. Build settings:
- Build Command: `npm run docs:build`
- Output Directory: `docs/.vitepress/dist`
3. Automatic deployment
## Netlify
1. Connect your repository
2. Build settings:
- Build command: `npm run docs:build`
- Publish directory: `docs/.vitepress/dist`
3. Automatic deployment
## Docker Deployment
```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run docs:build
FROM nginx:alpine
COPY --from=0 /app/docs/.vitepress/dist /usr/share/nginx/html
EXPOSE 80
```
Build and run:
```bash
docker build -t my-vitepress-site .
docker run -p 80:80 my-vitepress-site
```
## Custom Domain
Add a custom domain in your deployment platform, then add a CNAME record with your domain provider.
## Important Notes
1. Ensure the build command is correct
2. Check the output directory path
3. Configure the correct Node.js version
4. Enable HTTPS (most platforms enable it by default)
FILE:references/theme-customization.md
# VitePress Theme Customization
## Custom Styles
### Method 1: Inline Styles
In `.vitepress/theme/index.ts`:
```typescript
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default {
...DefaultTheme,
enhanceApp({ app }) {
// Custom logic
}
}
```
### Method 2: CSS Variable Overrides
Create `.vitepress/theme/custom.css`:
```css
:root {
--vp-c-brand: #007acc;
--vp-c-brand-light: #0094e6;
--vp-font-family-base: 'Inter', sans-serif;
}
.dark {
--vp-c-brand: #0094e6;
}
```
## Custom Layout
### Adding Custom Components
```vue
<!-- .vitepress/components/MyComponent.vue -->
<template>
<div class="my-component">
<slot />
</div>
</template>
```
Register in `index.ts`:
```typescript
import MyComponent from '../components/MyComponent.vue'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.component('MyComponent', MyComponent)
}
}
```
## Common CSS Variables
```css
/* Colors */
--vp-c-brand /* Primary color */
--vp-c-text-1 /* Main text color */
--vp-c-bg /* Background color */
/* Fonts */
--vp-font-family-base /* Base font */
--vp-font-family-mono /* Code font */
/* Dimensions */
--vp-nav-height /* Navbar height */
--vp-sidebar-width /* Sidebar width */
```
## Dark Mode Customization
```css
.dark {
--vp-c-brand: #your-dark-theme-color;
--vp-c-bg: #1a1a1a;
}
```Accessing the Douyin homepage through browser automation, entering keywords in the search bar and collecting relevant keyword suggestions in the automated pr...
---
name: douyin-keyword-collector
description: Accessing the Douyin homepage through browser automation, entering keywords in the search bar and collecting relevant keyword suggestions in the automated prompt box.
---
# Douyin keyword collection tool
## Feature Overview
This skill automatically accesses the Douyin homepage through the browser, enters keywords in the search bar and collects relevant keyword suggestions in the automatic prompt box. No API key required, completely browser-based automation.
## Triggers
This skill is triggered when the user mentions any of the following keywords:
- 抖音关键词
- 收集抖音关键词
- 抖音搜索建议
- 抖音热门词
- 抖音 SEO
- 抖音话题
- Douyin keywords
- Collect Douyin keywords
- Douyin search suggestions
- Douyin hot words
- Douyin SEO
- Douyin topics
## Usage Scenarios
- Douyin SEO Keyword Research
- Content creation inspiration collection
- Trending topic trend analysis
- Competitive keyword research
- Short video topic selection planning
## Operation process
### 1. Launch the browser
Use the `browser` tool's `start` or `snapshot` action to launch the browser.
### 2. Visit the Douyin homepage
Navigate to the official website of Douyin:
```
https://www.douyin.com
```
### 3. Check and close the login pop-up
Use the `snapshot` action of the `browser` tool to get a page element reference and check for a login pop-up.
If there is a login pop-up (look for a close button, usually an `img` or `button` element), use the `act` action to click close:
```
browser action=act request={"kind":"click","ref"<关闭按钮引用>:""}
```
### 4. Locate the search bar
Use the `snapshot` action of the `browser` tool to get a page element reference and find the search bar input box (textbox type, description contains 'search').
### 5. Enter a keyword
Using the `act` action of the `browser` tool, select the `type` type and enter your target keyword in the search bar:
```
browser action=act request={"kind":"type","ref":"<搜索栏引用>","text":"<关键词>"}
```
### 6. Wait for the prompt box to appear
Wait 1-2 seconds for the auto prompt box to load:
```
browser action=act request={"kind":"wait","timeMs":2000}
```
### 7. Collect automated prompts
Use the `snapshot` action to get a list of keywords in the prompt box, looking for the keyword text contained in the `list` or `generic` element.
### 8. Organize the output
Organize the collected keywords into a list format and output them to users.
## Example of Browser Automation Commands
### Launch your browser and access Douyin
```
browser action=start profile=openclaw
browser action=navigate targetUrl=https://www.douyin.com
```
### Get a snapshot of the page (get an element reference)
```
browser action=snapshot refs=aria
```
### Close the login pop-up (if present)
Look for the close button in the pop-up window (usually the `img` or `button` element, near the top-right corner of the pop-up), and click:
```
browser action=act request={"kind":"click","ref"<关闭按钮引用>:""}
```
### Enter keywords in the search bar
```
browser action=act request={"kind":"type","ref":"<搜索栏引用>","text":"<关键词>"}
```
### Wait for the prompt box to load
```
browser action=act request={"kind":"wait","timeMs":2000}
```
### Get the content of the prompt box
```
browser action=snapshot refs=aria
```
## Considerations
1. **Login pop-up processing**: After accessing the Douyin homepage, a login box may pop up, and you need to click the close button (usually the X icon in the upper right corner of the pop-up window) before proceeding.
2. **Login Status**: Some search functions may require login. If you still cannot get the prompt after closing the pop-up window, it is recommended that you manually scan the QR code to log in.
3. **Anti-crawler mechanism**: Douyin may have an anti-crawler mechanism, and you need to add appropriate delays when operating to avoid triggering risk control.
4. **Element References**: Use `refs=aria` to obtain stable element references to ensure operational accuracy.
5. **Waiting Time**: After entering the keyword, wait 1-2 seconds for the automatic prompt box to load.
6. **Mobile adaptation**: Douyin may have different interfaces between mobile and desktop, and it is recommended to use the desktop mode.
## Output Format
```
Keywords: [Entered keywords]
Search suggestions:
1. Suggestion 1
2. Suggestion 2
3. Suggestion 3
...
```Automatically accesses the Jinri Toutiao homepage via browser automation, inputs keywords into the search bar, and collects related keyword suggestions from...
--- name: jinritoutiao-keyword-collector description: Automatically accesses the Jinri Toutiao homepage via browser automation, inputs keywords into the search bar, and collects related keyword suggestions from the auto-suggest dropdown. --- # Jinri Toutiao Keyword Collector ## Feature Overview This skill uses browser automation to access Jinri Toutiao (www.toutiao.com), simulates user behavior of entering keywords in the search box, and automatically collects the relevant keyword suggestions displayed in the search dropdown. ## Trigger Conditions Trigger this skill when the user mentions any of the following keywords: - 今日头条关键词 - 收集头条关键词 - 头条搜索建议 - 头条热门词 - 头条 SEO - 头条话题 - Jinri Toutiao keywords - Collect Toutiao keywords - Toutiao search suggestions - Toutiao trending keywords - Toutiao SEO - Toutiao topics ## Use Cases - SEO keyword research and optimization - Content creation inspiration gathering - Trending topic discovery - Competitor keyword analysis - Market research and trend analysis ## Operation Workflow ### 1. Launch Browser Use the `browser` tool to launch the browser: ``` action: start profile: openclaw ``` ### 2. Access Jinri Toutiao Homepage Navigate to Jinri Toutiao: ``` action: navigate targetUrl: https://www.toutiao.com ``` Wait for the page to fully load. ### 3. Get Page Snapshot Use `snapshot` to get the page element structure and locate the search box: ``` action: snapshot refs: aria ``` Search for the search box element in the snapshot results (typically an input element containing keywords like "search"). ### 4. Input Keywords Use the `act` tool to input keywords into the search box: ``` action: act ref: <ref value of the search box> kind: type text: <user-provided keyword> slowly: true ``` Set `slowly: true` to ensure the page can properly trigger the auto-suggest functionality. ### 5. Wait for Suggestion Dropdown After input is complete, wait 1-2 seconds for the auto-suggest dropdown to load: ``` action: act kind: wait timeMs: 2000 ``` ### 6. Get Dropdown Snapshot Take another page snapshot, this time capturing the keyword list in the auto-suggest dropdown: ``` action: snapshot refs: aria ``` ### 7. Extract Keywords Extract all keyword text from the snapshot results within the suggestion dropdown. The dropdown typically contains multiple `option`, `li`, or `div` elements, each containing a suggested keyword. ### 8. Output Format ``` Keyword: [Input Keyword] Search Suggestions: 1. Suggestion 1 2. Suggestion 2 3. Suggestion 3 ... ``` ### 9. Cleanup (Optional) If the user has no further requests, close the browser: ``` action: close ``` ## Important Notes 1. **Network Latency**: Jinri Toutiao page loading may take time; ensure sufficient waiting time before operations 2. **Element Locating**: Using `refs: aria` provides more stable element references 3. **Input Speed**: Setting `slowly: true` ensures the page can properly trigger auto-suggest 4. **Anti-scraping Mechanisms**: Avoid frequent requests in a short period; it is recommended to wait 5-10 seconds between multiple collections 5. **Session Persistence**: For multiple collections, keep the browser session open to improve efficiency ## Batch Collection for Multiple Keywords To collect suggestions for multiple keywords: 1. Keep the browser session open 2. Repeat steps 4-7 for each keyword 3. Use `act` with `kind: type` to clear the search box before entering a new keyword 4. Compile all results into a summary report ## Troubleshooting ### Search Box Not Found - Check if the page has fully loaded - Try refreshing the page and retrying - Use a more detailed snapshot (add the `depth` parameter) ### Suggestion Dropdown Does Not Appear - Ensure input speed is slow enough (`slowly: true`) - Increase wait time (`timeMs: 3000` or longer) - Check if the network connection is normal ### Keyword List is Empty - Verify the input keyword is valid - Try testing with common keywords - Check if Jinri Toutiao has updated its page structure ## Reference Resources - Browser Automation Best Practices: See `references/browser-automation-best-practices.md` - Jinri Toutiao Page Structure Description: See `references/toutiao-structure.md` FILE:references/browser-automation-best-practices.md # Browser Automation Best Practices ## Waiting Strategies ### Fixed Wait Suitable for operations with known delays: ``` action: act kind: wait timeMs: 2000 ``` ### Conditional Wait Wait for a specific element to appear or disappear: ``` action: act kind: wait textGone: Loading... ``` ## Element Location ### Using ARIA References ``` action: snapshot refs: aria ``` Advantages: - More stable element identification - Not affected by page structure changes - Supports accessibility for elements ### Using Role References (Default) ``` action: snapshot refs: role ``` Suitable for standard HTML elements. ## Input Optimization ### Slow Typing Triggers autocomplete and dynamic loading: ``` action: act kind: type text: keyword slowly: true ``` ### Clear Input Field Clear before re-entering: ``` action: act ref: <input-ref> kind: fill fields: [] ``` ## Performance Optimization ### Maintain Session Reuse the browser session for multiple operations: 1. Launch the browser for the first time 2. Use the same `targetId` for subsequent operations 3. Close all at the end ### Delay Requests Avoid triggering anti-scraping mechanisms: - Interval for single operations: 2-3 seconds - Interval for batch operations: 5-10 seconds - Avoid high-frequency access during peak hours ## Error Handling ### Timeout Settings Increase timeout for long operations: ``` action: navigate targetUrl: https://www.toutiao.com timeoutMs: 30000 ``` ### Retry Strategy Retry 2-3 times after failure: 1. Wait for 3 seconds 2. Refresh the page 3. Re-execute the operation ## Debugging Tips ### Screenshot Assistance Take a screenshot when encountering problems: ``` action: screenshot fullPage: true ``` ### Console Logs Check for page errors: ``` action: console ``` FILE:references/toutiao-structure.md # Today's Headlines Page Structure Description ## Homepage Elements ### Search Box - **Location**: Top navigation bar of the page - **Features**: - input element - placeholder contains the word "search" - usually accompanied by a search icon - **ARIA Label**: may include keywords like "search" or "搜索" ### Search Suggestion Box - **Trigger Condition**: After entering text in the search box - **Location**: Directly below the search box - **Element Type**: - div container - contains multiple li or div items - each item includes a suggested keyword - **Delay**: Appears about 200-500ms after input ## Common Element Selectors ### Search Box Identification Check in snapshot for: - role: "searchbox" - role: "textbox" - name contains "搜索" - placeholder contains "搜索" ### Suggestion Item Identification Check in snapshot for: - list items located below the search box - role: "option" or role: "listitem" - clickable elements containing text content ## Page Loading Characteristics ### First Screen Load - Navigation bar: 1-2 seconds - Recommended content: 2-4 seconds - Fully loaded: 5-8 seconds ### Dynamic Loading - Search suggestions: 200-500ms after input - Search results: 1-3 seconds after submission - Infinite scroll: 1-2 seconds after scrolling ## Anti-Scraping Mechanism ### Detection Features - High-frequency requests - Abnormal input speed - No mouse movement traces ### Avoidance Suggestions - Input using `slowly: true` - 2-5 seconds intervals between operations - Avoid a large number of requests in a short time - Use a normal browser configuration profile ## Update Log ### Common Structure in 2024 ``` Search box: input[aria-label*="搜索"] Suggestion box: div.suggestion-list Suggestion item: div.suggestion-item ``` **Note**: Page structure may update at any time; rely on real-time snapshots for actual operations.
Automatically publishes graphic content on Toutiao through browser automation, supporting intelligent formatting, automatic generation of popular tags, and t...
--- name: toutiao-graphic-publisher description: Automatically publishes graphic content on Toutiao through browser automation, supporting intelligent formatting, automatic generation of popular tags, and tag activation. --- # Toutiao Automatic Article Publishing ## Feature Overview Automatically publishes graphic content on Toutiao through browser automation, supporting intelligent formatting, automatic generation of popular tags, and tag activation. No API keys required; uses browser automation to complete the entire process of login, content filling, tag generation, and publishing. Only QR code login requires manual operation; all other steps are fully automated. ## Trigger Scenarios - 用户说"发布到今日头条"、"发到头条"、"自动发布头条文章" - 用户有文章标题和内容需要发布到今日头条 - 用户需要批量发布内容到头条号 - User says "publish to Toutiao", "post to Toutiao", "automatically publish Toutiao article" - User has article title and content to publish on Toutiao - User needs to batch publish content to Toutiao account ## Workflow ### 1. Login Detection - Visit https://mp.toutiao.com/profile_v4/index - Check login status - If not logged in, prompt user to scan QR code to log in (requires manual operation) - Wait for login to complete ### 2. Enter Publishing Page - Directly visit https://mp.toutiao.com/profile_v4/graphic/publish - Wait for the editor to fully load ### 3. Content Intelligent Processing #### 3.1 Title Recognition and Processing - Analyze the body content to identify potential section headings - Heading characteristics: - Starts with numbers (e.g., "1.", "一、", "(1)") - Starts with "Chapter X/Section X" - Short sentence at the beginning of a paragraph (within 10 characters) - Contains keywords (e.g., "Introduction", "Conclusion", "Summary", "Foreword") #### 3.2 Automatically Apply Subheading Styles Once headings are identified, automatically apply Toutiao editor's subheading styles: - Select the heading text - Click the editor's "H" button or select the "Subheading" style - Ensure headings are prominently displayed #### 3.3 Body Text Formatting Optimization - **Paragraph Spacing**: Add blank lines between paragraphs to improve readability - **Key Point Emphasis**: Use **bold** to highlight key sentences - **List Optimization**: Convert enumerated content into ordered or unordered lists - **Paragraph Splitting**: Appropriately split long paragraphs, ideally 3-5 sentences per paragraph ### 4. Automatically Generate Popular Tags #### 4.1 Tag Analysis Dimensions Automatically generate 3-5 popular tags based on article content: | Analysis Dimension | Description | Example | |---------|------|------| | Core Theme | Main technology/field discussed in the article | OpenClaw, AI Agent | | Industry Hotspot | Current trending topics | Artificial Intelligence, Large Language Models | | Niche Area | Vertical application scenarios | Enterprise Intelligence, Personal Efficiency | | Trend Prediction | Future-oriented discussions | Development Trends, Future Outlook | | Practical Value | Value readers can gain | Tutorials, Guides, Analysis | #### 4.2 Tag Generation Rules ``` Tag Source Priority: 1. Core words from the article title 2. Keywords from each section heading 3. Frequently occurring technical terms 4. Popular terms in related fields 5. Target audience tags ``` #### 4.3 Tag Selection Strategy - **Mandatory Tags**: Core theme words of the article (1-2) - **Recommended Tags**: Industry hotspot words (1-2) - **Auxiliary Tags**: Niche area/practical value words (1) **Number of Tags**: 3-5, no more than 5 ### 5. Activate Tags #### 5.1 Tag Input Method - Locate the "Tags" input field on the article publishing page - Enter the generated popular tags one by one - Press Enter after each tag to confirm - Wait for the system to automatically match/add #### 5.2 Tag Activation Checklist Checklist for tag activation: - ✅ Whether the number of tags is within the 3-5 range - ✅ Whether tags are relevant to the article content - ✅ Whether popular tags have search volume - ✅ Avoid duplicate or similar tags #### 5.3 Tag Optimization Suggestions - Prioritize tags with search volume - Use long-tail tags as supplements - Avoid tags that are too broad or too specialized - Reference popular topics at the end of articles ### 6. Content Filling - **Title**: Fill in the user-provided title in the title input field (2-30 characters) - **Body Text**: Fill in the content after intelligent formatting processing - **Tags**: Fill in and activate the automatically generated popular tags - **Display Cover**: Select no cover ### 7. Execute Publishing - Click the "Preview and Publish" button - When the preview pop-up appears, click the "Confirm Publish" button - Click the "Confirm Publish" button ## Intelligent Tag System ### Tag Combination Strategy | Article Type | Tag Combination Example | |---------|------------| | Technical Tutorial | Core Tool + Operation Method + Practical Value | | Trend Analysis | Industry Hotspot + Core Theme + Future Trend | | Product Review | Product Name + Core Features + Application Scenarios | | Experience Sharing | Core Experience + Target Audience + Outcome Value | ## Intelligent Formatting Rules ### Heading Recognition Rules ``` Primary Heading Characteristics: - Format: 一、二、三... or 1. 2. 3... or Chapter 1/Section 1 - Position: Beginning of paragraph - Length: Typically 2-10 characters Secondary Heading Characteristics: - Format: (一)(二) or 1.1 1.2 or ① ② - Position: Beginning of paragraph - Length: Typically 2-15 characters Keyword Headings: - Introduction/Foreword/Preface - Conclusion/Summary/Closing Remarks - Background/Overview/Brief Introduction - Methods/Analysis/Discussion ``` ### Formatting Beautification Rules 1. **Heading Hierarchy**: Use "Subheading" style for primary headings, use **bold** for secondary headings 2. **Paragraph Optimization**: Keep each paragraph to 100-200 characters, split if too long 3. **Key Point Emphasis**: Use **bold** for core viewpoints, data, and conclusions 4. **List Conversion**: Convert 3 or more parallel items into list format 5. **Blank Line Handling**: Maintain appropriate blank lines before and after headings, and between paragraphs ## Usage Instructions Users need to provide: - **Title**: Article title (2-30 characters) (required) - **Body Text**: Article content (required) ## Important Notes 1. **Login Status**: QR code login is required for first-time use or when cookies expire 2. **Content Compliance**: Adhere to Toutiao community guidelines; avoid violating content 3. **Tag Selection**: Choose tags highly relevant to the article; avoid stacking irrelevant tags 4. **Frequency Limits**: Avoid publishing multiple articles in a short period; it is recommended to wait at least 5 minutes between publications 5. **Formatting Check**: It is recommended to preview and check the formatting effect and tag display after publishing ## Error Handling - Login Failure: Prompt user to rescan the QR code - Publishing Failure: Check network connection, retry, or provide specific error information - Content Violation: Prompt user to modify content and retry - Formatting Anomaly: Check if the editor loaded correctly; refresh the page and retry if necessary - Tags Cannot Be Activated: Manually check if the tag input field was filled in correctly
小红书搜索建议关键词收集工具。通过浏览器自动化访问小红书探索页,在搜索栏输入关键词并收集自动提示框中的相关关键词列表。使用场景:(1) 用户需要获取小红书搜索联想词 (2) 关键词调研和热门话题发现 (3) SEO优化和内容选题 (4) 竞品分析中的关键词挖掘。触发词:"小红书关键词"、"搜索建议"、"联想词"、...
--- name: xhs-suggest-keywords description: 小红书搜索建议关键词收集工具。通过浏览器自动化访问小红书探索页,在搜索栏输入关键词并收集自动提示框中的相关关键词列表。使用场景:(1) 用户需要获取小红书搜索联想词 (2) 关键词调研和热门话题发现 (3) SEO优化和内容选题 (4) 竞品分析中的关键词挖掘。触发词:"小红书关键词"、"搜索建议"、"联想词"、"小红书热搜词"、"关键词收集"。 --- # 小红书搜索建议关键词收集 ## 概述 本技能通过浏览器自动化工具,访问小红书探索页面,在搜索栏中输入关键词,收集搜索框自动提示的相关关键词列表。无需API,纯浏览器操作实现。 ## 工作流程 ### 1. 打开小红书探索页 使用 browser 工具导航到小红书探索页: ``` URL: https://www.xiaohongshu.com/explore ``` ### 2. 定位搜索栏 在页面上找到搜索输入框,通常位于页面顶部。 ### 3. 输入关键词 在搜索栏中填充用户提供的关键词,**不要按回车或点击搜索按钮**。 ### 4. 收集建议关键词 等待自动提示框出现后,收集提示框中显示的所有关键词建议。 ### 5. 输出结果 将收集到的关键词列表整理输出给用户。 ## 操作示例 ### 示例1:收集单个关键词的建议 用户请求:"帮我收集小红书上'护肤'的搜索建议词" 执行步骤: 1. 打开 https://www.xiaohongshu.com/explore 2. 在搜索框输入"护肤" 3. 等待提示框出现 4. 收集所有建议关键词 5. 返回关键词列表 ### 示例2:批量收集多个关键词 用户请求:"帮我收集'减肥'、'健身'、'瑜伽'这三个词的小红书搜索建议" 执行步骤: 1. 对每个关键词重复上述流程 2. 汇总所有收集结果 3. 可选:去重、分类整理 ## 注意事项 - **不要点击搜索按钮**:只需输入关键词,收集提示词即可 - **等待加载**:提示框可能需要1-2秒加载,确保等待足够时间 - **登录状态**:部分内容可能需要登录才能查看完整建议 - **反爬机制**:如遇到验证码或限制,需提示用户手动处理 ## 输出格式 收集单个关键词的建议格式输出结果: ``` 关键词:[输入的关键词] 搜索建议词: 1. 建议词1 2. 建议词2 3. 建议词3 ... ``` 批量收集多个关键词输出结果: ``` 关键词:[输入批量关键词中的关键词1] 搜索建议词: 1. 建议词1 2. 建议词2 3. 建议词3 ... 关键词:[输入批量关键词中的关键词1] 搜索建议词: 1. 建议词1 2. 建议词2 3. 建议词3 ... ``` ## 使用工具 本技能依赖 `browser` 工具进行浏览器自动化操作。确保浏览器工具可用。 ## 无需资源 本技能不需要额外的脚本、参考资料或资源文件,完全依赖浏览器自动化操作。
小红书自动长文发布工具。用户已有长文内容需要发布到小红书时,自动完成登录检测、长文内容分段优化、AI 生成配图、内容填充、AI 生成标签、标签激活、原创声明、执行发布的全流程。仅扫码登录需人工操作,其余步骤全自动化。使用场景:用户已有笔记长文内容需要发布到小红书;触发词包括"小红书长文发布"、"发布小红书长文"、...
---
name: xiaohongshu-longpost-auto
description: When users have long-form content ready to publish on Xiaohongshu, automatically completes the entire process: login detection, long content segmentation optimization, AI-generated images, content filling, AI-generated tags, tag activation, original content declaration, and publishing.
---
# Xiaohongshu Automatic Long-Form Post Publishing
## Feature Overview
When users have long-form content ready to publish on Xiaohongshu, automatically completes the entire process: login detection, long content segmentation optimization, AI-generated images, content filling, AI-generated tags, tag activation, original content declaration, and publishing. Only QR code login requires manual operation; all other steps are fully automated.
## Trigger Conditions
Trigger this skill when the user mentions any of the following keywords:
- Xiaohongshu long-form post publishing
- Publish Xiaohongshu long-form post
- Automatically publish Xiaohongshu long-form post
- Xiaohongshu long-form notes
- Xiaohongshu article publishing
- 小红书长文发布
- 发布小红书长文
- 自动发小红书长文
- 小红书长文笔记
- 小红书文章发布
## Use Cases
- Users have existing long-form note content ready to publish on Xiaohongshu
## 🔄 Workflow
```
1. Content Preprocessing → 2. Login Detection → 3. Enter Publishing Page → 4. Fill Content →
5. One-Click Formatting → 6. Select Template → 7. Generate Description → 8. Add Tags →
9. Declare Original → 10. Publish
```
## Step-by-Step Guide
### 1️⃣ Content Preprocessing
**Segmentation Principles:**
- 300-500 characters per paragraph to maintain reading rhythm
- Add subheadings for easy browsing
- Front-load key information; present core points at the beginning of each paragraph
- Appropriate spacing with blank lines between paragraphs
- Moderate use of emojis ✨💡
**Content Structure:**
```
Opening Hook (50-100 chars) → Spark curiosity or resonate
Body Paragraphs (300-500 chars each) → Problem/Background → Analysis/Methods → Cases/Experience → Summary/Suggestions
Closing Interaction (50 chars) → Encourage comments or saves
```
### 2️⃣ Login Detection
**Visit:** `https://creator.xiaohongshu.com/`
| Status | Action |
|------|------|
| Logged in | Directly enter publishing page |
| Not logged in | Prompt user to scan QR code, wait for completion |
**Technical Implementation:**
```javascript
// Detect login status
browser.navigate('https://creator.xiaohongshu.com/')
// If redirected to /login page, not logged in
```
### 3️⃣ Enter Publishing Page
**Visit:** `https://creator.xiaohongshu.com/publish/publish`
**Operation Steps:**
1. Navigate to the publishing page
2. Click the **"Write Long-Form Post"** button
3. Click **"New Creation"** to enter the editor
**Technical Implementation:**
```javascript
browser.navigate('https://creator.xiaohongshu.com/publish/publish')
browser.snapshot() // Get page elements
browser.act({ kind: 'click', ref: 'e111' }) // Click "Write Long-Form Post"
browser.act({ kind: 'click', ref: 'e148' }) // Click "New Creation"
```
### 4️⃣ Fill Content
| Field | Requirements |
|------|------|
| Title | ≤20 characters, containing 1-2 keywords |
| Body Text | Paste preprocessed content |
**Technical Implementation:**
```javascript
// Fill title
browser.act({ kind: 'type', ref: 'e253', text: 'Title content' })
// Fill body text (inject using evaluate)
browser.act({
kind: 'evaluate',
fn: "() => { const editor = document.querySelector('[contenteditable]'); editor.textContent = 'Body content'; editor.dispatchEvent(new InputEvent('input', {bubbles: true})); return 'done'; }"
})
```
### 5️⃣ One-Click Formatting
Click the **"One-Click Formatting"** button; the system automatically optimizes the format.
**Technical Implementation:**
```javascript
browser.act({ kind: 'click', ref: 'e260' }) // Click "One-Click Formatting"
```
### 6️⃣ Select Template
| Template Type | Applicable Scenarios |
|----------|----------|
| Fresh Minimalist | Lifestyle sharing, reading notes |
| Workplace Expertise | Experience summaries, skill sharing |
| Vibrant Fashion | Beauty/fashion, trending topics |
| Warm Healing | Emotional stories, inspirational content |
| Professional Rigorous | Educational content, tutorials, guides |
| Logical Structure | Tech news, industry analysis |
| Simple Basic | General content |
> **Principle:** Choose based on content theme and target audience
> **Recommendation:** For tech/workplace content, select "Logical Structure" or "Workplace Expertise"
**Technical Implementation:**
```javascript
browser.act({ kind: 'click', ref: 'e334' }) // Click "Logical Structure" template
browser.act({ kind: 'click', ref: 'e647' }) // Click "Next"
```
### 7️⃣ Generate Body Description
**Optimization Principles:**
| Element | Requirements |
|------|------|
| Length | 50-100 characters |
| Content | Summarize core points or highlights |
| Tone | Conversational, friendly |
| Hook | Create suspense or highlight pain points at the beginning |
| Keywords | Include 1-2 search keywords |
**Example:**
- ❌ "This article introduces several methods for time management"
- ✅ "Same 24 hours, why can others get 3 times the work done? These 5 time management techniques doubled my productivity, number 3 is truly amazing!"
**Technical Implementation:**
```javascript
browser.act({ kind: 'type', ref: 'e706', text: 'Description content' })
```
### 8️⃣ Add Tags
**Tag Structure (5-8 total):**
| Type | Quantity | Example |
|------|------|------|
| Core Tags | 1-2 | #WorkplaceExpertise #LearningMethods |
| Niche Tags | 2-3 | #TimeManagement #Productivity |
| Popular Tags | 1-2 | #OfficeWorkers #Students |
| Long-Tail Tags | 1-2 | #PomodoroTechnique #MorningJournal |
**Checklist:**
- ✅ 5-8 tags total
- ✅ Highly relevant to content
- ✅ Balanced popularity (high traffic + precise)
**Technical Implementation:**
```javascript
browser.act({ kind: 'click', ref: 'e723' }) // Click "Topic" button
browser.act({ kind: 'click', ref: 'e1033' }) // Click recommended tag "#ArtificialIntelligence"
browser.act({ kind: 'click', ref: 'e712' }) // Click recommended tag "#LargeLanguageModels"
```
### 9️⃣ Declare Original
**Operation Steps:**
1. Check the **"Original Content Declaration"** checkbox
2. In the pop-up, check **"I have read and agree"**
3. Click the **"Declare Original"** button
**Technical Implementation:**
```javascript
browser.act({ kind: 'click', ref: 'e806' }) // Check original declaration
browser.act({ kind: 'click', ref: 'e1083' }) // Check agreement box
browser.act({ kind: 'click', ref: 'e1088' }) // Click "Declare Original"
```
### 🔟 Publish
**Pre-Publishing Checklist:**
- [ ] Title complete and engaging (≤20 characters)
- [ ] Body text formatting looks good
- [ ] Body description engaging (50-100 characters)
- [ ] Tags activated (5-8 tags)
- [ ] Original declaration checked
**Technical Implementation:**
```javascript
browser.act({ kind: 'click', ref: 'e1013' }) // Click "Publish"
```
**Publication Success Indicators:**
- Page displays green checkmark ✅
- Displays "Published Successfully" text
- Automatically returns to homepage after 3 seconds
## ⚠️ Important Notes
| Item | Description |
|------|------|
| Content Compliance | Must comply with Xiaohongshu community guidelines; avoid sensitive words |
| Image Copyright | AI-generated images should avoid copyright risks |
| Publishing Frequency | Avoid publishing too frequently in a short period (recommended interval > 1 hour) |
| Engagement Maintenance | Monitor comments after publishing and respond promptly |
| Title Length | Strictly control within 20 characters; otherwise cannot publish |
| Tag Count | Minimum 3, maximum 8, recommended 5-6 |
---
## 🛠️ Error Handling
| Error Scenario | Handling Method |
|----------|----------|
| Login expired | Prompt user to scan QR code again; wait for completion and continue |
| Element not found | Re-snapshot to get latest ref, retry up to 3 times |
| Content injection failed | Check contenteditable element, activate using focus()+click() |
| Image upload failed | Retry up to 3 times; if still failing, skip that image |
| Content moderation prompt | Prompt user to modify sensitive content |
| Publishing frequency limit | Prompt user to wait before retrying (typically 1-24 hours) |
| Title too long | Automatically truncate or have AI regenerate a shorter title |
**Debugging Tips:**
```javascript
// 1. Screenshot to confirm current page status
browser.screenshot({ fullPage: true })
// 2. Get latest element references
browser.snapshot({ refs: 'aria' })
// 3. Check if editor is editable
browser.act({ fn: "document.querySelector('[contenteditable]').isContentEditable" })
```
---
## 🔧 Technical Details
### Browser Automation Essentials
**1. Element Locating:**
- Use `refs: 'aria'` to obtain stable aria-ref locators
- Avoid using unstable XPath or CSS selectors
**2. Content Injection:**
```javascript
// Recommended method: Use evaluate + dispatchEvent
browser.act({
kind: 'evaluate',
fn: "() => {
const editor = document.querySelector('[contenteditable]');
editor.textContent = 'Content';
editor.dispatchEvent(new InputEvent('input', { bubbles: true }));
return 'done';
}"
})
```
**3. Waiting Strategy:**
- Wait 500-1000ms after clicks to allow page to respond
- Use snapshot to confirm element state before proceeding
## 🔗 Reference Documentation
- [Xiaohongshu Creator Platform](https://creator.xiaohongshu.com/)
- [Xiaohongshu Community Guidelines](https://www.xiaohongshu.com/community_guidelines)
- [Xiaohongshu Long-Form Post Guide](https://creator.xiaohongshu.com/help)