Repository navigation
Expand file tree
/
Copy pathapp.html
More file actions
70 lines (70 loc) · 15.6 KB
/
Copy pathapp.html
File metadata and controls
70 lines (70 loc) · 15.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sift — Your feed, on your terms</title>
<link rel="stylesheet" href="app.css">
<script type="module" src="app.js"></script>
</head>
<body>
<div class="app-shell">
<aside class="sidebar">
<a class="brand" href="#preferences" aria-label="Sift home"><svg viewBox="0 0 36 36" aria-hidden="true"><path d="M7 9h22l-8 10v8l-6 3V19Z" fill="currentColor"/><path d="M10 5h16" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg><span>sift<span class="brand-dot">.</span></span></a>
<p class="sidebar-caption">A little less noise.<br>A little more you.</p>
<nav class="main-nav" aria-label="Main navigation">
<a class="nav-link active" href="#preferences" data-tab="preferences"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h16M4 17h16M8 4v6m8 4v6"/></svg>Preferences</a>
<a class="nav-link" href="#review" data-tab="review"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="4" y="5" width="16" height="15" rx="3"/><path d="M8 3v4m8-4v4M8 12h8m-8 4h5"/></svg>Review feed<span class="nav-count" id="history-count">0</span></a>
<a class="nav-link" href="#connection" data-tab="connection"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m8 13 5-5m-6 8-1 1a4 4 0 0 1-6-6l4-4a4 4 0 0 1 6 0m4 1 1-1a4 4 0 0 1 6 6l-4 4a4 4 0 0 1-6 0" transform="translate(2 0) scale(.9)"/></svg>Connection</a>
</nav>
<div class="sidebar-bottom">
<div class="filter-control"><div><span class="filter-label">Feed filter</span><span id="sidebar-filter-description" class="muted-light">Ready when you are</span></div><label class="switch"><input type="checkbox" id="enabled-toggle" aria-label="Enable feed filter"><span></span></label></div>
<button id="open-x" class="open-x-button">Open X <span aria-hidden="true">↗</span></button>
<p class="sidebar-note">Made for a more intentional scroll.</p>
</div>
</aside>
<main class="main">
<header class="topbar"><span class="eyebrow">YOUR PERSONAL FEED FILTER</span><a id="connection-status" class="connection-badge" href="#connection"><span class="status-dot"></span><span id="connection-status-text">Checking connection</span></a></header>
<div id="app-notice" class="notice" role="status" hidden></div>
<section id="preferences-panel" class="tab-panel" aria-labelledby="preferences-title">
<div class="page-heading"><div><span class="section-kicker">LESS NOISE, MORE SIGNAL</span><h1 id="preferences-title">Your feed, on your terms.</h1><p>Tell Sift what belongs in your feed.<br>Your feedback makes the details clearer.</p></div><div class="sift-art" aria-hidden="true"><div class="art-line line-one"></div><div class="art-line line-two"></div><div class="art-line line-three"></div><div class="art-seed seed-one"></div><div class="art-seed seed-two"></div><div class="art-seed seed-three"></div><span class="art-caption">Find your signal.</span></div></div>
<div id="setup-notice" class="setup-notice" hidden><span class="setup-icon" aria-hidden="true">↗</span><div><strong id="setup-title">One connection. A calmer feed.</strong><p id="setup-description">Add an OpenAI API key and your preferences, then open your X home feed to start filtering.</p></div><a class="text-button" id="setup-action" href="#connection">Set up Sift <span aria-hidden="true">→</span></a></div>
<div class="preferences-grid">
<div class="preferences-main">
<form id="preferences-form" class="card preference-card">
<div class="card-title-row"><div><span class="step-label">01 / THE BIG PICTURE</span><h2>What would you like to see?</h2></div><span class="pill">In your own words</span></div>
<p class="card-description" id="preferences-help">Your preferences apply to posts and replies. You can mention replies naturally, for example: “In replies…” Describe writing quality: AI-style filler refers to style and does not establish who wrote a reply.</p>
<label class="sr-only" for="preferences-input">Feed preferences</label>
<textarea id="preferences-input" rows="8" aria-describedby="preferences-help" placeholder="Keep thoughtful design, technology, useful research, and people sharing what they’re building. Skip engagement bait and repetitive hype. In replies, hide generic AI-style filler, hate, and comments that add nothing. Keep useful criticism, questions, and first-hand experience." maxlength="12000"></textarea>
<div class="preference-actions"><button class="subtle-button" id="use-example" type="button">Try an example <span aria-hidden="true">↗</span></button><div class="save-actions"><span id="preferences-save-status" class="save-status" role="status"></span><button class="primary-button" id="save-preferences" type="submit">Save preferences <span aria-hidden="true">→</span></button></div></div>
</form>
<section class="card remembered-card" aria-labelledby="remembered-title"><div class="card-title-row"><div><span class="step-label">02 / THE FINER DETAILS</span><h2 id="remembered-title">What Sift has learned</h2></div><span class="count-pill" id="rule-count">0 rules</span></div><p class="card-description">Your feedback becomes a remembered rule for future Decisions requests. Rules apply to posts and replies unless you scope them. Remove any rule to stop using it.</p><div id="rules-list"></div></section>
</div>
<aside class="context-column">
<section class="card how-card"><div class="mini-icon" aria-hidden="true">✳</div><h3>A feed that gets you.</h3><ol><li><span>01</span><div><strong>Describe your preferences</strong><p>A few sentences are a great start.</p></div></li><li><span>02</span><div><strong>Scroll as usual</strong><p>Sift reviews loaded posts and replies, using the preferences you write.</p></div></li><li><span>03</span><div><strong>Fine-tune as you go</strong><p>Use “Tune feed” on a post or correct a hidden post in Review feed.</p></div></li></ol></section>
<section class="stats-card"><span class="step-label">YOUR FEED, SO FAR</span><div class="stat-large"><strong data-stat="reviewed" title="Posts first reviewed since reset. Deduplication tracks the last 5,000 post IDs.">0</strong><span title="Posts first reviewed since reset. Deduplication tracks the last 5,000 post IDs.">posts reviewed</span></div><div class="stats-divider"></div><div class="stat-pair"><div><strong data-stat="hidden" title="Posts hidden at least once since reset. Corrections can overlap with initially kept posts. Deduplication tracks the last 5,000 post IDs.">0</strong><span title="Posts hidden at least once since reset. Corrections can overlap with initially kept posts. Deduplication tracks the last 5,000 post IDs.">ever filtered</span></div><div><strong data-stat="kept" title="Posts shown on their first review since reset, even if later hidden. Corrections may overlap with ever-filtered posts. Deduplication tracks the last 5,000 post IDs.">0</strong><span title="Posts shown on their first review since reset, even if later hidden. Corrections may overlap with ever-filtered posts. Deduplication tracks the last 5,000 post IDs.">initially kept</span></div></div><p>Since reset. Corrections can overlap; deduplication tracks the last 5,000 post IDs.</p></section>
</aside>
</div>
</section>
<section id="review-panel" class="tab-panel" aria-labelledby="review-title" hidden>
<div class="page-heading compact-heading"><div><span class="section-kicker">A LITTLE TRANSPARENCY</span><h1 id="review-title">Nothing disappears for good.</h1><p>See what Sift decided, understand why, and teach it a little more.</p></div></div>
<div class="review-stats"><div><span class="metric-label" title="Posts first reviewed since reset. Deduplication tracks the last 5,000 post IDs.">Posts reviewed</span><strong data-stat="reviewed" title="Posts first reviewed since reset. Deduplication tracks the last 5,000 post IDs.">0</strong></div><div><span class="metric-label" title="Posts hidden at least once since reset. Corrections can overlap with initially kept posts. Deduplication tracks the last 5,000 post IDs.">Ever filtered</span><strong data-stat="hidden" title="Posts hidden at least once since reset. Corrections can overlap with initially kept posts. Deduplication tracks the last 5,000 post IDs.">0</strong></div><div><span class="metric-label" title="Posts shown on their first review since reset, even if later hidden. Corrections may overlap with ever-filtered posts. Deduplication tracks the last 5,000 post IDs.">Initially kept</span><strong data-stat="kept" title="Posts shown on their first review since reset, even if later hidden. Corrections may overlap with ever-filtered posts. Deduplication tracks the last 5,000 post IDs.">0</strong></div><div><span class="metric-label">Your corrections</span><strong data-stat="feedback">0</strong></div></div>
<div class="review-toolbar"><label class="search-field"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 4 4"/></svg><input id="history-search" type="search" placeholder="Search posts, people, or reasons" aria-label="Search review history"></label><label class="sr-only" for="history-filter">Filter review history</label><select id="history-filter"><option value="hidden">Hidden posts</option><option value="all">All decisions</option><option value="restored">Restored posts</option><option value="shown">Kept posts</option></select><span class="result-count" id="result-count"></span></div>
<p class="history-note">History shows recent decisions stored on this device. New feedback updates loaded posts and future decisions.</p>
<div id="history-list" class="history-list"></div>
</section>
<section id="connection-panel" class="tab-panel" aria-labelledby="connection-title" hidden>
<div class="page-heading compact-heading"><div><span class="section-kicker">THE ENGINE UNDERNEATH</span><h1 id="connection-title">Connect your intelligence.</h1><p>Sift uses the OpenAI Decisions API to match each post against your preferences.</p></div></div>
<div class="connection-grid"><div>
<form id="connection-form" class="card connection-card"><span class="step-label">OPENAI CONNECTION</span><h2>Your API, your control.</h2><p class="card-description">An OpenAI API key is required. API usage is billed separately from a ChatGPT subscription.</p><div class="form-field"><label for="api-key">API key</label><div class="password-field"><input id="api-key" type="password" placeholder="sk-…" autocomplete="off" spellcheck="false" maxlength="500"><button id="show-key" type="button" class="subtle-button" aria-label="Show API key">Show</button></div><p>Stored locally in this Chrome profile. The key is not encrypted.</p></div><div class="form-field"><label for="model-input">Model</label><input id="model-input" type="text" value="gpt-6-luna" spellcheck="false" readonly aria-describedby="model-description"><p id="model-description">OpenAI Decisions API · gpt-6-luna. This is the model supported by the Decisions endpoint.</p></div><div class="connection-actions"><button id="test-connection" type="button" class="secondary-button">Test connection</button><button id="save-connection" type="submit" class="primary-button">Save connection <span aria-hidden="true">→</span></button></div><p id="connection-message" class="form-message" role="status"></p></form>
<section class="card behavior-card"><span class="step-label">MAKE YOURSELF AT HOME</span><h2>Filtering behavior</h2><div class="setting-row"><div><label for="home-only">Limit feed filtering to Home</label><p>For feed timelines, leave profiles and search as they are. Reply threads have their own setting below.</p></div><label class="switch"><input type="checkbox" id="home-only"><span></span></label></div><div class="setting-row"><div><label for="filter-replies">Filter replies</label><p>Use your preferences in reply threads and identified feed replies, including when feed filtering is limited to Home. Keep the original post and its ancestors visible.</p></div><label class="switch"><input type="checkbox" id="filter-replies"><span></span></label></div><div class="setting-row"><div><label for="show-placeholders">Leave a small note for hidden posts</label><p>See what was filtered and restore it without leaving X.</p></div><label class="switch"><input type="checkbox" id="show-placeholders"><span></span></label></div><p id="behavior-message" class="form-message" role="status"></p></section>
</div><aside class="context-column"><section class="card privacy-card"><div class="mini-icon" aria-hidden="true">⌁</div><h3>A clear view of your data.</h3><p>Post text, available author information, context and image descriptions, your preferences, and remembered rules are sent to OpenAI to make filtering decisions.</p><p>Sift stores preferences, recent decisions, and feedback in this Chrome profile. Feedback adds rules; it does not train the model. Post text and available image descriptions are evaluated; images and videos themselves are not sent.</p><a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer">Get an OpenAI API key <span aria-hidden="true">↗</span></a></section><section class="card usage-card"><span class="step-label">API USAGE</span><dl><div><dt>Requests</dt><dd data-stat="apiRequests">0</dd></div><div><dt>Input tokens</dt><dd data-stat="inputTokens">0</dd></div><div><dt>Output tokens</dt><dd data-stat="outputTokens">0</dd></div></dl><p>Token counts are reported by the API. Charges follow the Decisions API model’s pricing.</p></section><section class="data-controls"><h3>A fresh start</h3><button id="clear-history" class="text-button" type="button">Clear review history <span aria-hidden="true">↗</span></button><button id="clear-stats" class="text-button" type="button">Reset statistics <span aria-hidden="true">↗</span></button><p>Your preferences and remembered rules stay in place.</p></section></aside></div>
</section>
<footer class="main-footer"><span>Less noise. Better scrolling.</span><span>SIFT / PERSONAL FEED FILTER</span></footer>
</main>
</div>
<dialog id="feedback-dialog"><form id="feedback-form"><div class="dialog-heading"><span class="step-label">TEACH SIFT A LITTLE MORE</span><button type="button" class="icon-button" id="close-feedback" aria-label="Close feedback dialog">×</button></div><h2 id="feedback-title">Keep posts like this</h2><p id="feedback-explainer">Tell Sift what it missed. Your comment becomes a preference for future posts.</p><div id="feedback-thread" hidden></div><blockquote id="feedback-preview"></blockquote><label for="feedback-comment">What should Sift remember?</label><textarea id="feedback-comment" rows="4" required maxlength="1000" placeholder="For example: In replies, keep useful criticism and first-hand experience."></textarea><p class="form-message" id="feedback-message" role="status"></p><div class="dialog-actions"><button type="button" id="cancel-feedback" class="secondary-button">Cancel</button><button type="submit" class="primary-button" id="submit-feedback">Save & restore post <span aria-hidden="true">→</span></button></div></form></dialog>
<dialog id="confirm-dialog"><form method="dialog"><span class="step-label">A FRESH START</span><h2 id="confirm-title">Clear review history?</h2><p id="confirm-copy"></p><div class="dialog-actions"><button value="cancel" class="secondary-button">Cancel</button><button id="confirm-action" value="confirm" class="primary-button">Clear history</button></div></form></dialog>
<div id="toast" class="toast" role="status" hidden></div>
</body>
</html>