better prompting
This commit is contained in:
parent
2a492b8442
commit
9f760718f0
|
|
@ -134,11 +134,11 @@ app.ws('/save', {
|
||||||
return sendError(ws, 'Unable to retrieve video info from YouTube. Please try again later.')
|
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.microformat.playerMicroformatRenderer.description?.simpleText || '').replaceAll('\n', '<br>'),
|
||||||
data.videoDetails.channelId)
|
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);
|
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.');
|
return sendError(ws, 'Your download has been rejected by our slop filter.');
|
||||||
}
|
}
|
||||||
|
|
@ -216,10 +216,10 @@ app.ws('/savechannel', {
|
||||||
break;
|
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)
|
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, '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.');
|
sendError(ws, 'Your download has been rejected by our slop filter.');
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ const channelBlacklist = [
|
||||||
'UCUQmW2YLzhEmMTqO0RAPlOw',
|
'UCUQmW2YLzhEmMTqO0RAPlOw',
|
||||||
'UC4Anp9y2TU-d5blFUf7wCqw',
|
'UC4Anp9y2TU-d5blFUf7wCqw',
|
||||||
'UC-TaLb_bURExFdLFXkJ3Adg',
|
'UC-TaLb_bURExFdLFXkJ3Adg',
|
||||||
'UC1XgosSxwK9xtrMLsRzCbHw'
|
'UC1XgosSxwK9xtrMLsRzCbHw',
|
||||||
|
'UCInXezQxpWgrd7uPKeA6gPQ',
|
||||||
]
|
]
|
||||||
|
|
||||||
async function analyseSlop(id: string, title: string, description: string) {
|
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'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: 'gemini-2.5-flash-lite',
|
model: 'deepseek/deepseek-v3.2',
|
||||||
messages: [
|
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)
|
### DECISION RULES
|
||||||
- **0:** Original, complex, artistic. No slop signals.
|
**Score SLOP if the video matches either of these categories:**
|
||||||
- **1:** Fan edit with unique perspective, non-obvious choices.
|
**1. Slop Edit** — a formulaic fan/character edit. Look for a combination of these signals:
|
||||||
- **2:** Well-made but predictable, adds nothing new.
|
- **Emoji in title** — strong signal, especially 😂🤣😎😍🥺. Multiple emoji = very strong. (optional)
|
||||||
- **3:** Some slop signals present, minimal effort visible.
|
- **Title is entirely hashtags, or mostly hastags** — near-instant slop
|
||||||
- **4:** Textbook slop — popular character + overused/slowed song + 4K tag + "Edit."
|
- **Hashtag spam** — title consists of a short hook followed by 3+ hashtags, or the description is dominated by hashtags. Strong signal on its own.
|
||||||
- **5:** Maximum slop density — every possible signal stacked.
|
- **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.
|
||||||
### SLOP SIGNALS
|
- **4K / [4K] tag** — strong signal when paired with anything else (optional)
|
||||||
Use these as intuition guides, not a checklist. Weight them by how many stack together.
|
- **"Edit" / "OneShot" / "Morphosis"** as suffix or with delimiters (║ Edit ║, 「Edit」)
|
||||||
|
- **Slowed / Reverb / Slowed+Reverb / MONTAGEM** — only counts when stacked with other signals
|
||||||
- **Emoji in title** — strong signal, especially 😂🤣😎😍🥺. Multiple emoji = very strong.
|
- **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.
|
||||||
- **Title is entirely hashtags** — near-instant slop.
|
- **Song name explicitly in title** — especially if slowed or remixed
|
||||||
- **Unicode styled text** (𝐋𝐢𝐤𝐞 𝐓𝐡𝐢𝐬) — common in character edits.
|
- **Description** — hashtag spam or music credits reinforce title signals
|
||||||
- **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.
|
- **Title mirrors description exactly** — reinforces slop when combined with other signals (optional)
|
||||||
- **4K / [4K] tag** — almost always slop when paired with anything else.
|
**2. Raw clip** — an unedited or minimally edited fragment of a TV show or movie with no transformative content.
|
||||||
- **"Edit" / "OneShot" / "Morphosis"** suffix or delimiter usage (║ Edit ║, 「Edit」).
|
**3. AI-generated compilation** — footage generated by AI tools. Score SLOP if:
|
||||||
- **Slowed / Reverb / Slowed+Reverb / MONTAGEM** — only counts when stacked with others
|
- Title or description explicitly mentions "Sora"
|
||||||
- **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.
|
|
||||||
|
|
||||||
### EXCEPTIONS
|
### EXCEPTIONS
|
||||||
- Tutorials, news, commentary, politics — score 0 automatically
|
Always score NOT SLOP:
|
||||||
- Lost/archived content — score 0 automatically
|
- News, commentary, politics
|
||||||
- Fan animations/original franchise-inspired art — do not trigger slop
|
- Lost or archived content
|
||||||
- Direct movie/TV clips or scenes uploaded without transformative editing — score 4 automatically
|
|
||||||
|
### 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
|
### 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 Title: ${title}
|
||||||
User Description: ${description.slice(0,100)}` }
|
User Description: ${description.slice(0,500)}` }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
})).json()
|
})).json()
|
||||||
|
|
||||||
let parsedResponse: {score: number, reasoning: string}
|
let parsedResponse: {is_slop: boolean, reasoning: string}
|
||||||
= { score: 0, reasoning: 'failed to parse' }
|
= { is_slop: false, reasoning: 'failed to parse' }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parsedResponse = JSON.parse(llmResponse.choices[0].message.content.replace(/```json|```/g, '').trim())
|
parsedResponse = JSON.parse(llmResponse.choices[0].message.content.replace(/```json|```/g, '').trim())
|
||||||
|
|
@ -82,16 +86,16 @@ User Description: ${description.slice(0,100)}` }
|
||||||
return parsedResponse
|
return parsedResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseSlop(id: string, title: string, description: string, channelId: string): Promise<number> {
|
async function parseSlop(id: string, title: string, description: string, channelId: string): Promise<boolean> {
|
||||||
if (channelBlacklist.includes(channelId)) return 5;
|
if (channelBlacklist.includes(channelId)) return true;
|
||||||
|
|
||||||
const cachedSlop = await redis.get(`slop:${id}`)
|
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)
|
const { is_slop, reasoning } = await analyseSlop(id , title, description)
|
||||||
if (reasoning != 'failed to parse') await redis.set(`slop:${id}`, score, 'EX', 60 * 60 * 24 * 7)
|
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 }
|
export { parseSlop }
|
||||||
Loading…
Reference in New Issue