Reuse an existing category's spelling in the categorizer; document the Interests page (step 9)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K9PrjtUS16PAQve8D4bHgc
This commit is contained in:
@@ -214,7 +214,10 @@ sees complete issues and article chapters and can download available formats
|
||||
from a single download menu. An
|
||||
`admin` can additionally follow direct dashboard links from issue entries and
|
||||
article chapters, rate articles, and use every `/dashboard/*` page, including
|
||||
settings and jobs. Personalization is shared across accounts for now.
|
||||
settings and jobs. `/dashboard/interests` lists the standing interests with
|
||||
their LLM-assigned category and a rating-derived weight, adds or deletes them,
|
||||
and links every interest name in the UI to the articles it matched.
|
||||
Personalization is shared across accounts for now.
|
||||
|
||||
Visitors can request an account with their preferred username at
|
||||
`/request-access`; admins review open requests on `/dashboard/users`. Approving
|
||||
@@ -250,6 +253,7 @@ Set `server.jobs_enabled = false` to make starts unavailable.
|
||||
| `backfill-social` | Refresh recent social scores. |
|
||||
| `features-prune` | Remove stale embeddings and curation telemetry. |
|
||||
| `import-ratings` | Fetch, embed, and rate URLs queued from the Ratings page. |
|
||||
| `interests-categorize` | File uncategorized interests under categories with the bulk model. |
|
||||
|
||||
The Ratings page accepts up to 500 historical article URLs at a time with one
|
||||
verdict and optional note. Imports run in the background and show per-URL
|
||||
|
||||
+11
-5
@@ -354,8 +354,8 @@ async fn categorize_with_llm(db: &Db, pending: &[Interest], llm: &LlmClient) ->
|
||||
.collect::<HashMap<_, _>>();
|
||||
let existing_categories = categories
|
||||
.iter()
|
||||
.map(|category| category.to_lowercase())
|
||||
.collect::<BTreeSet<_>>();
|
||||
.map(|category| (category.to_lowercase(), *category))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let mut assigned = BTreeSet::new();
|
||||
let mut new_categories = BTreeSet::new();
|
||||
let now = Timestamp::now();
|
||||
@@ -367,10 +367,16 @@ async fn categorize_with_llm(db: &Db, pending: &[Interest], llm: &LlmClient) ->
|
||||
if !(1..=60).contains(&category.chars().count()) || !assigned.insert(interest.id) {
|
||||
continue;
|
||||
}
|
||||
set_category(db, interest.id, Some(category), now).await?;
|
||||
if !existing_categories.contains(&category.to_lowercase()) {
|
||||
// A model that answers "software" for an existing "Software" must not
|
||||
// split the category.
|
||||
let category = match existing_categories.get(&category.to_lowercase()) {
|
||||
Some(existing) => existing,
|
||||
None => {
|
||||
new_categories.insert(category.to_string());
|
||||
category
|
||||
}
|
||||
};
|
||||
set_category(db, interest.id, Some(category), now).await?;
|
||||
}
|
||||
|
||||
let mut message = format!(
|
||||
@@ -750,7 +756,7 @@ mod tests {
|
||||
let backend = Arc::new(MockBackend::new());
|
||||
backend.push(
|
||||
r#"{"assignments":[
|
||||
{"interest":"RUST MACROS","category":" Software "},
|
||||
{"interest":"RUST MACROS","category":" software "},
|
||||
{"interest":"Wheel-thrown pottery","category":"Creative crafts"},
|
||||
{"interest":"Not in the batch","category":"Made up"}
|
||||
]}"#,
|
||||
|
||||
Reference in New Issue
Block a user