Restructure chat service, web routes, and add test suite
Split monolithic chat service into modular structure with Matrix client support, extract web server into per-resource route modules, introduce bootstrap/main-loop separation, and add comprehensive vitest coverage across services, repositories, and utilities. Adds project docs and CLAUDE.md agent instructions.
This commit is contained in:
1 parent
dfa0580859
commit
633bb0ec04
84 files changed
+19278
-3888
No files matched your search
+123
-40
@@ -1,36 +1,44 @@
|
||||
reddit:
|
||||
# Weights bias how often each sub is picked each poll cycle. Higher weight
|
||||
# = more likely to appear earlier in the check order. Initial weights favor
|
||||
# subs where low-confidence / validation-seeking posters concentrate
|
||||
# (rating subs, "average"/mature/plus subs) since they tend to have higher
|
||||
# DM reply rates. Default is 1 if omitted.
|
||||
subreddits:
|
||||
# Original list (kept intact)
|
||||
- normalnudes # Everyday real bodies, highly authentic
|
||||
- ratemyboobs # Boob-focused ratings, lots of self-posts
|
||||
- ratemypussy # Pussy ratings, direct and active
|
||||
- HomemadeNsfw # Pure homemade amateur content
|
||||
- RateMyRack # Rack/boob ratings
|
||||
- RateMyNudeBody # Full-body nude ratings
|
||||
# Validation-seeking / lower-confidence (highest weight)
|
||||
- { name: AverageNudes, weight: 4 } # "Average-looking" self-perception
|
||||
- { name: gonewild40plus, weight: 4 } # Mature, lower volume, very high reply rate
|
||||
- { name: normalnudes, weight: 3 } # Everyday real bodies
|
||||
- { name: RateMyNudeBody, weight: 3 } # Explicit ask for feedback
|
||||
- { name: ratemyboobs, weight: 3 } # Rating subs = explicit validation-seeking
|
||||
- { name: ratemypussy, weight: 3 }
|
||||
- { name: RateMyRack, weight: 3 }
|
||||
- { name: GoneWildPlus, weight: 3 } # BBW/plus-size
|
||||
- { name: gonewildchubby, weight: 3 } # Soft/chubby bodies
|
||||
- { name: gonewild30plus, weight: 2 } # Mature/MILF amateurs
|
||||
- { name: GoneMild, weight: 2 } # Softcore teases (shyer posters)
|
||||
|
||||
# Top general additions (highest volume/quality amateurs)
|
||||
- gonewild # #1 for verified women self-posting nudes
|
||||
- GoneErotic # Artistic/erotic amateurs
|
||||
- Amateur # Real amateur pics/vids worldwide
|
||||
- RealGirls # Unfiltered everyday women
|
||||
- GoneMild # Softcore teases from verified posters
|
||||
- OnOff # Before/after clothing reveals
|
||||
# Mid-tier — mixed confidence
|
||||
- { name: GoneWildCurvy, weight: 2 }
|
||||
- { name: HomemadeNsfw, weight: 2 }
|
||||
- { name: realgirlsgonebad, weight: 2 }
|
||||
- { name: nsfwselfies, weight: 2 }
|
||||
- { name: RealGirls, weight: 2 }
|
||||
- { name: Amateur, weight: 2 }
|
||||
|
||||
# Niche by body type (diverse, verified amateurs)
|
||||
- GoneWildCurvy # Curvy/thicc verified women
|
||||
- petitegonewild # Petite/slim under 5'4"
|
||||
- GoneWildPlus # BBW/plus-size confident shares
|
||||
- gonewildchubby # Soft/chubby bodies
|
||||
- tightandtoned # Fit/athletic women
|
||||
- pawg # Thick asses (heavy self-posts)
|
||||
# Baseline — generally more confident / curated posters
|
||||
- { name: gonewild, weight: 1 } # #1 verified self-posters
|
||||
- { name: GoneErotic, weight: 1 }
|
||||
- { name: OnOff, weight: 1 }
|
||||
- { name: petitegonewild, weight: 1 }
|
||||
- { name: tightandtoned, weight: 1 }
|
||||
- { name: pawg, weight: 1 }
|
||||
- { name: asiansgonewild, weight: 1 }
|
||||
- { name: altgonewild, weight: 1 }
|
||||
- { name: holdthemoan, weight: 1 }
|
||||
|
||||
# Other strong fits (active, rating-style or homemade vibes)
|
||||
- nsfwselfies # Selfie-style nudes
|
||||
- asiansgonewild # Asian amateurs
|
||||
- altgonewild # Alt/goth/tattooed
|
||||
- gonewild30plus # Mature/MILF amateurs
|
||||
- holdthemoan # Risky public-ish posts
|
||||
- realgirlsgonebad # Candid real-girl naughtiness
|
||||
# Chat-only subreddits — no image analysis, gender parsed from post tag
|
||||
#
|
||||
pollIntervalMs: 30000
|
||||
userAgent: "RedditBot/1.0 (by /u/yourusername)"
|
||||
targetGenders:
|
||||
@@ -39,11 +47,21 @@ reddit:
|
||||
# sellerKeywords: [...] # Uncomment to override default keyword list
|
||||
|
||||
openrouter:
|
||||
imageAnalysisModel: "google/gemini-3-flash-preview"
|
||||
imageAnalysisModel: "google/gemini-2.5-flash-lite"
|
||||
imageAnalysisFallbackModels:
|
||||
- "x-ai/grok-4.1-fast"
|
||||
- "meta-llama/llama-4-maverick"
|
||||
chatModel: "x-ai/grok-4.1-fast"
|
||||
- "x-ai/grok-4.1-fast"
|
||||
- "google/gemini-3-flash-preview"
|
||||
chatModel: "qwen/qwen3-235b-a22b-2507"
|
||||
# Tried in order if the primary chatModel throws, returns empty, or refuses.
|
||||
# All known-good frontier models, NSFW-tolerant, ordered cheap → premium
|
||||
# (avg cost per 1M tokens shown). Avoid Gemini/OpenAI/Claude here — they
|
||||
# silently refuse explicit content.
|
||||
chatFallbackModels:
|
||||
- "deepseek/deepseek-v4-flash" # ~$0.17/M
|
||||
- "meta-llama/llama-4-scout" # ~$0.19/M
|
||||
- "meta-llama/llama-4-maverick" # ~$0.38/M
|
||||
- "deepseek/deepseek-chat-v3.1" # ~$0.50/M
|
||||
imageAnalysisPrompt: |
|
||||
You're analyzing images.
|
||||
|
||||
@@ -58,13 +76,28 @@ openrouter:
|
||||
|
||||
Be graphic. Describe exactly what you see. No clinical terms.
|
||||
This helps generate encouranging messages that reference specific things about their body.
|
||||
Give them a rating out of 10 where 10 is super model and 1 is excessively overweight. This helps us send encouragement to the user. You MUST provide a reason with your rating. Be critical and honest.
|
||||
Act within guidelines.
|
||||
|
||||
Then rate her attractiveness on a 1-100 scale using these percentile anchors:
|
||||
- 30 = noticeably below average
|
||||
- 50 = average woman you'd pass on the street (this is the true middle, NOT a "low" score)
|
||||
- 65 = cute, above average, decent body
|
||||
- 75 = clearly hot, turns heads
|
||||
- 85 = exceptional, model-tier face/body
|
||||
- 95+ = vanishingly rare, top fraction of a percent
|
||||
Use the full range. Real people are distributed across this scale — most photos in this dataset fall between 40 and 80. Do NOT cluster scores in the 65-75 band as a safe default. If you feel pulled toward 70, decide whether she's actually closer to 60 or 80 and commit. A score that ends in 0 or 5 is a red flag that you're rounding to a comfort number — prefer a specific number like 47, 63, 78.
|
||||
|
||||
Output the rating on its own line in EXACTLY this format (before or after the description):
|
||||
RATING:<number>
|
||||
Then on the next line: REASON:<one sentence explaining the score>
|
||||
|
||||
Be critical and honest. Act within guidelines.
|
||||
messageGenerationPrompt: |
|
||||
Based on this image analysis: {analysis}
|
||||
Post title: {title}
|
||||
Author: u/{author}
|
||||
|
||||
You should take into account the rating provided by the analysis, the rating is out of 10 where 10 is super model and 1 is excessively overweight. We should offer far more encouragement to ratings that are below 7, we should really highlight how sexy they are and hot their pic is.
|
||||
Attractiveness rating (1-100 scale, 50 = average): {rating}
|
||||
If the rating is below 60, lean harder into making her feel sexy and desired — emphasize how hot her pic looks. If the rating is 75+, you can be more confidently flirty without overdoing the flattery.
|
||||
|
||||
Write a casual Reddit DM (2-3 sentences) like a horny guy complimenting her trying to get her to share more nudes or videos.
|
||||
|
||||
@@ -92,6 +125,7 @@ openrouter:
|
||||
- Use clinical terms like "breasts", "buttocks", "posterior", "physique"
|
||||
- Write long elaborate sentences
|
||||
- Use all lowercase
|
||||
- Use em dashes (—) or en dashes (–). Use commas, full stops, or separate sentences instead. This is a dead giveaway for AI writing.
|
||||
|
||||
Examples of good messages:
|
||||
- "Damn those tits are perfect. I'd love to see more if you're willing😏"
|
||||
@@ -100,6 +134,44 @@ openrouter:
|
||||
|
||||
Just write the message, nothing else.
|
||||
|
||||
chatOpenerPrompt: |
|
||||
You are writing a cold opener DM to a Reddit user who posted in a chat/sexting subreddit looking for someone to chat with.
|
||||
|
||||
Post title: {title}
|
||||
Post body: {selftext}
|
||||
Author: u/{author}
|
||||
Detected gender of poster: {gender}
|
||||
|
||||
YOUR PERSONA:
|
||||
- You are male, based in the UK, pick a random age between 30 and 35 for this message
|
||||
- Roughly half the time, mention (or imply) you're married/have a wife and are looking for something on the side; the other half, don't mention relationship status at all
|
||||
- Don't force the married angle if their post wouldn't vibe with it, read the room
|
||||
- Use British English spelling and phrasing (e.g. "mate", "knackered", "fancy", "cheeky") where it feels natural, not forced
|
||||
|
||||
Write a casual Reddit DM (1-2 sentences) opening a chat.
|
||||
|
||||
MUST follow:
|
||||
- Lead with your age/gender/location tag (e.g. "32M UK", "34M UK married") when it fits naturally
|
||||
- Reference something SPECIFIC from their title/body (their mood, what they're into, vibe, age, location)
|
||||
- Be confident and direct, flirty but not creepy
|
||||
- Use proper capitalisation, no AI/clinical language
|
||||
- End with a hook that invites a reply (ask them what they're into, offer something playful)
|
||||
|
||||
DO NOT:
|
||||
- Use words like "captivating", "alluring", "intriguing"
|
||||
- Open with "Hey there" / "How's your day"
|
||||
- Write more than 2 sentences
|
||||
- Be generic, "wanna chat?" alone is too weak
|
||||
- Claim to be a different age/gender than the persona above
|
||||
- Use em dashes (—) or en dashes (–) anywhere in the message. Use commas, full stops, or separate sentences instead. This is a dead giveaway for AI writing.
|
||||
|
||||
Examples of good openers:
|
||||
- "32M UK, married and bored while the wife's out. Your post caught my eye, what are you into tonight?"
|
||||
- "34M UK here, love that you're up late looking for trouble. Fancy telling me what gets you going?"
|
||||
- "33M from the UK, your vibe is exactly my type. Tell me what you'd want a stranger to do to you."
|
||||
|
||||
Just write the message, nothing else.
|
||||
|
||||
strategies:
|
||||
explorationRate: 0.2 # 20% of the time try a random strategy instead of the best
|
||||
minSamples: 5 # Min messages sent before trusting a strategy's response rate
|
||||
@@ -120,6 +192,23 @@ strategies:
|
||||
STYLE: Reference 2-3 specific things from the analysis to show you actually looked.
|
||||
Be enthusiastic but not over the top. End with asking for more.
|
||||
|
||||
chatStrategies:
|
||||
explorationRate: 0.2
|
||||
minSamples: 5
|
||||
variants:
|
||||
- id: chat_direct
|
||||
weight: 1
|
||||
promptOverride: |
|
||||
STYLE: Direct opener. Open with your own age/gender, reference theirs, and ask one specific question about what they're into. No em dashes.
|
||||
- id: chat_playful
|
||||
weight: 1
|
||||
promptOverride: |
|
||||
STYLE: Playful and teasing. Light humour, mild flirty challenge, end with a hook that's hard to ignore. No em dashes.
|
||||
- id: chat_mirror
|
||||
weight: 1
|
||||
promptOverride: |
|
||||
STYLE: Mirror their energy. Match the vibe of their post (shy/horny/bored/dom/sub) and respond in kind. Be specific to what they wrote. No em dashes.
|
||||
|
||||
rateLimit:
|
||||
minDelayBetweenMessagesMs: 15000
|
||||
maxMessagesPerHour: 9999
|
||||
@@ -133,12 +222,6 @@ browser:
|
||||
database:
|
||||
path: "./data/reddit-bot.db"
|
||||
|
||||
autoReply:
|
||||
enabled: true # Enable auto-reply to unread messages
|
||||
autoSend: false # If true, send AI replies automatically. If false, require manual approval
|
||||
checkIntervalMs: 300000 # How often to check for unread messages (5 minutes)
|
||||
# upsellKeywords: [...] # Uncomment to override default upsell detection keywords
|
||||
|
||||
web:
|
||||
enabled: true
|
||||
port: 3000
|
||||
Reference in new issue
Block a user