Views
No views yet
<|sid_start|>: Marks the beginning of a semantic ID<|sid_X|>: Hierarchical level tokens where X ∈ [0, 1023]<|sid_end|>: Marks the end of a semantic ID<|rec|>: Trigger token for generating recommendations<|sid_start|><|sid_127|><|sid_45|><|sid_89|><|sid_12|><|sid_end|>pip install transformers torch datasets1from transformers import AutoModelForCausalLM, AutoTokenizer
2import torch
3
4# Load model and tokenizer
5model_name = "eugeneyan/semantic-id-qwen3-8b-video-games"
6model = AutoModelForCausalLM.from_pretrained(
7 model_name,
8 torch_dtype=torch.bfloat16,
9 device_map="auto",
10 trust_remote_code=True
11)
12tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
13
14# Set padding for generation
15if tokenizer.pad_token is None:
16 tokenizer.pad_token = tokenizer.eos_token
17
18# Generate recommendations
19prompt = "User: <|sid_start|><|sid_8|><|sid_454|><|sid_630|><|sid_768|><|sid_end|>\n<|rec|>"
20inputs = tokenizer(prompt, return_tensors="pt")
21
22with torch.no_grad():
23 outputs = model.generate(
24 **inputs,
25 max_new_tokens=50,
26 temperature=0.3,
27 top_p=0.7,
28 top_k=20,
29 do_sample=True,
30 pad_token_id=tokenizer.pad_token_id,
31 eos_token_id=tokenizer.eos_token_id
32 )
33
34# Decode only the generated portion
35input_length = inputs["input_ids"].shape[1]
36generated_tokens = outputs[:, input_length:]
37response = tokenizer.decode(generated_tokens[0], skip_special_tokens=False)
38print(response)1from datasets import load_dataset
2import pandas as pd
3import re
4from typing import List
5
6# Load mapping dataset
7dataset = load_dataset("eugeneyan/video-games-semantic-ids-mapping")
8mapping_df = dataset['train'].to_pandas()
9
10def parse_semantic_id(semantic_id: str) -> List[str]:
11 """Parse semantic ID into component levels"""
12 sid = semantic_id.replace("<|sid_start|>", "").replace("<|sid_end|>", "")
13 pattern = r"<\|sid_\d+\|>"
14 return re.findall(pattern, sid)
15
16def map_semantic_id_to_titles(semantic_id_str: str, mapping_df: pd.DataFrame) -> dict:
17 """
18 Map semantic ID to titles with exact match and fallback.
19 Returns dict with match_level, titles, count, and match_type.
20 """
21 levels = parse_semantic_id(semantic_id_str)
22
23 if not levels:
24 return {"match_level": 0, "titles": [], "count": 0}
25
26 # Try exact match first
27 exact_matches = mapping_df[mapping_df["semantic_id"] == semantic_id_str]
28 if len(exact_matches) > 0:
29 titles = exact_matches["title"].tolist()
30 return {"match_level": 4, "titles": titles, "count": len(titles), "match_type": "exact"}
31
32 # Fallback to prefix matching
33 for depth in range(min(3, len(levels)), 0, -1):
34 prefix = "<|sid_start|>" + "".join(levels[:depth])
35 matches = mapping_df[mapping_df["semantic_id"].str.startswith(prefix)]
36
37 if len(matches) > 0:
38 titles = matches["title"].tolist()
39 return {
40 "match_level": depth,
41 "titles": titles[:5],
42 "count": len(titles),
43 "match_type": "prefix"
44 }
45
46 return {"match_level": 0, "titles": [], "count": 0, "match_type": "none"}
47
48def extract_and_replace_semantic_ids(text: str, mapping_df: pd.DataFrame) -> str:
49 """Replace all semantic IDs in text with product titles"""
50 pattern = r"<\|sid_start\|>(?:<\|sid_\d+\|>)+<\|sid_end\|>"
51 semantic_ids = re.findall(pattern, text)
52
53 result = text
54 for sid in semantic_ids:
55 match_result = map_semantic_id_to_titles(sid, mapping_df)
56 if match_result["count"] > 0:
57 title = match_result["titles"][0]
58 replacement = f'"{title}"'
59 if match_result["match_type"] == "prefix":
60 replacement += f' (L{match_result["match_level"]} match)'
61 if match_result["count"] > 1:
62 replacement += f' [+{match_result["count"]-1} similar]'
63 else:
64 replacement = "[Unknown Item]"
65 result = result.replace(sid, replacement)
66
67 return result1# Provide input of user past interactions and get recommendation
2INPUT = """User: <|sid_start|><|sid_8|><|sid_454|><|sid_630|><|sid_768|><|sid_end|>, <|sid_start|><|sid_126|><|sid_501|><|sid_553|><|sid_768|><|sid_end|>, <|sid_start|><|sid_205|><|sid_370|><|sid_548|><|sid_768|><|sid_end|>
3<|rec|>""".strip()
4response = chat(INPUT)
5
6# Output: Recommended product
7<|sid_start|><|sid_205|><|sid_407|><|sid_586|><|sid_768|><|sid_end|><|im_end|>
8
9# Output mapped
10ASSISTANT: "Assassin's Creed 2 Deluxe Edition [Download]"1# Provide input of single past item and get similar item
2INPUT = """Customers who bought <|sid_start|><|sid_201|><|sid_311|><|sid_758|><|sid_768|><|sid_end|> also bought:
3<|rec|>""".strip()
4response = chat(INPUT)
5
6# Output: Recommended product
7<|sid_start|><|sid_201|><|sid_396|><|sid_608|><|sid_769|><|sid_end|><|im_end|>
8
9# Output mapped
10ASSISTANT: "The Legend of Zelda: Ocarina of Time 3D"1# Input: Natural language context
2# Provide natural language chat input and get item recommendations
3INPUT = """I like scifi and action games.
4<|rec|>""".strip()
5response = chat(INPUT)
6
7# Output: Multiple relevant products
8<|sid_start|><|sid_64|><|sid_313|><|sid_637|><|sid_768|><|sid_end|>, <|sid_start|><|sid_219|><|sid_463|><|sid_660|><|sid_768|><|sid_end|>, <|sid_start|><|sid_64|><|sid_313|><|sid_608|><|sid_768|><|sid_end|><|im_end|>
9
10# Output mapped
11ASSISTANT: "Halo 3 Limited Edition -Xbox 360", "Battlefield: Bad Company - Playstation 3", "Halo Reach - Limited Edition -Xbox 360"1# Steering recommendations given an item and attribute (Xbox)
2INPUT = """Recommend Xbox games similar to <|sid_start|><|sid_201|><|sid_396|><|sid_608|><|sid_769|><|sid_end|>:
3<|rec|>""".strip()
4response = chat(INPUT)
5
6# Output: Xbox-specific recommendations
7<|sid_start|><|sid_64|><|sid_271|><|sid_576|><|sid_768|><|sid_end|>, <|sid_start|><|sid_64|><|sid_400|><|sid_594|><|sid_768|><|sid_end|>, <|sid_start|><|sid_167|><|sid_271|><|sid_578|><|sid_768|><|sid_end|><|im_end|>
8
9# Output mapped
10ASSISTANT: "Fallout: New Vegas - Xbox 360 Ultimate Edition", "Tales of Vesperia - Xbox 360", "Halo Reach - Legendary Edition1# Provide natural language chat input and get item recommendations
2INPUT = """I like animal and cute games.
3<|rec|>""".strip()
4response = chat(INPUT)
5
6# Output: Games matching the genre preference
7<|sid_start|><|sid_173|><|sid_324|><|sid_764|><|sid_768|><|sid_end|>, <|sid_start|><|sid_201|><|sid_397|><|sid_738|><|sid_769|><|sid_end|>, <|sid_start|><|sid_173|><|sid_305|><|sid_670|><|sid_768|><|sid_end|><|im_end|>
8
9# Output mapped
10ASSISTANT: "Animal Crossing: New Leaf", "Disney Magical World - Nintendo 3DS", "Nintendogs + Cats: Golden Retriever and New Friends"1# Provide item to get recommendation and explanation
2INPUT = """I just finished <|sid_start|><|sid_125|><|sid_417|><|sid_656|><|sid_768|><|sid_end|>. Suggest another <|rec|> and explain why:""".strip()
3response = chat(INPUT)
4
5# Output: Recommendation with natural language explanation
6<|sid_start|><|sid_139|><|sid_289|><|sid_534|><|sid_768|><|sid_end|>
7
8If you liked Dragon Quest Heroes II, you might like Nights of Azure because both are action RPGs for the PlayStation 4 with a focus on combat and character progression. Both games offer a narrative-driven experience with a strong emphasis on combat mechanics, suggesting a shared appeal for players who enjoy this genre on the platform.<|im_end|>
9
10# Output mapped
11ASSISTANT: "Nights of Azure - PlayStation 4"
12
13If you liked Dragon Quest Heroes II, you might like Nights of Azure because both are action RPGs for the PlayStation 4 with a focus on combat and character progression. Both games offer a narrative-driven experience with a strong emphasis on combat mechanics, suggesting a shared appeal for players who enjoy this genre on the platform.1from transformers import TextStreamer
2
3def chat(text_input: str, messages: list = None, stream: bool = True):
4 """Interactive chat with the model"""
5 if messages is None:
6 messages = []
7
8 messages.append({"role": "user", "content": text_input})
9
10 # Apply chat template
11 text = tokenizer.apply_chat_template(
12 messages,
13 tokenize=False,
14 add_generation_prompt=True
15 )
16 inputs = tokenizer(text, return_tensors="pt").to(model.device)
17
18 # Stream output for better UX
19 streamer = TextStreamer(tokenizer, skip_prompt=True) if stream else None
20
21 with torch.no_grad():
22 output = model.generate(
23 **inputs,
24 max_new_tokens=512,
25 temperature=0.3,
26 top_p=0.7,
27 top_k=20,
28 do_sample=True,
29 streamer=streamer
30 )
31
32 # Extract only new tokens
33 input_length = inputs["input_ids"].shape[1]
34 generated = tokenizer.decode(output[0][input_length:], skip_special_tokens=True)
35
36 messages.append({"role": "assistant", "content": generated})
37 return generated, messages1# 1st turn: Ask for games similar to Mario Kart
2INPUT = "I'm looking for games similar to Mario Kart. <|rec|>"
3response1 = chat(INPUT)
4
5# Output
6<|sid_start|><|sid_131|><|sid_492|><|sid_639|><|sid_768|><|sid_end|>, <|sid_start|><|sid_145|><|sid_480|><|sid_617|><|sid_768|><|sid_end|>, <|sid_start|><|sid_145|><|sid_290|><|sid_620|><|sid_768|><|sid_end|><|im_end|>
7
8# Output mapped
9ASSISTANT: "CTR: Crash Team Racing", "Crazy Taxi 2 - Sega Dreamcast", "Mario Kart: Super Circuit"
10
11# 2nd turn: Tweak it for Xbox
12INPUT = "How about something similar but for Xbox? <|rec|>"
13response2 = chat(INPUT, new_convo=False)
14
15# Output
16<|sid_start|><|sid_183|><|sid_461|><|sid_517|><|sid_768|><|sid_end|>, <|sid_start|><|sid_183|><|sid_313|><|sid_679|><|sid_769|><|sid_end|>, <|sid_start|><|sid_183|><|sid_313|><|sid_605|><|sid_768|><|sid_end|><|im_end|>
17
18# Output mapped
19ASSISTANT: "Need for Speed Carbon - Xbox 360", "Forza Motorsport 2 - Xbox 360", "NASCAR '14 - Xbox 360"
20
21# 3rd turn: Ask for bundle name
22INPUT = "Suggest a name and description for the bundle"
23response3 = chat(INPUT, new_convo=False)
24
25# Output
26ASSISTANT: Xbox Racing Legends: NASCAR & Forza Collection@model{semantic_id_qwen3_8b_video_games,
author = {Eugene Yan},
title = {Semantic ID Recommender - Qwen3 8B (Video Games)},
year = {2024},
publisher = {Hugging Face},
url = {https://huggingface.co/eugeneyan/semantic-id-qwen3-8b-video-games}
}