better prompting

This commit is contained in:
localhost 2026-03-03 17:11:29 +01:00
parent 2a492b8442
commit 9f760718f0
3 changed files with 48 additions and 44 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -134,11 +134,11 @@ app.ws('/save', {
return sendError(ws, 'Unable to retrieve video info from YouTube. Please try again later.')
}
const slopScore = await parseSlop(videoId, data.videoDetails.title,
const isSlop = await parseSlop(videoId, data.videoDetails.title,
(data.microformat.playerMicroformatRenderer.description?.simpleText || '').replaceAll('\n', '<br>'),
data.videoDetails.channelId)
if (slopScore >= 4) {
if (isSlop) {
sendError(ws, 'Filters can always be wrong. Is the rating wrong? Email me at admin@preservetube.com', false);
return sendError(ws, 'Your download has been rejected by our slop filter.');
}
@ -216,10 +216,10 @@ app.ws('/savechannel', {
break;
}
const slopScore = await parseSlop(video.video_id, video.title.text,
const isSlop = await parseSlop(video.video_id, video.title.text,
video.description_snippet?.text || '', channelId)
if (slopScore >= 4) {
if (isSlop) {
sendError(ws, 'Filters can always be wrong. Is the rating wrong? Email me at admin@preservetube.com', false);
sendError(ws, 'Your download has been rejected by our slop filter.');
continue;

View File

@ -14,7 +14,8 @@ const channelBlacklist = [
'UCUQmW2YLzhEmMTqO0RAPlOw',
'UC4Anp9y2TU-d5blFUf7wCqw',
'UC-TaLb_bURExFdLFXkJ3Adg',
'UC1XgosSxwK9xtrMLsRzCbHw'
'UC1XgosSxwK9xtrMLsRzCbHw',
'UCInXezQxpWgrd7uPKeA6gPQ',
]
async function analyseSlop(id: string, title: string, description: string) {
@ -25,52 +26,55 @@ async function analyseSlop(id: string, title: string, description: string) {
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gemini-2.5-flash-lite',
model: 'deepseek/deepseek-v3.2',
messages: [
{ role: 'user', content: `Role: You are "The Slop Detector." Analyze video titles and rate them 0-5 on the "Slop Score." Slop is derivative content using popular movie/TV footage + trendy audio + basic editing.
{ role: 'user', content: `You are "The Slop Detector." Analyze video titles and determine if the content is SLOP or NOT SLOP.
### SLOP SCORE (0-5)
- **0:** Original, complex, artistic. No slop signals.
- **1:** Fan edit with unique perspective, non-obvious choices.
- **2:** Well-made but predictable, adds nothing new.
- **3:** Some slop signals present, minimal effort visible.
- **4:** Textbook slop popular character + overused/slowed song + 4K tag + "Edit."
- **5:** Maximum slop density every possible signal stacked.
### SLOP SIGNALS
Use these as intuition guides, not a checklist. Weight them by how many stack together.
- **Emoji in title** strong signal, especially 😂🤣😎😍🥺. Multiple emoji = very strong.
- **Title is entirely hashtags** near-instant slop.
- **Unicode styled text** (𝐋𝐢𝐤𝐞 𝐓𝐡𝐢𝐬) common in character edits.
- **Pipe separators** (|) splitting title into the classic pattern of caption | source | song only a signal when used to stack multiple slop elements (e.g. character | show | slowed song). A single pipe for emphasis or listing does not count.
- **4K / [4K] tag** almost always slop when paired with anything else.
- **"Edit" / "OneShot" / "Morphosis"** suffix or delimiter usage ( Edit , Edit).
- **Slowed / Reverb / Slowed+Reverb / MONTAGEM** only counts when stacked with others
- **Known slop franchises:** This list is definitive, not illustrative. Only the following qualify: Johnny English, Mr. Bean, Breaking Bad, Peaky Blinders, American Psycho, Patrick Bateman, The Boys, Homelander, Dexter, Joe Goldberg, Squid Game, Rick Grimes, Thomas Shelby, John Wick, Kingsman. They must be explicitly named, no interpretation from your side.
- **Song name explicitly in title** especially if slowed/remixed.
- **Description** if it contains hashtag spam, or music credits it reinforces slop signals from the title.
- **Clickbait** is its own category and does not affect the slop score.
### DECISION RULES
**Score SLOP if the video matches either of these categories:**
**1. Slop Edit** a formulaic fan/character edit. Look for a combination of these signals:
- **Emoji in title** strong signal, especially 😂🤣😎😍🥺. Multiple emoji = very strong. (optional)
- **Title is entirely hashtags, or mostly hastags** near-instant slop
- **Hashtag spam** title consists of a short hook followed by 3+ hashtags, or the description is dominated by hashtags. Strong signal on its own.
- **Unicode styled text** (𝐋𝐢𝐤𝐞 𝐓𝐡𝐢𝐬) common in character edits (optional)
- **Pipe separators** (|) are only a signal when the segments themselves are slop elements (character name | franchise | song title). Pipes used for general formatting, listing topics, or separating unrelated phrases do not count under any circumstances.
- **4K / [4K] tag** strong signal when paired with anything else (optional)
- **"Edit" / "OneShot" / "Morphosis"** as suffix or with delimiters ( Edit , Edit)
- **Slowed / Reverb / Slowed+Reverb / MONTAGEM** only counts when stacked with other signals
- **Known slop franchises** this list is exhaustive, not illustrative. Only these qualify: Johnny English, Mr. Bean, Breaking Bad, Peaky Blinders, American Psycho, Patrick Bateman, The Boys, Homelander, Dexter, Joe Goldberg, Squid Game, Rick Grimes, Thomas Shelby, John Wick, Kingsman. Must be explicitly named.
- **Song name explicitly in title** especially if slowed or remixed
- **Description** hashtag spam or music credits reinforce title signals
- **Title mirrors description exactly** reinforces slop when combined with other signals (optional)
**2. Raw clip** an unedited or minimally edited fragment of a TV show or movie with no transformative content.
**3. AI-generated compilation** footage generated by AI tools. Score SLOP if:
- Title or description explicitly mentions "Sora"
### EXCEPTIONS
- Tutorials, news, commentary, politics score 0 automatically
- Lost/archived content score 0 automatically
- Fan animations/original franchise-inspired art do not trigger slop
- Direct movie/TV clips or scenes uploaded without transformative editing score 4 automatically
Always score NOT SLOP:
- News, commentary, politics
- Lost or archived content
### NOTES
- Emoji alone does not make something slop
- A character reference alone does not make something slop
- Pipes and emoji together are not sufficient for a SLOP ruling without additional corroborating signals
- ASMR, art, cooking, and similar creator content is NOT slop even if it uses emoji or pipes
- Do not infer or assume anything about creators, channels, or franchises not explicitly listed in the known slop franchises. If it's not on the list, it's not a signal.
- A channel with social links, Discord, Patreon, and editor credits in the description is a legitimate creator, not a slop channel
### OUTPUT
Valid JSON only. No other text. One sentence reasoning max, be brief. Use your judgment if multiple signals stack logically toward slop, score accordingly. Do not assume content type beyond what title explicitly states.
Valid JSON only. No other text. One sentence reasoning max, be brief.
{"score": 0, "reasoning": "..."}
{"is_slop": true/false, "reasoning": "..."}
User Title: ${title}
User Description: ${description.slice(0,100)}` }
User Description: ${description.slice(0,500)}` }
]
})
})).json()
let parsedResponse: {score: number, reasoning: string}
= { score: 0, reasoning: 'failed to parse' }
let parsedResponse: {is_slop: boolean, reasoning: string}
= { is_slop: false, reasoning: 'failed to parse' }
try {
parsedResponse = JSON.parse(llmResponse.choices[0].message.content.replace(/```json|```/g, '').trim())
@ -82,16 +86,16 @@ User Description: ${description.slice(0,100)}` }
return parsedResponse
}
async function parseSlop(id: string, title: string, description: string, channelId: string): Promise<number> {
if (channelBlacklist.includes(channelId)) return 5;
async function parseSlop(id: string, title: string, description: string, channelId: string): Promise<boolean> {
if (channelBlacklist.includes(channelId)) return true;
const cachedSlop = await redis.get(`slop:${id}`)
if (cachedSlop) return parseInt(cachedSlop)
if (cachedSlop) return Boolean(cachedSlop)
const { score, reasoning } = await analyseSlop(id , title, description)
if (reasoning != 'failed to parse') await redis.set(`slop:${id}`, score, 'EX', 60 * 60 * 24 * 7)
const { is_slop, reasoning } = await analyseSlop(id , title, description)
if (reasoning != 'failed to parse') await redis.set(`slop:${id}`, is_slop.toString(), 'EX', 60 * 60 * 24 * 7)
return score
return is_slop
}
export { parseSlop }