<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Priyansh Kumar</title>
    <description>The latest articles on DEV Community by Priyansh Kumar (@pkumar18).</description>
    <link>https://dev.to/pkumar18</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4027956%2Fb370baac-c5f3-4464-9f03-487728aa6eca.jpg</url>
      <title>DEV Community: Priyansh Kumar</title>
      <link>https://dev.to/pkumar18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pkumar18"/>
    <language>en</language>
    <item>
      <title># I Shipped the First Real Stage of My Fanfiction Taste Engine, and It Isn't What I Originally Planned</title>
      <dc:creator>Priyansh Kumar</dc:creator>
      <pubDate>Sat, 25 Jul 2026 06:08:47 +0000</pubDate>
      <link>https://dev.to/pkumar18/-i-shipped-the-first-real-stage-of-my-fanfiction-taste-engine-and-it-isnt-what-i-originally-3gfd</link>
      <guid>https://dev.to/pkumar18/-i-shipped-the-first-real-stage-of-my-fanfiction-taste-engine-and-it-isnt-what-i-originally-3gfd</guid>
      <description>&lt;p&gt;A few weeks ago I wrote about &lt;a href="https://github.com/P-Kumar-18/Siagnos" rel="noopener noreferrer"&gt;Siagnos&lt;/a&gt;, a personal taste engine for fanfiction that learns from reading behavior instead of matching tags. I was three stages in: scraper done, schema designed, embeddings working as a proof of concept.&lt;/p&gt;

&lt;p&gt;Then I got a two-week internship window to build something deployable, and I made a call. Instead of pushing Siagnos forward stage by stage, I built &lt;a href="https://github.com/P-Kumar-18/Opsis" rel="noopener noreferrer"&gt;Opsis&lt;/a&gt;: a scoped-down, content-based recommender that answers one specific question. Given a fic, what else in a real, collected corpus is closest to it in content?&lt;/p&gt;

&lt;p&gt;Opsis doesn't do taste modeling. It doesn't touch my reading behavior at all. It's the layer underneath that, and it's live right now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why not just keep building Siagnos directly
&lt;/h2&gt;

&lt;p&gt;Two weeks isn't enough time to get a reading tracker, a feature pipeline, and a trained preference model all working end to end. It is enough time to take the scraper and schema I already had and turn them into something real: a working recommender, deployed, with a UI, that someone else can actually use today.&lt;/p&gt;

&lt;p&gt;So I scoped down on purpose. No personal taste model yet. No behavior tracking yet. Just: can I take one fic and find genuinely similar ones, from AO3 metadata alone, using content instead of tags?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Opsis actually does
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Scrapes AO3 metadata under conditions the OTW Communications Committee confirmed were acceptable before I collected anything: one persistent session, randomized delays, capped retries&lt;/li&gt;
&lt;li&gt;Cleans and validates the raw data, log-and-skip instead of all-or-nothing, so one malformed row doesn't take down a 7,000-fic load&lt;/li&gt;
&lt;li&gt;Normalizes everything into PostgreSQL: fics, six lookup tables, six join tables, idempotent upserts so re-running the loader is always safe&lt;/li&gt;
&lt;li&gt;Embeds every fic's summary with &lt;code&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ranks candidates with a blended score: 0.70 embedding cosine similarity, 0.15 fandom overlap, 0.10 relationship overlap, 0.05 popularity&lt;/li&gt;
&lt;li&gt;If you submit a fic that isn't in the database yet, Opsis scrapes it, cleans it, stores it, and embeds it on the spot, then recommends, closing the loop between "not yet known" and "recommendable" without me touching anything
That last part started as a stretch goal. It shipped.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;Deployed and reachable right now: FastAPI and Jinja2 on Render, PostgreSQL on Neon. Not a notebook, not a local script, an actual multi-page site: a landing page, a recommend page with three ways to submit a fic (work ID, URL, or title and author), and an about page walking through the pipeline for anyone non-technical who lands on it.&lt;/p&gt;

&lt;p&gt;The dataset: 7,031 fics, mostly My Hero Academia with a meaningful share of crossover works pulling in other fandoms, 1,549 distinct fandom tags, 5,584 relationships, 5,785 characters, 30,132 freeform tags. Metadata only. No fanwork text is ever scraped or stored.&lt;/p&gt;

&lt;p&gt;What I haven't done: a formal accuracy benchmark. No precision or recall number, because that needs labeled relevance data I don't have yet, and a fixed corpus snapshot to test against, which a system with on-demand ingestion doesn't naturally have. I said so directly in the project report instead of making up a number. What I do have: informal testing across manual queries, top recommendations consistently landing in a 50 to 70 percent blended similarity range, which is a plausibility check, not a quality claim.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this sets up for Siagnos
&lt;/h2&gt;

&lt;p&gt;The architecture wasn't built to only solve Opsis's narrower problem. The embedding storage sits behind an abstract interface specifically so a future pgvector migration doesn't touch the ranking logic that consumes it. The schema already has a &lt;code&gt;behaviour&lt;/code&gt; table and a &lt;code&gt;rating_types&lt;/code&gt; enum, sitting there unpopulated, waiting for Stage 4.&lt;/p&gt;

&lt;p&gt;That's next: a reading tracker, logging what I actually open, how far I get, whether I come back. Once that exists, the fixed linear ranking blend Opsis uses today gets replaced by something trained on real ground truth, my ground truth, instead of a hand-picked weight for embedding similarity versus tag overlap.&lt;/p&gt;

&lt;p&gt;Opsis proved the retrieval half works. Siagnos is still about the half that matters more: whether a system can learn what I actually like.&lt;/p&gt;




&lt;p&gt;I recorded a two-minute walkthrough of the pipeline and the live site, linked below. Both repos are public:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/P-Kumar-18/Opsis" rel="noopener noreferrer"&gt;Opsis on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/P-Kumar-18/Siagnos" rel="noopener noreferrer"&gt;Siagnos on GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://youtu.be/tzvqT1WojLo" rel="noopener noreferrer"&gt;Video&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>nlp</category>
      <category>machinelearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Got Tired of Bad Fanfiction Recommendations, So I'm Building My Own Taste Engine</title>
      <dc:creator>Priyansh Kumar</dc:creator>
      <pubDate>Tue, 14 Jul 2026 02:15:50 +0000</pubDate>
      <link>https://dev.to/pkumar18/i-got-tired-of-bad-fanfiction-recommendations-so-im-building-my-own-taste-engine-1ag1</link>
      <guid>https://dev.to/pkumar18/i-got-tired-of-bad-fanfiction-recommendations-so-im-building-my-own-taste-engine-1ag1</guid>
      <description>&lt;p&gt;I read fanfiction. A lot of it, on AO3 and FanFiction.net. Finding something worth reading takes longer than it should.&lt;/p&gt;

&lt;p&gt;AO3 has over 10 million works. The discovery tool is tag search. You type a fandom, a ship, maybe a few tags, and scroll through whatever comes back. Kudos and bookmarks sort the list, but those measure popularity, not whether you'll enjoy it. A fic with 10k kudos might be beloved by thousands and still not your thing.&lt;/p&gt;

&lt;p&gt;I tried describing what I wanted to Claude once. It couldn't help. No domain knowledge, no idea what makes a fic actually good, no model of my taste. It guessed from a description. That's not useful.&lt;/p&gt;

&lt;p&gt;Every existing recommendation tool in this space matches surface features. Same fandom, same tags, same ship. None of them look at pacing, character voice, emotional tone, the things that make you stay up until 3am finishing something.&lt;/p&gt;

&lt;p&gt;I'm building Siagnos to fix that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Siagnos actually does
&lt;/h2&gt;

&lt;p&gt;Siagnos is a personal taste engine. Track what I actually read, build a model of my taste from that behavior, score unseen fics against it.&lt;/p&gt;

&lt;p&gt;A preference model trained on my own reading data. The pipeline has six parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrape fic metadata from AO3: title, fandom, tags, word count, kudos, completion status, summary&lt;/li&gt;
&lt;li&gt;Track real reading sessions: what I open, how far I get, whether I come back&lt;/li&gt;
&lt;li&gt;Generate embeddings from summaries using HuggingFace sentence transformers&lt;/li&gt;
&lt;li&gt;Run a local LLM (Mistral 7B via Ollama) to extract richer features from summaries (tone, pacing, character dynamics)&lt;/li&gt;
&lt;li&gt;Train a preference model on reading history using XGBoost&lt;/li&gt;
&lt;li&gt;Given a fic URL, return a taste score and a plain-language reason&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The output I want: "This matches your taste because it has the same slow-burn structure and morally grey protagonist you keep coming back to." Actual signal, not a popularity rank.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where it stands right now
&lt;/h2&gt;

&lt;p&gt;I'm three stages in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 0&lt;/strong&gt;: project structure, Git, virtual environment, mental model of embeddings and cosine similarity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1&lt;/strong&gt;: sentence transformers installed, embeddings generated for a handful of fic summaries, cosine similarity working. Proof of concept done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2&lt;/strong&gt;: scraper complete. Built with cloudscraper and BeautifulSoup, retry logic, failed URL logging, adult content bypass, resume from last point. Scraped around 7,000 My Hero Academia fics to CSV. Also collected behavior data for about 100 fics I've personally read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3&lt;/strong&gt;: PostgreSQL schema designed and implemented. Tables for fics, reading sessions, six value tables, six join tables, ENUMs for status and rating types. Schema committed to the repo.&lt;/p&gt;

&lt;p&gt;Stage 4 is next: a reading tracker, either a browser extension or a bookmarklet, that logs real sessions to the database.&lt;/p&gt;




&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;p&gt;Python throughout. FastAPI for the backend when I get there. PostgreSQL replacing SQLite, which I'd outgrown. HuggingFace sentence transformers for embeddings. Ollama running Mistral 7B locally for feature extraction. XGBoost for the preference model. Docker for containerization. Azure for deployment.&lt;/p&gt;

&lt;p&gt;One constraint I set myself: no LangChain or similar for the core pipeline. Build it first, understand what's actually happening, add abstractions later if they help.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this is worth building
&lt;/h2&gt;

&lt;p&gt;Nobody with real ML experience is building for fanfiction readers. The domain is large (AO3 hit 879 million weekly page views earlier this year) and the recommendation problem is unsolved. I know the domain as a reader, which most ML engineers building recommendation systems don't.&lt;/p&gt;

&lt;p&gt;Siagnos builds a preference model trained on individual reading behavior. I'm a BCA student, this is my second serious project, and I'm learning ML from first principles by building it. Future posts will cover the pipeline, the modeling approach, and what failed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Siagnos is on GitHub: &lt;a href="https://github.com/P-Kumar-18/Siagnos" rel="noopener noreferrer"&gt;github.com/P-Kumar-18&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>nlp</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
