File size: 4,947 Bytes
6b1bc4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Apply the engine-3.0 integration edits to a checkout of the UniHive `main` repo (python apply_main_patch.py <repo root>).
Every replacement must match exactly once, so the script refuses to run on a different version of the files.
  backend/personalization/service.py : create_slate asks the hybrid engine for POST scores when PERSONALIZATION_ENGINE=hybrid (falls back to the baseline on any error)
  backend/tagging.py                 : default tagger model gpt-oss-120b (with the token budget a reasoning model needs)
  backend/requirements.txt           : onnxruntime stated explicitly (fastembed already pulls it in)
  docker-compose.yml                 : mounts migration 012 for fresh databases"""
import os, sys
root = sys.argv[1]

def patch(rel, pairs):
    p = os.path.join(root, rel); s = open(p, encoding="utf8", newline="").read(); crlf = "\r\n" in s; s = s.replace("\r\n", "\n")
    for old, new in pairs:
        assert s.count(old) == 1, f"{rel}: expected exactly one match for: {old[:90]!r} (found {s.count(old)})"
        s = s.replace(old, new)
    open(p, "w", encoding="utf8", newline="").write(s.replace("\n", "\r\n") if crlf else s); print("patched", rel)

patch("backend/personalization/service.py", [
    ("from .math import features, aggregate, affinities, reading_reward, rank_score, diversify, MODEL_VERSION, decay\n",
     "from .math import features, aggregate, affinities, reading_reward, rank_score, diversify, MODEL_VERSION, decay\n"
     "import logging\nfrom . import hybrid as hybrid_engine\n\n_log=logging.getLogger('personalization')\nHYBRID_SUFFIX='+hybrid-3.0-bge384'\n\n"
     "def _model_version(items):\n    \"\"\"The snapshot's model version: the baseline's, plus a suffix when the hybrid engine scored any post in it.\"\"\"\n"
     "    return MODEL_VERSION+HYBRID_SUFFIX if any((i.get('features') or {}).get('engine') for i in items) else MODEL_VERSION\n"),
    ("    ranked=[]\n    for entity_type,entities in [('POST',posts),('PROJECT',projects)]:\n",
     "    hybrid=None\n    if state['enabled'] and posts and hybrid_engine.enabled():\n"
     "        # Engine 3.0 scores the POSTS (projects keep the baseline); any failure falls back to the baseline ranker for this slate.\n"
     "        try:\n            from .hybrid.main_adapter import score_posts_for_slate\n"
     "            hybrid=await score_posts_for_slate(c,hybrid_engine.get_engine(),user_id,posts,[dict(v) for v in vectors],order_mode=hybrid_engine.order_mode())\n"
     "        except Exception:\n            _log.exception('Hybrid engine failed; using the baseline ranker for this slate');hybrid=None\n"
     "    ranked=[]\n    for entity_type,entities in [('POST',posts),('PROJECT',projects)]:\n"),
    ("            score,reasons,values=rank_score(entity,f,state['preferences'],state['declared'],skill_match=skill_match,semantic=semantic)\n",
     "            if entity_type=='POST' and hybrid is not None and str(entity['id']) in hybrid:\n"
     "                h=hybrid[str(entity['id'])];score,reasons,values=h['score'],h['reasons'],{**h['features'],'engine':'hybrid-3.0-bge384','engine_score':h['engine_score']}\n"
     "            else:score,reasons,values=rank_score(entity,f,state['preferences'],state['declared'],skill_match=skill_match,semantic=semantic)\n"),
    ("('news' if news else 'home'),state['version'],MODEL_VERSION,items)\n", "('news' if news else 'home'),state['version'],_model_version(items),items)\n"),
    ("'reasons':item['reasons'],'model_version':MODEL_VERSION}\n", "'reasons':item['reasons'],'model_version':_model_version(items)}\n"),
    ("'request_id':str(request_id),'model_version':MODEL_VERSION}\n", "'request_id':str(request_id),'model_version':_model_version(items)}\n"),
])
patch("backend/tagging.py", [
    ("def provider_tags(title, content, domains):\n",
     "def _model():\n    return os.getenv('TAGGING_MODEL', 'openai/gpt-oss-120b')\n\n"
     "def _extra():\n    # A reasoning model spends completion tokens on reasoning: give it room and keep the reasoning short.\n"
     "    return {'reasoning_effort':'low','max_tokens':1500} if _model().startswith('openai/gpt-oss') else {'max_tokens':250}\n\n"
     "def provider_tags(title, content, domains):\n"),
    ("json={'model':os.getenv('TAGGING_MODEL','llama-3.3-70b-versatile'),", "json={'model':_model(),"),
    ("'temperature':0,'max_tokens':250})", "'temperature':0,**_extra()})"),
])
patch("backend/requirements.txt", [("fastembed==0.7.4", "fastembed==0.7.4\nonnxruntime>=1.18")])
patch("docker-compose.yml", [("      - ./backend/migrations/011_social_moderation.sql:/docker-entrypoint-initdb.d/11_social_moderation.sql:ro\n",
                              "      - ./backend/migrations/011_social_moderation.sql:/docker-entrypoint-initdb.d/11_social_moderation.sql:ro\n"
                              "      - ./backend/migrations/012_domains_catalogue.sql:/docker-entrypoint-initdb.d/12_domains_catalogue.sql:ro\n")])