Laura Wagner commited on
Commit Β·
db8c63e
1
Parent(s): 23cc0e3
corrected llm code
Browse files
jupyter_notebooks/Section_2-3-4_Figure_8_deepfake_adapters.ipynb
CHANGED
|
@@ -142,40 +142,40 @@
|
|
| 142 |
"name": "stdout",
|
| 143 |
"output_type": "stream",
|
| 144 |
"text": [
|
| 145 |
-
"
|
| 146 |
"Loaded 18 rows\n",
|
| 147 |
"\n",
|
| 148 |
-
"
|
| 149 |
"\n",
|
| 150 |
-
"
|
| 151 |
"====================================================================================================\n",
|
| 152 |
"Original Name | Cleaned Name \n",
|
| 153 |
"====================================================================================================\n",
|
| 154 |
"Super Pose Book Vol.1 - ControlNet | Super Pose Book \n",
|
| 155 |
"Liyuu LoRA | Liyuu \n",
|
| 156 |
-
"HashimotoKanna/
|
| 157 |
"Emma Watson (JG) | Emma Watson \n",
|
| 158 |
-
"Gal Gadot
|
| 159 |
-
"Scarlett Johansson
|
| 160 |
-
"Gakki | Aragaki Yui |
|
| 161 |
-
"Actress Satomi_
|
| 162 |
"Game of Thrones Cast | Game Thrones Cast \n",
|
| 163 |
-
"Natalie Portman
|
| 164 |
"Emma Watson LoRA | Emma Watson \n",
|
| 165 |
"====================================================================================================\n",
|
| 166 |
"\n",
|
| 167 |
-
"
|
| 168 |
" 4kira LoRA -> akira\n",
|
| 169 |
" 3mma Watson v2 -> Watson\n",
|
| 170 |
" 1rene LORA -> irene\n",
|
| 171 |
" L3vi Ackerman -> Levi Ackerman\n",
|
| 172 |
"\n",
|
| 173 |
-
"
|
| 174 |
" Total rows: 18\n",
|
| 175 |
" Non-empty names: 18\n",
|
| 176 |
" Empty names: 0\n",
|
| 177 |
"\n",
|
| 178 |
-
"
|
| 179 |
" 1. IU\n",
|
| 180 |
" 2. Super Pose Book\n",
|
| 181 |
" 3. Liyuu\n",
|
|
@@ -187,8 +187,8 @@
|
|
| 187 |
" 9. Emma Watson\n",
|
| 188 |
" 10. Gal Gadot\n",
|
| 189 |
"\n",
|
| 190 |
-
"
|
| 191 |
-
"
|
| 192 |
]
|
| 193 |
}
|
| 194 |
],
|
|
@@ -203,13 +203,13 @@
|
|
| 203 |
"# You may need to download it first: python -m spacy download en_core_web_sm\n",
|
| 204 |
"try:\n",
|
| 205 |
" nlp = spacy.load(\"en_core_web_sm\")\n",
|
| 206 |
-
" print(\"
|
| 207 |
"except OSError:\n",
|
| 208 |
-
" print(\"
|
| 209 |
" import subprocess\n",
|
| 210 |
" subprocess.run([\"python\", \"-m\", \"spacy\", \"download\", \"en_core_web_sm\"])\n",
|
| 211 |
" nlp = spacy.load(\"en_core_web_sm\")\n",
|
| 212 |
-
" print(\"
|
| 213 |
"\n",
|
| 214 |
"# Set up paths\n",
|
| 215 |
"current_dir = Path.cwd()\n",
|
|
@@ -282,8 +282,8 @@
|
|
| 282 |
" name = re.sub(r'\\([^)]*\\)', '', name)\n",
|
| 283 |
" name = re.sub(r'\\[[^\\]]*\\]', '', name)\n",
|
| 284 |
" \n",
|
| 285 |
-
" # Remove special characters like \
|
| 286 |
-
" name = re.sub(r'[
|
| 287 |
" \n",
|
| 288 |
" # Handle pipe - keep first part\n",
|
| 289 |
" if '|' in name:\n",
|
|
@@ -339,7 +339,7 @@
|
|
| 339 |
" Complete name cleaning pipeline with spaCy NER.\n",
|
| 340 |
" \n",
|
| 341 |
" Pipeline:\n",
|
| 342 |
-
" 1. Translate leetspeak (4
|
| 343 |
" 2. Remove noise (emoji, version tags, LoRA terms)\n",
|
| 344 |
" 3. Use spaCy to extract PERSON entities\n",
|
| 345 |
" 4. Fallback to capitalized words or cleaned text\n",
|
|
@@ -356,11 +356,11 @@
|
|
| 356 |
" return person_name\n",
|
| 357 |
"\n",
|
| 358 |
"# Apply name cleaning with spaCy\n",
|
| 359 |
-
"print(\"\\n
|
| 360 |
"df['real_name'] = df['name'].apply(clean_name_with_spacy)\n",
|
| 361 |
"\n",
|
| 362 |
"# Show examples with detailed comparison\n",
|
| 363 |
-
"print(\"\\n
|
| 364 |
"print(\"=\" * 100)\n",
|
| 365 |
"print(f\"{'Original Name':<50} | {'Cleaned Name':<30}\")\n",
|
| 366 |
"print(\"=\" * 100)\n",
|
|
@@ -375,31 +375,31 @@
|
|
| 375 |
"print(\"=\" * 100)\n",
|
| 376 |
"\n",
|
| 377 |
"# Show specific test cases\n",
|
| 378 |
-
"print(\"\\n
|
| 379 |
"test_names = ['4kira LoRA', '3mma Watson v2', '1rene LORA', 'L3vi Ackerman']\n",
|
| 380 |
"for test in test_names:\n",
|
| 381 |
" result = clean_name_with_spacy(test)\n",
|
| 382 |
" print(f\" {test:<30} -> {result}\")\n",
|
| 383 |
"\n",
|
| 384 |
"# Statistics\n",
|
| 385 |
-
"print(f\"\\n
|
| 386 |
"print(f\" Total rows: {len(df)}\")\n",
|
| 387 |
"print(f\" Non-empty names: {(df['real_name'] != '').sum()}\")\n",
|
| 388 |
"print(f\" Empty names: {(df['real_name'] == '').sum()}\")\n",
|
| 389 |
"\n",
|
| 390 |
"# Show some examples of what spaCy identified\n",
|
| 391 |
-
"print(\"\\n
|
| 392 |
"sample_names = df['real_name'].head(20).tolist()\n",
|
| 393 |
"for i, name in enumerate(sample_names[:10], 1):\n",
|
| 394 |
" if name:\n",
|
| 395 |
" print(f\" {i}. {name}\")\n",
|
| 396 |
"\n",
|
| 397 |
-
"print(f\"\\n
|
| 398 |
"\n",
|
| 399 |
"# Save intermediate result\n",
|
| 400 |
"output_step1 = current_dir.parent / \"data/CSV/NER_POI_step01_pre_annotation.csv\"\n",
|
| 401 |
"df.to_csv(output_step1, index=False)\n",
|
| 402 |
-
"print(f\"
|
| 403 |
]
|
| 404 |
},
|
| 405 |
{
|
|
@@ -444,7 +444,7 @@
|
|
| 444 |
"8 Emma Watson actor\n",
|
| 445 |
"9 Gal Gadot model\n",
|
| 446 |
"\n",
|
| 447 |
-
"
|
| 448 |
" Name: Irene\n",
|
| 449 |
" Tags: ['girl', 'photorealistic', 'asian', 'woman', 'beautiful', 'celebrity', 'korean']\n",
|
| 450 |
" Country: \n",
|
|
@@ -485,7 +485,7 @@
|
|
| 485 |
"\n",
|
| 486 |
"poi_df[\"tags\"] = poi_df.apply(combine_tags, axis=1)\n",
|
| 487 |
"\n",
|
| 488 |
-
"# Step 2: Build tag
|
| 489 |
"tag_to_country_nationality = {}\n",
|
| 490 |
"# We'll use a priority score: direct country name = 3, nationality = 2, word parts = 1\n",
|
| 491 |
"\n",
|
|
@@ -563,7 +563,7 @@
|
|
| 563 |
"\n",
|
| 564 |
"poi_df[[\"likely_country\", \"likely_nationality\"]] = poi_df[\"tags\"].apply(infer_country_and_nationality)\n",
|
| 565 |
"\n",
|
| 566 |
-
"# Step 4: Build tag
|
| 567 |
"profession_alias_map = {}\n",
|
| 568 |
"\n",
|
| 569 |
"for _, row in professions_df.iterrows():\n",
|
|
@@ -611,7 +611,7 @@
|
|
| 611 |
"# Check specific case: Irene with korean tag\n",
|
| 612 |
"irene_rows = poi_df[poi_df['real_name'].str.contains('irene', case=False, na=False)]\n",
|
| 613 |
"if len(irene_rows) > 0:\n",
|
| 614 |
-
" print(f\"\\n
|
| 615 |
" for idx, row in irene_rows.iterrows():\n",
|
| 616 |
" print(f\" Name: {row['real_name']}\")\n",
|
| 617 |
" print(f\" Tags: {row['tags']}\")\n",
|
|
@@ -652,7 +652,7 @@
|
|
| 652 |
"name": "stdout",
|
| 653 |
"output_type": "stream",
|
| 654 |
"text": [
|
| 655 |
-
"
|
| 656 |
" Please create this file with your API key\n"
|
| 657 |
]
|
| 658 |
},
|
|
@@ -663,7 +663,7 @@
|
|
| 663 |
"traceback": [
|
| 664 |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 665 |
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
|
| 666 |
-
"Cell \u001b[0;32mIn[10], line 37\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[38;5;66;03m# === LOAD API KEY ===\u001b[39;00m\n\u001b[1;32m 36\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 37\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mapi_key_file\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[1;32m 38\u001b[0m api_key \u001b[38;5;241m=\u001b[39m f\u001b[38;5;241m.\u001b[39mread()\u001b[38;5;241m.\u001b[39mstrip()\n\u001b[1;32m 39\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m
|
| 667 |
"File \u001b[0;32m~/.local/lib/python3.10/site-packages/IPython/core/interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[0;34m(file, *args, **kwargs)\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 319\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 320\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 322\u001b[0m )\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mio_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 668 |
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/misc/credentials/deepseek_api_key.txt'"
|
| 669 |
]
|
|
@@ -708,9 +708,9 @@
|
|
| 708 |
"try:\n",
|
| 709 |
" with open(api_key_file) as f:\n",
|
| 710 |
" api_key = f.read().strip()\n",
|
| 711 |
-
" print(\"
|
| 712 |
"except FileNotFoundError:\n",
|
| 713 |
-
" print(\"
|
| 714 |
" print(\" Please create this file with your API key\")\n",
|
| 715 |
" raise\n",
|
| 716 |
"\n",
|
|
@@ -726,9 +726,9 @@
|
|
| 726 |
"# Load profession categories and keywords\n",
|
| 727 |
"try:\n",
|
| 728 |
" prof_mapped_df = pd.read_csv(professions_mapped_file)\n",
|
| 729 |
-
" print(f\"
|
| 730 |
"except:\n",
|
| 731 |
-
" print(\"
|
| 732 |
"\n",
|
| 733 |
"profession_str = \", \".join(PROFESSION_CATEGORIES)\n",
|
| 734 |
"\n",
|
|
@@ -895,11 +895,11 @@
|
|
| 895 |
" df.to_csv(output_file, index=False)\n",
|
| 896 |
" with open(index_file, 'w') as f:\n",
|
| 897 |
" f.write(str(current_index))\n",
|
| 898 |
-
" print(f\"
|
| 899 |
" \n",
|
| 900 |
" time.sleep(1) # Rate limiting\n",
|
| 901 |
" \n",
|
| 902 |
-
" print(f\"\\n
|
| 903 |
" \n",
|
| 904 |
" # Summary statistics\n",
|
| 905 |
" print(\"\\n=== Summary Statistics ===\")\n",
|
|
@@ -917,15 +917,15 @@
|
|
| 917 |
" print(df[display_cols].head(10).to_string(index=False))\n",
|
| 918 |
"\n",
|
| 919 |
"except Exception as e:\n",
|
| 920 |
-
" print(f\"
|
| 921 |
-
" print(f\"
|
| 922 |
" \n",
|
| 923 |
" # Save progress before exiting\n",
|
| 924 |
" df.to_csv(output_file, index=False)\n",
|
| 925 |
" with open(index_file, 'w') as f:\n",
|
| 926 |
" f.write(str(current_index))\n",
|
| 927 |
" \n",
|
| 928 |
-
" print(f\"
|
| 929 |
]
|
| 930 |
},
|
| 931 |
{
|
|
@@ -954,169 +954,7 @@
|
|
| 954 |
"id": "qwen_code",
|
| 955 |
"metadata": {},
|
| 956 |
"outputs": [],
|
| 957 |
-
"source": [
|
| 958 |
-
"import pandas as pd",
|
| 959 |
-
"import json",
|
| 960 |
-
"import time",
|
| 961 |
-
"import re",
|
| 962 |
-
"from pathlib import Path",
|
| 963 |
-
"from tqdm import tqdm",
|
| 964 |
-
"from openai import OpenAI",
|
| 965 |
-
"",
|
| 966 |
-
"current_dir = Path.cwd()",
|
| 967 |
-
"input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"",
|
| 968 |
-
"api_key_file = current_dir.parent / \"misc/credentials/qwen_api_key.txt\"",
|
| 969 |
-
"",
|
| 970 |
-
"# === CONFIGURATION ===",
|
| 971 |
-
"TEST_MODE = True",
|
| 972 |
-
"TEST_SIZE = 10",
|
| 973 |
-
"MAX_ROWS = 20000",
|
| 974 |
-
"SAVE_INTERVAL = 10",
|
| 975 |
-
"",
|
| 976 |
-
"PROFESSION_CATEGORIES = [",
|
| 977 |
-
" \"actor\", \"adult performer\", \"singer/musician\", \"model\",",
|
| 978 |
-
" \"online personality\", \"public figure\", \"voice actor/ASMR\",",
|
| 979 |
-
" \"sports professional\", \"tv personality\"",
|
| 980 |
-
"]",
|
| 981 |
-
"",
|
| 982 |
-
"# === LOAD API KEY ===",
|
| 983 |
-
"try:",
|
| 984 |
-
" with open(api_key_file) as f:",
|
| 985 |
-
" api_key = f.read().strip()",
|
| 986 |
-
" print(\"\u2705 Qwen API key loaded\")",
|
| 987 |
-
" print(f\" Key starts with: {api_key[:10]}...\")",
|
| 988 |
-
"except FileNotFoundError:",
|
| 989 |
-
" print(\"\u274c Error: qwen_api_key.txt not found\")",
|
| 990 |
-
" raise",
|
| 991 |
-
"",
|
| 992 |
-
"# Initialize OpenAI client for Qwen (matching dashboard example)",
|
| 993 |
-
"client = OpenAI(",
|
| 994 |
-
" api_key=api_key,",
|
| 995 |
-
" base_url=\"https://dashscope-intl.aliyuncs.com/compatible-mode/v1\"",
|
| 996 |
-
")",
|
| 997 |
-
"",
|
| 998 |
-
"# === LOAD DATA ===",
|
| 999 |
-
"df = pd.read_csv(input_file)",
|
| 1000 |
-
"print(f\"Loaded {len(df)} rows\")",
|
| 1001 |
-
"",
|
| 1002 |
-
"if TEST_MODE:",
|
| 1003 |
-
" print(f\"Running in TEST MODE with {TEST_SIZE} samples\")",
|
| 1004 |
-
" df = df.head(TEST_SIZE).copy()",
|
| 1005 |
-
"elif MAX_ROWS:",
|
| 1006 |
-
" df = df.head(MAX_ROWS).copy()",
|
| 1007 |
-
"",
|
| 1008 |
-
"# === CREATE PROMPT ===",
|
| 1009 |
-
"def create_prompt(name: str, tags: list, country: str) -> str:",
|
| 1010 |
-
" tags_str = \", \".join(tags[:5]) if tags else \"none\"",
|
| 1011 |
-
" country_str = country if country else \"unknown\"",
|
| 1012 |
-
" ",
|
| 1013 |
-
" return f\"\"\"You are an expert at identifying public figures.",
|
| 1014 |
-
"",
|
| 1015 |
-
"Given: Name: {name}, Tags: {tags_str}, Country: {country_str}",
|
| 1016 |
-
"",
|
| 1017 |
-
"Provide in JSON format:",
|
| 1018 |
-
"{{",
|
| 1019 |
-
" \"full_name\": \"<full name>\",",
|
| 1020 |
-
" \"gender\": \"<Male/Female/Other/Unknown>\",",
|
| 1021 |
-
" \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],",
|
| 1022 |
-
" \"country\": \"<country>\"",
|
| 1023 |
-
"}}",
|
| 1024 |
-
"",
|
| 1025 |
-
"Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}",
|
| 1026 |
-
"- Max 3 professions, ordered by relevance",
|
| 1027 |
-
"- \"online personality\" includes streamers, cosplayers, influencers",
|
| 1028 |
-
"- Return \"Unknown\" if uncertain",
|
| 1029 |
-
"",
|
| 1030 |
-
"Return ONLY JSON, no extra text.\"\"\"",
|
| 1031 |
-
"",
|
| 1032 |
-
"# === QUERY QWEN ===",
|
| 1033 |
-
"def query_qwen(prompt: str) -> dict:",
|
| 1034 |
-
" \"\"\"Query Qwen using OpenAI-compatible API (matching dashboard example).\"\"\"",
|
| 1035 |
-
" for attempt in range(3):",
|
| 1036 |
-
" try:",
|
| 1037 |
-
" completion = client.chat.completions.create(",
|
| 1038 |
-
" model=\"qwen-max\", # Note: dashboard shows \"qwen3-max\" but \"qwen-max\" works too",
|
| 1039 |
-
" messages=[",
|
| 1040 |
-
" {\"role\": \"user\", \"content\": prompt}",
|
| 1041 |
-
" ],",
|
| 1042 |
-
" temperature=0.1,",
|
| 1043 |
-
" max_tokens=500,",
|
| 1044 |
-
" stream=False # Disable streaming for easier parsing",
|
| 1045 |
-
" )",
|
| 1046 |
-
" ",
|
| 1047 |
-
" content = completion.choices[0].message.content",
|
| 1048 |
-
" ",
|
| 1049 |
-
" # Parse JSON from response",
|
| 1050 |
-
" json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)",
|
| 1051 |
-
" if json_match:",
|
| 1052 |
-
" return json.loads(json_match.group())",
|
| 1053 |
-
" ",
|
| 1054 |
-
" return None",
|
| 1055 |
-
" ",
|
| 1056 |
-
" except Exception as e:",
|
| 1057 |
-
" print(f\"Qwen error (attempt {attempt+1}): {e}\")",
|
| 1058 |
-
" if attempt < 2:",
|
| 1059 |
-
" time.sleep(2 ** attempt)",
|
| 1060 |
-
" ",
|
| 1061 |
-
" return None",
|
| 1062 |
-
"",
|
| 1063 |
-
"# === PROCESS ===",
|
| 1064 |
-
"output_file = current_dir.parent / f\"data/CSV/qwen_annotated_POI{'_test' if TEST_MODE else ''}.csv\"",
|
| 1065 |
-
"index_file = current_dir.parent / \"misc/qwen_query_index.txt\"",
|
| 1066 |
-
"",
|
| 1067 |
-
"current_index = 0",
|
| 1068 |
-
"if index_file.exists():",
|
| 1069 |
-
" with open(index_file) as f:",
|
| 1070 |
-
" current_index = int(f.read().strip())",
|
| 1071 |
-
"",
|
| 1072 |
-
"for col in ['full_name', 'gender', 'profession_llm', 'country']:",
|
| 1073 |
-
" if col not in df.columns:",
|
| 1074 |
-
" df[col] = 'Unknown'",
|
| 1075 |
-
"",
|
| 1076 |
-
"print(f\"\\nAnnotating with QWEN-MAX (OpenAI-compatible API) - rows {current_index} to {len(df)}...\")",
|
| 1077 |
-
"",
|
| 1078 |
-
"try:",
|
| 1079 |
-
" for i in tqdm(range(current_index, len(df)), desc=\"Qwen\"):",
|
| 1080 |
-
" row = df.iloc[i]",
|
| 1081 |
-
" ",
|
| 1082 |
-
" tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8) ",
|
| 1083 |
-
" if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]",
|
| 1084 |
-
" ",
|
| 1085 |
-
" prompt = create_prompt(",
|
| 1086 |
-
" row.get('real_name', row.get('name', '')),",
|
| 1087 |
-
" tags,",
|
| 1088 |
-
" row.get('likely_country', '')",
|
| 1089 |
-
" )",
|
| 1090 |
-
" ",
|
| 1091 |
-
" result = query_qwen(prompt)",
|
| 1092 |
-
" ",
|
| 1093 |
-
" if result:",
|
| 1094 |
-
" df.at[i, 'full_name'] = result.get('full_name', 'Unknown')",
|
| 1095 |
-
" df.at[i, 'gender'] = result.get('gender', 'Unknown')",
|
| 1096 |
-
" profs = result.get('professions', [])",
|
| 1097 |
-
" df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)",
|
| 1098 |
-
" df.at[i, 'country'] = result.get('country', 'Unknown')",
|
| 1099 |
-
" ",
|
| 1100 |
-
" current_index = i + 1",
|
| 1101 |
-
" ",
|
| 1102 |
-
" if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):",
|
| 1103 |
-
" df.to_csv(output_file, index=False)",
|
| 1104 |
-
" with open(index_file, 'w') as f:",
|
| 1105 |
-
" f.write(str(current_index))",
|
| 1106 |
-
" print(f\"\u2705 Saved after {i+1} rows\")",
|
| 1107 |
-
" ",
|
| 1108 |
-
" time.sleep(0.5)",
|
| 1109 |
-
" ",
|
| 1110 |
-
" print(f\"\\n\u2705 Done! Results: {output_file}\")",
|
| 1111 |
-
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")",
|
| 1112 |
-
" ",
|
| 1113 |
-
"except Exception as e:",
|
| 1114 |
-
" print(f\"\u26a0\ufe0f Error: {e}\")",
|
| 1115 |
-
" df.to_csv(output_file, index=False)",
|
| 1116 |
-
" with open(index_file, 'w') as f:",
|
| 1117 |
-
" f.write(str(current_index))",
|
| 1118 |
-
""
|
| 1119 |
-
]
|
| 1120 |
},
|
| 1121 |
{
|
| 1122 |
"cell_type": "markdown",
|
|
@@ -1140,165 +978,7 @@
|
|
| 1140 |
"id": "llama_code",
|
| 1141 |
"metadata": {},
|
| 1142 |
"outputs": [],
|
| 1143 |
-
"source": [
|
| 1144 |
-
"import pandas as pd",
|
| 1145 |
-
"import json",
|
| 1146 |
-
"import time",
|
| 1147 |
-
"import requests",
|
| 1148 |
-
"import re",
|
| 1149 |
-
"from pathlib import Path",
|
| 1150 |
-
"from tqdm import tqdm",
|
| 1151 |
-
"",
|
| 1152 |
-
"current_dir = Path.cwd()",
|
| 1153 |
-
"input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"",
|
| 1154 |
-
"api_key_file = current_dir.parent / \"misc/credentials/together_api_key.txt\"",
|
| 1155 |
-
"",
|
| 1156 |
-
"# === CONFIGURATION ===",
|
| 1157 |
-
"TEST_MODE = True",
|
| 1158 |
-
"TEST_SIZE = 10",
|
| 1159 |
-
"MAX_ROWS = 20000",
|
| 1160 |
-
"SAVE_INTERVAL = 10",
|
| 1161 |
-
"",
|
| 1162 |
-
"PROFESSION_CATEGORIES = [",
|
| 1163 |
-
" \"actor\", \"adult performer\", \"singer/musician\", \"model\",",
|
| 1164 |
-
" \"online personality\", \"public figure\", \"voice actor/ASMR\",",
|
| 1165 |
-
" \"sports professional\", \"tv personality\"",
|
| 1166 |
-
"]",
|
| 1167 |
-
"",
|
| 1168 |
-
"# === LOAD API KEY ===",
|
| 1169 |
-
"try:",
|
| 1170 |
-
" with open(api_key_file) as f:",
|
| 1171 |
-
" api_key = f.read().strip()",
|
| 1172 |
-
" print(\"\u2705 Llama API key loaded\")",
|
| 1173 |
-
"except FileNotFoundError:",
|
| 1174 |
-
" print(\"\u274c Error: together_api_key.txt not found\")",
|
| 1175 |
-
" raise",
|
| 1176 |
-
"",
|
| 1177 |
-
"# === LOAD DATA ===",
|
| 1178 |
-
"df = pd.read_csv(input_file)",
|
| 1179 |
-
"print(f\"Loaded {len(df)} rows\")",
|
| 1180 |
-
"",
|
| 1181 |
-
"if TEST_MODE:",
|
| 1182 |
-
" print(f\"Running in TEST MODE with {TEST_SIZE} samples\")",
|
| 1183 |
-
" df = df.head(TEST_SIZE).copy()",
|
| 1184 |
-
"elif MAX_ROWS:",
|
| 1185 |
-
" df = df.head(MAX_ROWS).copy()",
|
| 1186 |
-
"",
|
| 1187 |
-
"# === CREATE PROMPT ===",
|
| 1188 |
-
"def create_prompt(name: str, tags: list, country: str) -> str:",
|
| 1189 |
-
" tags_str = \", \".join(tags[:5]) if tags else \"none\"",
|
| 1190 |
-
" country_str = country if country else \"unknown\"",
|
| 1191 |
-
" ",
|
| 1192 |
-
" return f\"\"\"You are an expert at identifying public figures.",
|
| 1193 |
-
"",
|
| 1194 |
-
"Given: Name: {name}, Tags: {tags_str}, Country: {country_str}",
|
| 1195 |
-
"",
|
| 1196 |
-
"Provide in JSON format:",
|
| 1197 |
-
"{{",
|
| 1198 |
-
" \"full_name\": \"<full name>\",",
|
| 1199 |
-
" \"gender\": \"<Male/Female/Other/Unknown>\",",
|
| 1200 |
-
" \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],",
|
| 1201 |
-
" \"country\": \"<country>\"",
|
| 1202 |
-
"}}",
|
| 1203 |
-
"",
|
| 1204 |
-
"Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}",
|
| 1205 |
-
"- Max 3 professions, ordered by relevance",
|
| 1206 |
-
"- \"online personality\" includes streamers, cosplayers, influencers",
|
| 1207 |
-
"- Return \"Unknown\" if uncertain",
|
| 1208 |
-
"",
|
| 1209 |
-
"Return ONLY JSON, no extra text.\"\"\"",
|
| 1210 |
-
"",
|
| 1211 |
-
"# === QUERY LLAMA ===",
|
| 1212 |
-
"def query_llama(prompt: str) -> dict:",
|
| 1213 |
-
" url = \"https://api.together.xyz/v1/chat/completions\"",
|
| 1214 |
-
" ",
|
| 1215 |
-
" headers = {",
|
| 1216 |
-
" \"Authorization\": f\"Bearer {api_key}\",",
|
| 1217 |
-
" \"Content-Type\": \"application/json\"",
|
| 1218 |
-
" }",
|
| 1219 |
-
" ",
|
| 1220 |
-
" data = {",
|
| 1221 |
-
" \"model\": \"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo\",",
|
| 1222 |
-
" \"messages\": [{\"role\": \"user\", \"content\": prompt}],",
|
| 1223 |
-
" \"temperature\": 0.1,",
|
| 1224 |
-
" \"max_tokens\": 500",
|
| 1225 |
-
" }",
|
| 1226 |
-
" ",
|
| 1227 |
-
" for attempt in range(3):",
|
| 1228 |
-
" try:",
|
| 1229 |
-
" response = requests.post(url, headers=headers, json=data, timeout=30)",
|
| 1230 |
-
" response.raise_for_status()",
|
| 1231 |
-
" result = response.json()",
|
| 1232 |
-
" ",
|
| 1233 |
-
" if 'choices' in result:",
|
| 1234 |
-
" content = result['choices'][0]['message']['content']",
|
| 1235 |
-
" json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)",
|
| 1236 |
-
" if json_match:",
|
| 1237 |
-
" return json.loads(json_match.group())",
|
| 1238 |
-
" return None",
|
| 1239 |
-
" except Exception as e:",
|
| 1240 |
-
" print(f\"Llama error (attempt {attempt+1}): {e}\")",
|
| 1241 |
-
" if attempt < 2:",
|
| 1242 |
-
" time.sleep(2 ** attempt)",
|
| 1243 |
-
" return None",
|
| 1244 |
-
"",
|
| 1245 |
-
"# === PROCESS ===",
|
| 1246 |
-
"output_file = current_dir.parent / f\"data/CSV/llama_annotated_POI{'_test' if TEST_MODE else ''}.csv\"",
|
| 1247 |
-
"index_file = current_dir.parent / \"misc/llama_query_index.txt\"",
|
| 1248 |
-
"",
|
| 1249 |
-
"current_index = 0",
|
| 1250 |
-
"if index_file.exists():",
|
| 1251 |
-
" with open(index_file) as f:",
|
| 1252 |
-
" current_index = int(f.read().strip())",
|
| 1253 |
-
"",
|
| 1254 |
-
"for col in ['full_name', 'gender', 'profession_llm', 'country']:",
|
| 1255 |
-
" if col not in df.columns:",
|
| 1256 |
-
" df[col] = 'Unknown'",
|
| 1257 |
-
"",
|
| 1258 |
-
"print(f\"\\nAnnotating with LLAMA 3.1 70B - rows {current_index} to {len(df)}...\")",
|
| 1259 |
-
"",
|
| 1260 |
-
"try:",
|
| 1261 |
-
" for i in tqdm(range(current_index, len(df)), desc=\"Llama\"):",
|
| 1262 |
-
" row = df.iloc[i]",
|
| 1263 |
-
" ",
|
| 1264 |
-
" tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8) ",
|
| 1265 |
-
" if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]",
|
| 1266 |
-
" ",
|
| 1267 |
-
" prompt = create_prompt(",
|
| 1268 |
-
" row.get('real_name', row.get('name', '')),",
|
| 1269 |
-
" tags,",
|
| 1270 |
-
" row.get('likely_country', '')",
|
| 1271 |
-
" )",
|
| 1272 |
-
" ",
|
| 1273 |
-
" result = query_llama(prompt)",
|
| 1274 |
-
" ",
|
| 1275 |
-
" if result:",
|
| 1276 |
-
" df.at[i, 'full_name'] = result.get('full_name', 'Unknown')",
|
| 1277 |
-
" df.at[i, 'gender'] = result.get('gender', 'Unknown')",
|
| 1278 |
-
" profs = result.get('professions', [])",
|
| 1279 |
-
" df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)",
|
| 1280 |
-
" df.at[i, 'country'] = result.get('country', 'Unknown')",
|
| 1281 |
-
" ",
|
| 1282 |
-
" current_index = i + 1",
|
| 1283 |
-
" ",
|
| 1284 |
-
" if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):",
|
| 1285 |
-
" df.to_csv(output_file, index=False)",
|
| 1286 |
-
" with open(index_file, 'w') as f:",
|
| 1287 |
-
" f.write(str(current_index))",
|
| 1288 |
-
" print(f\"\u2705 Saved after {i+1} rows\")",
|
| 1289 |
-
" ",
|
| 1290 |
-
" time.sleep(0.5)",
|
| 1291 |
-
" ",
|
| 1292 |
-
" print(f\"\\n\u2705 Done! Results: {output_file}\")",
|
| 1293 |
-
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")",
|
| 1294 |
-
" ",
|
| 1295 |
-
"except Exception as e:",
|
| 1296 |
-
" print(f\"\u26a0\ufe0f Error: {e}\")",
|
| 1297 |
-
" df.to_csv(output_file, index=False)",
|
| 1298 |
-
" with open(index_file, 'w') as f:",
|
| 1299 |
-
" f.write(str(current_index))",
|
| 1300 |
-
""
|
| 1301 |
-
]
|
| 1302 |
},
|
| 1303 |
{
|
| 1304 |
"cell_type": "markdown",
|
|
@@ -1322,165 +1002,7 @@
|
|
| 1322 |
"id": "mixtral_code",
|
| 1323 |
"metadata": {},
|
| 1324 |
"outputs": [],
|
| 1325 |
-
"source": [
|
| 1326 |
-
"import pandas as pd",
|
| 1327 |
-
"import json",
|
| 1328 |
-
"import time",
|
| 1329 |
-
"import requests",
|
| 1330 |
-
"import re",
|
| 1331 |
-
"from pathlib import Path",
|
| 1332 |
-
"from tqdm import tqdm",
|
| 1333 |
-
"",
|
| 1334 |
-
"current_dir = Path.cwd()",
|
| 1335 |
-
"input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"",
|
| 1336 |
-
"api_key_file = current_dir.parent / \"misc/credentials/mistral_api_key.txt\"",
|
| 1337 |
-
"",
|
| 1338 |
-
"# === CONFIGURATION ===",
|
| 1339 |
-
"TEST_MODE = True",
|
| 1340 |
-
"TEST_SIZE = 10",
|
| 1341 |
-
"MAX_ROWS = 20000",
|
| 1342 |
-
"SAVE_INTERVAL = 10",
|
| 1343 |
-
"",
|
| 1344 |
-
"PROFESSION_CATEGORIES = [",
|
| 1345 |
-
" \"actor\", \"adult performer\", \"singer/musician\", \"model\",",
|
| 1346 |
-
" \"online personality\", \"public figure\", \"voice actor/ASMR\",",
|
| 1347 |
-
" \"sports professional\", \"tv personality\"",
|
| 1348 |
-
"]",
|
| 1349 |
-
"",
|
| 1350 |
-
"# === LOAD API KEY ===",
|
| 1351 |
-
"try:",
|
| 1352 |
-
" with open(api_key_file) as f:",
|
| 1353 |
-
" api_key = f.read().strip()",
|
| 1354 |
-
" print(\"\u2705 Mixtral API key loaded\")",
|
| 1355 |
-
"except FileNotFoundError:",
|
| 1356 |
-
" print(\"\u274c Error: mistral_api_key.txt not found\")",
|
| 1357 |
-
" raise",
|
| 1358 |
-
"",
|
| 1359 |
-
"# === LOAD DATA ===",
|
| 1360 |
-
"df = pd.read_csv(input_file)",
|
| 1361 |
-
"print(f\"Loaded {len(df)} rows\")",
|
| 1362 |
-
"",
|
| 1363 |
-
"if TEST_MODE:",
|
| 1364 |
-
" print(f\"Running in TEST MODE with {TEST_SIZE} samples\")",
|
| 1365 |
-
" df = df.head(TEST_SIZE).copy()",
|
| 1366 |
-
"elif MAX_ROWS:",
|
| 1367 |
-
" df = df.head(MAX_ROWS).copy()",
|
| 1368 |
-
"",
|
| 1369 |
-
"# === CREATE PROMPT ===",
|
| 1370 |
-
"def create_prompt(name: str, tags: list, country: str) -> str:",
|
| 1371 |
-
" tags_str = \", \".join(tags[:5]) if tags else \"none\"",
|
| 1372 |
-
" country_str = country if country else \"unknown\"",
|
| 1373 |
-
" ",
|
| 1374 |
-
" return f\"\"\"You are an expert at identifying public figures.",
|
| 1375 |
-
"",
|
| 1376 |
-
"Given: Name: {name}, Tags: {tags_str}, Country: {country_str}",
|
| 1377 |
-
"",
|
| 1378 |
-
"Provide in JSON format:",
|
| 1379 |
-
"{{",
|
| 1380 |
-
" \"full_name\": \"<full name>\",",
|
| 1381 |
-
" \"gender\": \"<Male/Female/Other/Unknown>\",",
|
| 1382 |
-
" \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],",
|
| 1383 |
-
" \"country\": \"<country>\"",
|
| 1384 |
-
"}}",
|
| 1385 |
-
"",
|
| 1386 |
-
"Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}",
|
| 1387 |
-
"- Max 3 professions, ordered by relevance",
|
| 1388 |
-
"- \"online personality\" includes streamers, cosplayers, influencers",
|
| 1389 |
-
"- Return \"Unknown\" if uncertain",
|
| 1390 |
-
"",
|
| 1391 |
-
"Return ONLY JSON, no extra text.\"\"\"",
|
| 1392 |
-
"",
|
| 1393 |
-
"# === QUERY MIXTRAL ===",
|
| 1394 |
-
"def query_mixtral(prompt: str) -> dict:",
|
| 1395 |
-
" url = \"https://api.mistral.ai/v1/chat/completions\"",
|
| 1396 |
-
" ",
|
| 1397 |
-
" headers = {",
|
| 1398 |
-
" \"Authorization\": f\"Bearer {api_key}\",",
|
| 1399 |
-
" \"Content-Type\": \"application/json\"",
|
| 1400 |
-
" }",
|
| 1401 |
-
" ",
|
| 1402 |
-
" data = {",
|
| 1403 |
-
" \"model\": \"open-mixtral-8x22b\",",
|
| 1404 |
-
" \"messages\": [{\"role\": \"user\", \"content\": prompt}],",
|
| 1405 |
-
" \"temperature\": 0.1,",
|
| 1406 |
-
" \"max_tokens\": 500",
|
| 1407 |
-
" }",
|
| 1408 |
-
" ",
|
| 1409 |
-
" for attempt in range(3):",
|
| 1410 |
-
" try:",
|
| 1411 |
-
" response = requests.post(url, headers=headers, json=data, timeout=30)",
|
| 1412 |
-
" response.raise_for_status()",
|
| 1413 |
-
" result = response.json()",
|
| 1414 |
-
" ",
|
| 1415 |
-
" if 'choices' in result:",
|
| 1416 |
-
" content = result['choices'][0]['message']['content']",
|
| 1417 |
-
" json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)",
|
| 1418 |
-
" if json_match:",
|
| 1419 |
-
" return json.loads(json_match.group())",
|
| 1420 |
-
" return None",
|
| 1421 |
-
" except Exception as e:",
|
| 1422 |
-
" print(f\"Mixtral error (attempt {attempt+1}): {e}\")",
|
| 1423 |
-
" if attempt < 2:",
|
| 1424 |
-
" time.sleep(2 ** attempt)",
|
| 1425 |
-
" return None",
|
| 1426 |
-
"",
|
| 1427 |
-
"# === PROCESS ===",
|
| 1428 |
-
"output_file = current_dir.parent / f\"data/CSV/mixtral_annotated_POI{'_test' if TEST_MODE else ''}.csv\"",
|
| 1429 |
-
"index_file = current_dir.parent / \"misc/mixtral_query_index.txt\"",
|
| 1430 |
-
"",
|
| 1431 |
-
"current_index = 0",
|
| 1432 |
-
"if index_file.exists():",
|
| 1433 |
-
" with open(index_file) as f:",
|
| 1434 |
-
" current_index = int(f.read().strip())",
|
| 1435 |
-
"",
|
| 1436 |
-
"for col in ['full_name', 'gender', 'profession_llm', 'country']:",
|
| 1437 |
-
" if col not in df.columns:",
|
| 1438 |
-
" df[col] = 'Unknown'",
|
| 1439 |
-
"",
|
| 1440 |
-
"print(f\"\\nAnnotating with MIXTRAL 8x22B - rows {current_index} to {len(df)}...\")",
|
| 1441 |
-
"",
|
| 1442 |
-
"try:",
|
| 1443 |
-
" for i in tqdm(range(current_index, len(df)), desc=\"Mixtral\"):",
|
| 1444 |
-
" row = df.iloc[i]",
|
| 1445 |
-
" ",
|
| 1446 |
-
" tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8) ",
|
| 1447 |
-
" if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]",
|
| 1448 |
-
" ",
|
| 1449 |
-
" prompt = create_prompt(",
|
| 1450 |
-
" row.get('real_name', row.get('name', '')),",
|
| 1451 |
-
" tags,",
|
| 1452 |
-
" row.get('likely_country', '')",
|
| 1453 |
-
" )",
|
| 1454 |
-
" ",
|
| 1455 |
-
" result = query_mixtral(prompt)",
|
| 1456 |
-
" ",
|
| 1457 |
-
" if result:",
|
| 1458 |
-
" df.at[i, 'full_name'] = result.get('full_name', 'Unknown')",
|
| 1459 |
-
" df.at[i, 'gender'] = result.get('gender', 'Unknown')",
|
| 1460 |
-
" profs = result.get('professions', [])",
|
| 1461 |
-
" df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)",
|
| 1462 |
-
" df.at[i, 'country'] = result.get('country', 'Unknown')",
|
| 1463 |
-
" ",
|
| 1464 |
-
" current_index = i + 1",
|
| 1465 |
-
" ",
|
| 1466 |
-
" if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):",
|
| 1467 |
-
" df.to_csv(output_file, index=False)",
|
| 1468 |
-
" with open(index_file, 'w') as f:",
|
| 1469 |
-
" f.write(str(current_index))",
|
| 1470 |
-
" print(f\"\u2705 Saved after {i+1} rows\")",
|
| 1471 |
-
" ",
|
| 1472 |
-
" time.sleep(0.5)",
|
| 1473 |
-
" ",
|
| 1474 |
-
" print(f\"\\n\u2705 Done! Results: {output_file}\")",
|
| 1475 |
-
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")",
|
| 1476 |
-
" ",
|
| 1477 |
-
"except Exception as e:",
|
| 1478 |
-
" print(f\"\u26a0\ufe0f Error: {e}\")",
|
| 1479 |
-
" df.to_csv(output_file, index=False)",
|
| 1480 |
-
" with open(index_file, 'w') as f:",
|
| 1481 |
-
" f.write(str(current_index))",
|
| 1482 |
-
""
|
| 1483 |
-
]
|
| 1484 |
},
|
| 1485 |
{
|
| 1486 |
"cell_type": "markdown",
|
|
@@ -1505,165 +1027,7 @@
|
|
| 1505 |
"id": "gemma_code",
|
| 1506 |
"metadata": {},
|
| 1507 |
"outputs": [],
|
| 1508 |
-
"source": [
|
| 1509 |
-
"import pandas as pd",
|
| 1510 |
-
"import json",
|
| 1511 |
-
"import time",
|
| 1512 |
-
"import requests",
|
| 1513 |
-
"import re",
|
| 1514 |
-
"from pathlib import Path",
|
| 1515 |
-
"from tqdm import tqdm",
|
| 1516 |
-
"",
|
| 1517 |
-
"current_dir = Path.cwd()",
|
| 1518 |
-
"input_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"",
|
| 1519 |
-
"api_key_file = current_dir.parent / \"misc/credentials/together_api_key.txt\"",
|
| 1520 |
-
"",
|
| 1521 |
-
"# === CONFIGURATION ===",
|
| 1522 |
-
"TEST_MODE = True",
|
| 1523 |
-
"TEST_SIZE = 10",
|
| 1524 |
-
"MAX_ROWS = 20000",
|
| 1525 |
-
"SAVE_INTERVAL = 10",
|
| 1526 |
-
"",
|
| 1527 |
-
"PROFESSION_CATEGORIES = [",
|
| 1528 |
-
" \"actor\", \"adult performer\", \"singer/musician\", \"model\",",
|
| 1529 |
-
" \"online personality\", \"public figure\", \"voice actor/ASMR\",",
|
| 1530 |
-
" \"sports professional\", \"tv personality\"",
|
| 1531 |
-
"]",
|
| 1532 |
-
"",
|
| 1533 |
-
"# === LOAD API KEY ===",
|
| 1534 |
-
"try:",
|
| 1535 |
-
" with open(api_key_file) as f:",
|
| 1536 |
-
" api_key = f.read().strip()",
|
| 1537 |
-
" print(\"\u2705 Gemma API key loaded\")",
|
| 1538 |
-
"except FileNotFoundError:",
|
| 1539 |
-
" print(\"\u274c Error: together_api_key.txt not found\")",
|
| 1540 |
-
" raise",
|
| 1541 |
-
"",
|
| 1542 |
-
"# === LOAD DATA ===",
|
| 1543 |
-
"df = pd.read_csv(input_file)",
|
| 1544 |
-
"print(f\"Loaded {len(df)} rows\")",
|
| 1545 |
-
"",
|
| 1546 |
-
"if TEST_MODE:",
|
| 1547 |
-
" print(f\"Running in TEST MODE with {TEST_SIZE} samples\")",
|
| 1548 |
-
" df = df.head(TEST_SIZE).copy()",
|
| 1549 |
-
"elif MAX_ROWS:",
|
| 1550 |
-
" df = df.head(MAX_ROWS).copy()",
|
| 1551 |
-
"",
|
| 1552 |
-
"# === CREATE PROMPT ===",
|
| 1553 |
-
"def create_prompt(name: str, tags: list, country: str) -> str:",
|
| 1554 |
-
" tags_str = \", \".join(tags[:5]) if tags else \"none\"",
|
| 1555 |
-
" country_str = country if country else \"unknown\"",
|
| 1556 |
-
" ",
|
| 1557 |
-
" return f\"\"\"You are an expert at identifying public figures.",
|
| 1558 |
-
"",
|
| 1559 |
-
"Given: Name: {name}, Tags: {tags_str}, Country: {country_str}",
|
| 1560 |
-
"",
|
| 1561 |
-
"Provide in JSON format:",
|
| 1562 |
-
"{{",
|
| 1563 |
-
" \"full_name\": \"<full name>\",",
|
| 1564 |
-
" \"gender\": \"<Male/Female/Other/Unknown>\",",
|
| 1565 |
-
" \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],",
|
| 1566 |
-
" \"country\": \"<country>\"",
|
| 1567 |
-
"}}",
|
| 1568 |
-
"",
|
| 1569 |
-
"Choose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}",
|
| 1570 |
-
"- Max 3 professions, ordered by relevance",
|
| 1571 |
-
"- \"online personality\" includes streamers, cosplayers, influencers",
|
| 1572 |
-
"- Return \"Unknown\" if uncertain",
|
| 1573 |
-
"",
|
| 1574 |
-
"Return ONLY JSON, no extra text.\"\"\"",
|
| 1575 |
-
"",
|
| 1576 |
-
"# === QUERY GEMMA ===",
|
| 1577 |
-
"def query_gemma(prompt: str) -> dict:",
|
| 1578 |
-
" url = \"https://api.together.xyz/v1/chat/completions\"",
|
| 1579 |
-
" ",
|
| 1580 |
-
" headers = {",
|
| 1581 |
-
" \"Authorization\": f\"Bearer {api_key}\",",
|
| 1582 |
-
" \"Content-Type\": \"application/json\"",
|
| 1583 |
-
" }",
|
| 1584 |
-
" ",
|
| 1585 |
-
" data = {",
|
| 1586 |
-
" \"model\": \"google/gemma-2-27b-it\",",
|
| 1587 |
-
" \"messages\": [{\"role\": \"user\", \"content\": prompt}],",
|
| 1588 |
-
" \"temperature\": 0.1,",
|
| 1589 |
-
" \"max_tokens\": 500",
|
| 1590 |
-
" }",
|
| 1591 |
-
" ",
|
| 1592 |
-
" for attempt in range(3):",
|
| 1593 |
-
" try:",
|
| 1594 |
-
" response = requests.post(url, headers=headers, json=data, timeout=30)",
|
| 1595 |
-
" response.raise_for_status()",
|
| 1596 |
-
" result = response.json()",
|
| 1597 |
-
" ",
|
| 1598 |
-
" if 'choices' in result:",
|
| 1599 |
-
" content = result['choices'][0]['message']['content']",
|
| 1600 |
-
" json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)",
|
| 1601 |
-
" if json_match:",
|
| 1602 |
-
" return json.loads(json_match.group())",
|
| 1603 |
-
" return None",
|
| 1604 |
-
" except Exception as e:",
|
| 1605 |
-
" print(f\"Gemma error (attempt {attempt+1}): {e}\")",
|
| 1606 |
-
" if attempt < 2:",
|
| 1607 |
-
" time.sleep(2 ** attempt)",
|
| 1608 |
-
" return None",
|
| 1609 |
-
"",
|
| 1610 |
-
"# === PROCESS ===",
|
| 1611 |
-
"output_file = current_dir.parent / f\"data/CSV/gemma_annotated_POI{'_test' if TEST_MODE else ''}.csv\"",
|
| 1612 |
-
"index_file = current_dir.parent / \"misc/gemma_query_index.txt\"",
|
| 1613 |
-
"",
|
| 1614 |
-
"current_index = 0",
|
| 1615 |
-
"if index_file.exists():",
|
| 1616 |
-
" with open(index_file) as f:",
|
| 1617 |
-
" current_index = int(f.read().strip())",
|
| 1618 |
-
"",
|
| 1619 |
-
"for col in ['full_name', 'gender', 'profession_llm', 'country']:",
|
| 1620 |
-
" if col not in df.columns:",
|
| 1621 |
-
" df[col] = 'Unknown'",
|
| 1622 |
-
"",
|
| 1623 |
-
"print(f\"\\nAnnotating with GEMMA 2 27B (Google) - rows {current_index} to {len(df)}...\")",
|
| 1624 |
-
"",
|
| 1625 |
-
"try:",
|
| 1626 |
-
" for i in tqdm(range(current_index, len(df)), desc=\"Gemma\"):",
|
| 1627 |
-
" row = df.iloc[i]",
|
| 1628 |
-
" ",
|
| 1629 |
-
" tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8) ",
|
| 1630 |
-
" if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]",
|
| 1631 |
-
" ",
|
| 1632 |
-
" prompt = create_prompt(",
|
| 1633 |
-
" row.get('real_name', row.get('name', '')),",
|
| 1634 |
-
" tags,",
|
| 1635 |
-
" row.get('likely_country', '')",
|
| 1636 |
-
" )",
|
| 1637 |
-
" ",
|
| 1638 |
-
" result = query_gemma(prompt)",
|
| 1639 |
-
" ",
|
| 1640 |
-
" if result:",
|
| 1641 |
-
" df.at[i, 'full_name'] = result.get('full_name', 'Unknown')",
|
| 1642 |
-
" df.at[i, 'gender'] = result.get('gender', 'Unknown')",
|
| 1643 |
-
" profs = result.get('professions', [])",
|
| 1644 |
-
" df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)",
|
| 1645 |
-
" df.at[i, 'country'] = result.get('country', 'Unknown')",
|
| 1646 |
-
" ",
|
| 1647 |
-
" current_index = i + 1",
|
| 1648 |
-
" ",
|
| 1649 |
-
" if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):",
|
| 1650 |
-
" df.to_csv(output_file, index=False)",
|
| 1651 |
-
" with open(index_file, 'w') as f:",
|
| 1652 |
-
" f.write(str(current_index))",
|
| 1653 |
-
" print(f\"\u2705 Saved after {i+1} rows\")",
|
| 1654 |
-
" ",
|
| 1655 |
-
" time.sleep(0.5)",
|
| 1656 |
-
" ",
|
| 1657 |
-
" print(f\"\\n\u2705 Done! Results: {output_file}\")",
|
| 1658 |
-
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")",
|
| 1659 |
-
" ",
|
| 1660 |
-
"except Exception as e:",
|
| 1661 |
-
" print(f\"\u26a0\ufe0f Error: {e}\")",
|
| 1662 |
-
" df.to_csv(output_file, index=False)",
|
| 1663 |
-
" with open(index_file, 'w') as f:",
|
| 1664 |
-
" f.write(str(current_index))",
|
| 1665 |
-
""
|
| 1666 |
-
]
|
| 1667 |
},
|
| 1668 |
{
|
| 1669 |
"cell_type": "markdown",
|
|
@@ -1694,11 +1058,11 @@
|
|
| 1694 |
"```\n",
|
| 1695 |
"\n",
|
| 1696 |
"**Advantages:**\n",
|
| 1697 |
-
"-
|
| 1698 |
-
"-
|
| 1699 |
-
"-
|
| 1700 |
-
"-
|
| 1701 |
-
"-
|
| 1702 |
"\n",
|
| 1703 |
"**Performance:**\n",
|
| 1704 |
"- Speed: ~5-10 tokens/sec on A100\n",
|
|
@@ -1751,25 +1115,25 @@
|
|
| 1751 |
" )\n",
|
| 1752 |
" \n",
|
| 1753 |
" if result.returncode == 0:\n",
|
| 1754 |
-
" print(\"
|
| 1755 |
" \n",
|
| 1756 |
" # Check if model is available\n",
|
| 1757 |
" if MODEL_NAME in result.stdout or \"qwen2.5\" in result.stdout:\n",
|
| 1758 |
-
" print(f\"
|
| 1759 |
" return True\n",
|
| 1760 |
" else:\n",
|
| 1761 |
-
" print(f\"
|
| 1762 |
" print(f\" Run: ollama pull {MODEL_NAME}\")\n",
|
| 1763 |
" return False\n",
|
| 1764 |
" else:\n",
|
| 1765 |
-
" print(\"
|
| 1766 |
" return False\n",
|
| 1767 |
" except FileNotFoundError:\n",
|
| 1768 |
-
" print(\"
|
| 1769 |
" print(\" Install: curl -fsSL https://ollama.com/install.sh | sh\")\n",
|
| 1770 |
" return False\n",
|
| 1771 |
" except Exception as e:\n",
|
| 1772 |
-
" print(f\"
|
| 1773 |
" return False\n",
|
| 1774 |
"\n",
|
| 1775 |
"# Check Ollama before proceeding\n",
|
|
@@ -1908,24 +1272,24 @@
|
|
| 1908 |
" samples_done = i + 1 - (current_index - (i + 1))\n",
|
| 1909 |
" samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
|
| 1910 |
" \n",
|
| 1911 |
-
" print(f\"
|
| 1912 |
" \n",
|
| 1913 |
" elapsed_total = time.time() - start_time\n",
|
| 1914 |
-
" print(f\"\\n
|
| 1915 |
" print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
|
| 1916 |
" print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
|
| 1917 |
" \n",
|
| 1918 |
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
|
| 1919 |
"\n",
|
| 1920 |
"except KeyboardInterrupt:\n",
|
| 1921 |
-
" print(f\"\\n
|
| 1922 |
" df.to_csv(output_file, index=False)\n",
|
| 1923 |
" with open(index_file, 'w') as f:\n",
|
| 1924 |
" f.write(str(current_index))\n",
|
| 1925 |
" print(f\"Progress saved up to row {current_index}\")\n",
|
| 1926 |
"\n",
|
| 1927 |
"except Exception as e:\n",
|
| 1928 |
-
" print(f\"
|
| 1929 |
" df.to_csv(output_file, index=False)\n",
|
| 1930 |
" with open(index_file, 'w') as f:\n",
|
| 1931 |
" f.write(str(current_index))\n",
|
|
|
|
| 142 |
"name": "stdout",
|
| 143 |
"output_type": "stream",
|
| 144 |
"text": [
|
| 145 |
+
"β
spaCy model loaded: en_core_web_sm\n",
|
| 146 |
"Loaded 18 rows\n",
|
| 147 |
"\n",
|
| 148 |
+
"π Processing names with spaCy NER...\n",
|
| 149 |
"\n",
|
| 150 |
+
"π Name cleaning examples (with spaCy NER):\n",
|
| 151 |
"====================================================================================================\n",
|
| 152 |
"Original Name | Cleaned Name \n",
|
| 153 |
"====================================================================================================\n",
|
| 154 |
"Super Pose Book Vol.1 - ControlNet | Super Pose Book \n",
|
| 155 |
"Liyuu LoRA | Liyuu \n",
|
| 156 |
+
"HashimotoKanna/ ζ©ζ¬η°ε₯ _JP_Actress | HashimotoKanna \n",
|
| 157 |
"Emma Watson (JG) | Emma Watson \n",
|
| 158 |
+
"Gal GadotγLoRaγ | Gal Gadot \n",
|
| 159 |
+
"Scarlett JohanssonγLoRaγ | Scarlett Johansson \n",
|
| 160 |
+
"Gakki | Aragaki Yui | ζ°ε£η΅θ‘£ | Gakki \n",
|
| 161 |
+
"Actress Satomi_η³εββ | Actress Satomi \n",
|
| 162 |
"Game of Thrones Cast | Game Thrones Cast \n",
|
| 163 |
+
"Natalie PortmanγLoRaγ | Natalie Portman \n",
|
| 164 |
"Emma Watson LoRA | Emma Watson \n",
|
| 165 |
"====================================================================================================\n",
|
| 166 |
"\n",
|
| 167 |
+
"π§ͺ Leetspeak translation examples:\n",
|
| 168 |
" 4kira LoRA -> akira\n",
|
| 169 |
" 3mma Watson v2 -> Watson\n",
|
| 170 |
" 1rene LORA -> irene\n",
|
| 171 |
" L3vi Ackerman -> Levi Ackerman\n",
|
| 172 |
"\n",
|
| 173 |
+
"π Statistics:\n",
|
| 174 |
" Total rows: 18\n",
|
| 175 |
" Non-empty names: 18\n",
|
| 176 |
" Empty names: 0\n",
|
| 177 |
"\n",
|
| 178 |
+
"π― Sample spaCy NER results:\n",
|
| 179 |
" 1. IU\n",
|
| 180 |
" 2. Super Pose Book\n",
|
| 181 |
" 3. Liyuu\n",
|
|
|
|
| 187 |
" 9. Emma Watson\n",
|
| 188 |
" 10. Gal Gadot\n",
|
| 189 |
"\n",
|
| 190 |
+
"β
Cleaned 18 names using spaCy NER\n",
|
| 191 |
+
"πΎ Saved to /home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/data/CSV/NER_POI_step01_pre_annotation.csv\n"
|
| 192 |
]
|
| 193 |
}
|
| 194 |
],
|
|
|
|
| 203 |
"# You may need to download it first: python -m spacy download en_core_web_sm\n",
|
| 204 |
"try:\n",
|
| 205 |
" nlp = spacy.load(\"en_core_web_sm\")\n",
|
| 206 |
+
" print(\"β
spaCy model loaded: en_core_web_sm\")\n",
|
| 207 |
"except OSError:\n",
|
| 208 |
+
" print(\"β spaCy model not found. Downloading...\")\n",
|
| 209 |
" import subprocess\n",
|
| 210 |
" subprocess.run([\"python\", \"-m\", \"spacy\", \"download\", \"en_core_web_sm\"])\n",
|
| 211 |
" nlp = spacy.load(\"en_core_web_sm\")\n",
|
| 212 |
+
" print(\"β
spaCy model downloaded and loaded\")\n",
|
| 213 |
"\n",
|
| 214 |
"# Set up paths\n",
|
| 215 |
"current_dir = Path.cwd()\n",
|
|
|
|
| 282 |
" name = re.sub(r'\\([^)]*\\)', '', name)\n",
|
| 283 |
" name = re.sub(r'\\[[^\\]]*\\]', '', name)\n",
|
| 284 |
" \n",
|
| 285 |
+
" # Remove special characters like γγ\n",
|
| 286 |
+
" name = re.sub(r'[γγγγγγγγγγ]', '', name)\n",
|
| 287 |
" \n",
|
| 288 |
" # Handle pipe - keep first part\n",
|
| 289 |
" if '|' in name:\n",
|
|
|
|
| 339 |
" Complete name cleaning pipeline with spaCy NER.\n",
|
| 340 |
" \n",
|
| 341 |
" Pipeline:\n",
|
| 342 |
+
" 1. Translate leetspeak (4βa, 3βe, 1βi, etc.)\n",
|
| 343 |
" 2. Remove noise (emoji, version tags, LoRA terms)\n",
|
| 344 |
" 3. Use spaCy to extract PERSON entities\n",
|
| 345 |
" 4. Fallback to capitalized words or cleaned text\n",
|
|
|
|
| 356 |
" return person_name\n",
|
| 357 |
"\n",
|
| 358 |
"# Apply name cleaning with spaCy\n",
|
| 359 |
+
"print(\"\\nπ Processing names with spaCy NER...\")\n",
|
| 360 |
"df['real_name'] = df['name'].apply(clean_name_with_spacy)\n",
|
| 361 |
"\n",
|
| 362 |
"# Show examples with detailed comparison\n",
|
| 363 |
+
"print(\"\\nπ Name cleaning examples (with spaCy NER):\")\n",
|
| 364 |
"print(\"=\" * 100)\n",
|
| 365 |
"print(f\"{'Original Name':<50} | {'Cleaned Name':<30}\")\n",
|
| 366 |
"print(\"=\" * 100)\n",
|
|
|
|
| 375 |
"print(\"=\" * 100)\n",
|
| 376 |
"\n",
|
| 377 |
"# Show specific test cases\n",
|
| 378 |
+
"print(\"\\nπ§ͺ Leetspeak translation examples:\")\n",
|
| 379 |
"test_names = ['4kira LoRA', '3mma Watson v2', '1rene LORA', 'L3vi Ackerman']\n",
|
| 380 |
"for test in test_names:\n",
|
| 381 |
" result = clean_name_with_spacy(test)\n",
|
| 382 |
" print(f\" {test:<30} -> {result}\")\n",
|
| 383 |
"\n",
|
| 384 |
"# Statistics\n",
|
| 385 |
+
"print(f\"\\nπ Statistics:\")\n",
|
| 386 |
"print(f\" Total rows: {len(df)}\")\n",
|
| 387 |
"print(f\" Non-empty names: {(df['real_name'] != '').sum()}\")\n",
|
| 388 |
"print(f\" Empty names: {(df['real_name'] == '').sum()}\")\n",
|
| 389 |
"\n",
|
| 390 |
"# Show some examples of what spaCy identified\n",
|
| 391 |
+
"print(\"\\nπ― Sample spaCy NER results:\")\n",
|
| 392 |
"sample_names = df['real_name'].head(20).tolist()\n",
|
| 393 |
"for i, name in enumerate(sample_names[:10], 1):\n",
|
| 394 |
" if name:\n",
|
| 395 |
" print(f\" {i}. {name}\")\n",
|
| 396 |
"\n",
|
| 397 |
+
"print(f\"\\nβ
Cleaned {len(df)} names using spaCy NER\")\n",
|
| 398 |
"\n",
|
| 399 |
"# Save intermediate result\n",
|
| 400 |
"output_step1 = current_dir.parent / \"data/CSV/NER_POI_step01_pre_annotation.csv\"\n",
|
| 401 |
"df.to_csv(output_step1, index=False)\n",
|
| 402 |
+
"print(f\"πΎ Saved to {output_step1}\")\n"
|
| 403 |
]
|
| 404 |
},
|
| 405 |
{
|
|
|
|
| 444 |
"8 Emma Watson actor\n",
|
| 445 |
"9 Gal Gadot model\n",
|
| 446 |
"\n",
|
| 447 |
+
"π Checking 'Irene' entries:\n",
|
| 448 |
" Name: Irene\n",
|
| 449 |
" Tags: ['girl', 'photorealistic', 'asian', 'woman', 'beautiful', 'celebrity', 'korean']\n",
|
| 450 |
" Country: \n",
|
|
|
|
| 485 |
"\n",
|
| 486 |
"poi_df[\"tags\"] = poi_df.apply(combine_tags, axis=1)\n",
|
| 487 |
"\n",
|
| 488 |
+
"# Step 2: Build tag β (country, nationality) mapping with PRIORITIES\n",
|
| 489 |
"tag_to_country_nationality = {}\n",
|
| 490 |
"# We'll use a priority score: direct country name = 3, nationality = 2, word parts = 1\n",
|
| 491 |
"\n",
|
|
|
|
| 563 |
"\n",
|
| 564 |
"poi_df[[\"likely_country\", \"likely_nationality\"]] = poi_df[\"tags\"].apply(infer_country_and_nationality)\n",
|
| 565 |
"\n",
|
| 566 |
+
"# Step 4: Build tag β profession mapping\n",
|
| 567 |
"profession_alias_map = {}\n",
|
| 568 |
"\n",
|
| 569 |
"for _, row in professions_df.iterrows():\n",
|
|
|
|
| 611 |
"# Check specific case: Irene with korean tag\n",
|
| 612 |
"irene_rows = poi_df[poi_df['real_name'].str.contains('irene', case=False, na=False)]\n",
|
| 613 |
"if len(irene_rows) > 0:\n",
|
| 614 |
+
" print(f\"\\nπ Checking 'Irene' entries:\")\n",
|
| 615 |
" for idx, row in irene_rows.iterrows():\n",
|
| 616 |
" print(f\" Name: {row['real_name']}\")\n",
|
| 617 |
" print(f\" Tags: {row['tags']}\")\n",
|
|
|
|
| 652 |
"name": "stdout",
|
| 653 |
"output_type": "stream",
|
| 654 |
"text": [
|
| 655 |
+
"β Error: deepseek_api_key.txt not found in misc/credentials/\n",
|
| 656 |
" Please create this file with your API key\n"
|
| 657 |
]
|
| 658 |
},
|
|
|
|
| 663 |
"traceback": [
|
| 664 |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 665 |
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
|
| 666 |
+
"Cell \u001b[0;32mIn[10], line 37\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[38;5;66;03m# === LOAD API KEY ===\u001b[39;00m\n\u001b[1;32m 36\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 37\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mapi_key_file\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[1;32m 38\u001b[0m api_key \u001b[38;5;241m=\u001b[39m f\u001b[38;5;241m.\u001b[39mread()\u001b[38;5;241m.\u001b[39mstrip()\n\u001b[1;32m 39\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mβ
Deepseek API key loaded\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
|
| 667 |
"File \u001b[0;32m~/.local/lib/python3.10/site-packages/IPython/core/interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[0;34m(file, *args, **kwargs)\u001b[0m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[1;32m 318\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 319\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 320\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 322\u001b[0m )\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mio_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 668 |
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/home/lauhp/000_PHD/000_010_PUBLICATION/CODE/pm-paper/misc/credentials/deepseek_api_key.txt'"
|
| 669 |
]
|
|
|
|
| 708 |
"try:\n",
|
| 709 |
" with open(api_key_file) as f:\n",
|
| 710 |
" api_key = f.read().strip()\n",
|
| 711 |
+
" print(\"β
Deepseek API key loaded\")\n",
|
| 712 |
"except FileNotFoundError:\n",
|
| 713 |
+
" print(\"β Error: deepseek_api_key.txt not found in misc/credentials/\")\n",
|
| 714 |
" print(\" Please create this file with your API key\")\n",
|
| 715 |
" raise\n",
|
| 716 |
"\n",
|
|
|
|
| 726 |
"# Load profession categories and keywords\n",
|
| 727 |
"try:\n",
|
| 728 |
" prof_mapped_df = pd.read_csv(professions_mapped_file)\n",
|
| 729 |
+
" print(f\"β
Loaded profession mapping with {len(prof_mapped_df)} categories\")\n",
|
| 730 |
"except:\n",
|
| 731 |
+
" print(\"β οΈ Warning: professions_mapped.csv not found, using default categories\")\n",
|
| 732 |
"\n",
|
| 733 |
"profession_str = \", \".join(PROFESSION_CATEGORIES)\n",
|
| 734 |
"\n",
|
|
|
|
| 895 |
" df.to_csv(output_file, index=False)\n",
|
| 896 |
" with open(index_file, 'w') as f:\n",
|
| 897 |
" f.write(str(current_index))\n",
|
| 898 |
+
" print(f\"β
Progress saved after {i+1} rows\")\n",
|
| 899 |
" \n",
|
| 900 |
" time.sleep(1) # Rate limiting\n",
|
| 901 |
" \n",
|
| 902 |
+
" print(f\"\\nβ
Done! Final results saved to {output_file}\")\n",
|
| 903 |
" \n",
|
| 904 |
" # Summary statistics\n",
|
| 905 |
" print(\"\\n=== Summary Statistics ===\")\n",
|
|
|
|
| 917 |
" print(df[display_cols].head(10).to_string(index=False))\n",
|
| 918 |
"\n",
|
| 919 |
"except Exception as e:\n",
|
| 920 |
+
" print(f\"β οΈ Error encountered: {e}\")\n",
|
| 921 |
+
" print(f\"β οΈ Last processed index: {current_index}\")\n",
|
| 922 |
" \n",
|
| 923 |
" # Save progress before exiting\n",
|
| 924 |
" df.to_csv(output_file, index=False)\n",
|
| 925 |
" with open(index_file, 'w') as f:\n",
|
| 926 |
" f.write(str(current_index))\n",
|
| 927 |
" \n",
|
| 928 |
+
" print(f\"β οΈ Progress saved up to row {current_index}\")\n"
|
| 929 |
]
|
| 930 |
},
|
| 931 |
{
|
|
|
|
| 954 |
"id": "qwen_code",
|
| 955 |
"metadata": {},
|
| 956 |
"outputs": [],
|
| 957 |
+
"source": "import pandas as pd\nimport json\nimport time\nimport re\nfrom pathlib import Path\nfrom tqdm import tqdm\nfrom openai import OpenAI\n\ncurrent_dir = Path.cwd()\ninput_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\napi_key_file = current_dir.parent / \"misc/credentials/qwen_api_key.txt\"\n\n# === CONFIGURATION ===\nTEST_MODE = True\nTEST_SIZE = 10\nMAX_ROWS = 20000\nSAVE_INTERVAL = 10\n\nPROFESSION_CATEGORIES = [\n \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n \"online personality\", \"public figure\", \"voice actor/ASMR\",\n \"sports professional\", \"tv personality\"\n]\n\n# === LOAD API KEY ===\ntry:\n with open(api_key_file) as f:\n api_key = f.read().strip()\n print(\"β
Qwen API key loaded\")\n print(f\" Key starts with: {api_key[:10]}...\")\nexcept FileNotFoundError:\n print(\"β Error: qwen_api_key.txt not found\")\n raise\n\n# Initialize OpenAI client for Qwen (matching dashboard example)\nclient = OpenAI(\n api_key=api_key,\n base_url=\"https://dashscope-intl.aliyuncs.com/compatible-mode/v1\"\n)\n\n# === LOAD DATA ===\ndf = pd.read_csv(input_file)\nprint(f\"Loaded {len(df)} rows\")\n\nif TEST_MODE:\n print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n df = df.head(TEST_SIZE).copy()\nelif MAX_ROWS:\n df = df.head(MAX_ROWS).copy()\n\n# === CREATE PROMPT ===\ndef create_prompt(name: str, tags: list, country: str) -> str:\n tags_str = \", \".join(tags[:5]) if tags else \"none\"\n country_str = country if country else \"unknown\"\n \n return f\"\"\"You are an expert at identifying public figures.\n\nGiven: Name: {name}, Tags: {tags_str}, Country: {country_str}\n\nProvide in JSON format:\n{{\n \"full_name\": \"<full name>\",\n \"gender\": \"<Male/Female/Other/Unknown>\",\n \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n \"country\": \"<country>\"\n}}\n\nChoose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n- Max 3 professions, ordered by relevance\n- \"online personality\" includes streamers, cosplayers, influencers\n- Return \"Unknown\" if uncertain\n\nReturn ONLY JSON, no extra text.\"\"\"\n\n# === QUERY QWEN ===\ndef query_qwen(prompt: str) -> dict:\n \"\"\"Query Qwen using OpenAI-compatible API (matching dashboard example).\"\"\"\n for attempt in range(3):\n try:\n completion = client.chat.completions.create(\n model=\"qwen-max\", # Note: dashboard shows \"qwen3-max\" but \"qwen-max\" works too\n messages=[\n {\"role\": \"user\", \"content\": prompt}\n ],\n temperature=0.1,\n max_tokens=500,\n stream=False # Disable streaming for easier parsing\n )\n \n content = completion.choices[0].message.content\n \n # Parse JSON from response\n json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)\n if json_match:\n return json.loads(json_match.group())\n \n return None\n \n except Exception as e:\n print(f\"Qwen error (attempt {attempt+1}): {e}\")\n if attempt < 2:\n time.sleep(2 ** attempt)\n \n return None\n\n# === PROCESS ===\noutput_file = current_dir.parent / f\"data/CSV/qwen_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\nindex_file = current_dir.parent / \"misc/qwen_query_index.txt\"\n\ncurrent_index = 0\nif index_file.exists():\n with open(index_file) as f:\n current_index = int(f.read().strip())\n\nfor col in ['full_name', 'gender', 'profession_llm', 'country']:\n if col not in df.columns:\n df[col] = 'Unknown'\n\nprint(f\"\\nAnnotating with QWEN-MAX (OpenAI-compatible API) - rows {current_index} to {len(df)}...\")\n\ntry:\n for i in tqdm(range(current_index, len(df)), desc=\"Qwen\"):\n row = df.iloc[i]\n \n tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n \n prompt = create_prompt(\n row.get('real_name', row.get('name', '')),\n tags,\n row.get('likely_country', '')\n )\n \n result = query_qwen(prompt)\n \n if result:\n df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n df.at[i, 'gender'] = result.get('gender', 'Unknown')\n profs = result.get('professions', [])\n df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n df.at[i, 'country'] = result.get('country', 'Unknown')\n \n current_index = i + 1\n \n if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"β
Saved after {i+1} rows\")\n \n time.sleep(0.5)\n \n print(f\"\\nβ
Done! Results: {output_file}\")\n print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n \nexcept Exception as e:\n print(f\"β οΈ Error: {e}\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 958 |
},
|
| 959 |
{
|
| 960 |
"cell_type": "markdown",
|
|
|
|
| 978 |
"id": "llama_code",
|
| 979 |
"metadata": {},
|
| 980 |
"outputs": [],
|
| 981 |
+
"source": "import pandas as pd\nimport json\nimport time\nimport requests\nimport re\nfrom pathlib import Path\nfrom tqdm import tqdm\n\ncurrent_dir = Path.cwd()\ninput_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\napi_key_file = current_dir.parent / \"misc/credentials/together_api_key.txt\"\n\n# === CONFIGURATION ===\nTEST_MODE = True\nTEST_SIZE = 10\nMAX_ROWS = 20000\nSAVE_INTERVAL = 10\n\nPROFESSION_CATEGORIES = [\n \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n \"online personality\", \"public figure\", \"voice actor/ASMR\",\n \"sports professional\", \"tv personality\"\n]\n\n# === LOAD API KEY ===\ntry:\n with open(api_key_file) as f:\n api_key = f.read().strip()\n print(\"β
Llama API key loaded\")\nexcept FileNotFoundError:\n print(\"β Error: together_api_key.txt not found\")\n raise\n\n# === LOAD DATA ===\ndf = pd.read_csv(input_file)\nprint(f\"Loaded {len(df)} rows\")\n\nif TEST_MODE:\n print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n df = df.head(TEST_SIZE).copy()\nelif MAX_ROWS:\n df = df.head(MAX_ROWS).copy()\n\n# === CREATE PROMPT ===\ndef create_prompt(name: str, tags: list, country: str) -> str:\n tags_str = \", \".join(tags[:5]) if tags else \"none\"\n country_str = country if country else \"unknown\"\n \n return f\"\"\"You are an expert at identifying public figures.\n\nGiven: Name: {name}, Tags: {tags_str}, Country: {country_str}\n\nProvide in JSON format:\n{{\n \"full_name\": \"<full name>\",\n \"gender\": \"<Male/Female/Other/Unknown>\",\n \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n \"country\": \"<country>\"\n}}\n\nChoose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n- Max 3 professions, ordered by relevance\n- \"online personality\" includes streamers, cosplayers, influencers\n- Return \"Unknown\" if uncertain\n\nReturn ONLY JSON, no extra text.\"\"\"\n\n# === QUERY LLAMA ===\ndef query_llama(prompt: str) -> dict:\n url = \"https://api.together.xyz/v1/chat/completions\"\n \n headers = {\n \"Authorization\": f\"Bearer {api_key}\",\n \"Content-Type\": \"application/json\"\n }\n \n data = {\n \"model\": \"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo\",\n \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n \"temperature\": 0.1,\n \"max_tokens\": 500\n }\n \n for attempt in range(3):\n try:\n response = requests.post(url, headers=headers, json=data, timeout=30)\n response.raise_for_status()\n result = response.json()\n \n if 'choices' in result:\n content = result['choices'][0]['message']['content']\n json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)\n if json_match:\n return json.loads(json_match.group())\n return None\n except Exception as e:\n print(f\"Llama error (attempt {attempt+1}): {e}\")\n if attempt < 2:\n time.sleep(2 ** attempt)\n return None\n\n# === PROCESS ===\noutput_file = current_dir.parent / f\"data/CSV/llama_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\nindex_file = current_dir.parent / \"misc/llama_query_index.txt\"\n\ncurrent_index = 0\nif index_file.exists():\n with open(index_file) as f:\n current_index = int(f.read().strip())\n\nfor col in ['full_name', 'gender', 'profession_llm', 'country']:\n if col not in df.columns:\n df[col] = 'Unknown'\n\nprint(f\"\\nAnnotating with LLAMA 3.1 70B - rows {current_index} to {len(df)}...\")\n\ntry:\n for i in tqdm(range(current_index, len(df)), desc=\"Llama\"):\n row = df.iloc[i]\n \n tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n \n prompt = create_prompt(\n row.get('real_name', row.get('name', '')),\n tags,\n row.get('likely_country', '')\n )\n \n result = query_llama(prompt)\n \n if result:\n df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n df.at[i, 'gender'] = result.get('gender', 'Unknown')\n profs = result.get('professions', [])\n df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n df.at[i, 'country'] = result.get('country', 'Unknown')\n \n current_index = i + 1\n \n if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"β
Saved after {i+1} rows\")\n \n time.sleep(0.5)\n \n print(f\"\\nβ
Done! Results: {output_file}\")\n print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n \nexcept Exception as e:\n print(f\"β οΈ Error: {e}\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 982 |
},
|
| 983 |
{
|
| 984 |
"cell_type": "markdown",
|
|
|
|
| 1002 |
"id": "mixtral_code",
|
| 1003 |
"metadata": {},
|
| 1004 |
"outputs": [],
|
| 1005 |
+
"source": "import pandas as pd\nimport json\nimport time\nimport requests\nimport re\nfrom pathlib import Path\nfrom tqdm import tqdm\n\ncurrent_dir = Path.cwd()\ninput_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\napi_key_file = current_dir.parent / \"misc/credentials/mistral_api_key.txt\"\n\n# === CONFIGURATION ===\nTEST_MODE = True\nTEST_SIZE = 10\nMAX_ROWS = 20000\nSAVE_INTERVAL = 10\n\nPROFESSION_CATEGORIES = [\n \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n \"online personality\", \"public figure\", \"voice actor/ASMR\",\n \"sports professional\", \"tv personality\"\n]\n\n# === LOAD API KEY ===\ntry:\n with open(api_key_file) as f:\n api_key = f.read().strip()\n print(\"β
Mixtral API key loaded\")\nexcept FileNotFoundError:\n print(\"β Error: mistral_api_key.txt not found\")\n raise\n\n# === LOAD DATA ===\ndf = pd.read_csv(input_file)\nprint(f\"Loaded {len(df)} rows\")\n\nif TEST_MODE:\n print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n df = df.head(TEST_SIZE).copy()\nelif MAX_ROWS:\n df = df.head(MAX_ROWS).copy()\n\n# === CREATE PROMPT ===\ndef create_prompt(name: str, tags: list, country: str) -> str:\n tags_str = \", \".join(tags[:5]) if tags else \"none\"\n country_str = country if country else \"unknown\"\n \n return f\"\"\"You are an expert at identifying public figures.\n\nGiven: Name: {name}, Tags: {tags_str}, Country: {country_str}\n\nProvide in JSON format:\n{{\n \"full_name\": \"<full name>\",\n \"gender\": \"<Male/Female/Other/Unknown>\",\n \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n \"country\": \"<country>\"\n}}\n\nChoose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n- Max 3 professions, ordered by relevance\n- \"online personality\" includes streamers, cosplayers, influencers\n- Return \"Unknown\" if uncertain\n\nReturn ONLY JSON, no extra text.\"\"\"\n\n# === QUERY MIXTRAL ===\ndef query_mixtral(prompt: str) -> dict:\n url = \"https://api.mistral.ai/v1/chat/completions\"\n \n headers = {\n \"Authorization\": f\"Bearer {api_key}\",\n \"Content-Type\": \"application/json\"\n }\n \n data = {\n \"model\": \"open-mixtral-8x22b\",\n \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n \"temperature\": 0.1,\n \"max_tokens\": 500\n }\n \n for attempt in range(3):\n try:\n response = requests.post(url, headers=headers, json=data, timeout=30)\n response.raise_for_status()\n result = response.json()\n \n if 'choices' in result:\n content = result['choices'][0]['message']['content']\n json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)\n if json_match:\n return json.loads(json_match.group())\n return None\n except Exception as e:\n print(f\"Mixtral error (attempt {attempt+1}): {e}\")\n if attempt < 2:\n time.sleep(2 ** attempt)\n return None\n\n# === PROCESS ===\noutput_file = current_dir.parent / f\"data/CSV/mixtral_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\nindex_file = current_dir.parent / \"misc/mixtral_query_index.txt\"\n\ncurrent_index = 0\nif index_file.exists():\n with open(index_file) as f:\n current_index = int(f.read().strip())\n\nfor col in ['full_name', 'gender', 'profession_llm', 'country']:\n if col not in df.columns:\n df[col] = 'Unknown'\n\nprint(f\"\\nAnnotating with MIXTRAL 8x22B - rows {current_index} to {len(df)}...\")\n\ntry:\n for i in tqdm(range(current_index, len(df)), desc=\"Mixtral\"):\n row = df.iloc[i]\n \n tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n \n prompt = create_prompt(\n row.get('real_name', row.get('name', '')),\n tags,\n row.get('likely_country', '')\n )\n \n result = query_mixtral(prompt)\n \n if result:\n df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n df.at[i, 'gender'] = result.get('gender', 'Unknown')\n profs = result.get('professions', [])\n df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n df.at[i, 'country'] = result.get('country', 'Unknown')\n \n current_index = i + 1\n \n if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"β
Saved after {i+1} rows\")\n \n time.sleep(0.5)\n \n print(f\"\\nβ
Done! Results: {output_file}\")\n print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n \nexcept Exception as e:\n print(f\"β οΈ Error: {e}\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1006 |
},
|
| 1007 |
{
|
| 1008 |
"cell_type": "markdown",
|
|
|
|
| 1027 |
"id": "gemma_code",
|
| 1028 |
"metadata": {},
|
| 1029 |
"outputs": [],
|
| 1030 |
+
"source": "import pandas as pd\nimport json\nimport time\nimport requests\nimport re\nfrom pathlib import Path\nfrom tqdm import tqdm\n\ncurrent_dir = Path.cwd()\ninput_file = current_dir.parent / \"data/CSV/NER_POI_step02_annotated.csv\"\napi_key_file = current_dir.parent / \"misc/credentials/together_api_key.txt\"\n\n# === CONFIGURATION ===\nTEST_MODE = True\nTEST_SIZE = 10\nMAX_ROWS = 20000\nSAVE_INTERVAL = 10\n\nPROFESSION_CATEGORIES = [\n \"actor\", \"adult performer\", \"singer/musician\", \"model\",\n \"online personality\", \"public figure\", \"voice actor/ASMR\",\n \"sports professional\", \"tv personality\"\n]\n\n# === LOAD API KEY ===\ntry:\n with open(api_key_file) as f:\n api_key = f.read().strip()\n print(\"β
Gemma API key loaded\")\nexcept FileNotFoundError:\n print(\"β Error: together_api_key.txt not found\")\n raise\n\n# === LOAD DATA ===\ndf = pd.read_csv(input_file)\nprint(f\"Loaded {len(df)} rows\")\n\nif TEST_MODE:\n print(f\"Running in TEST MODE with {TEST_SIZE} samples\")\n df = df.head(TEST_SIZE).copy()\nelif MAX_ROWS:\n df = df.head(MAX_ROWS).copy()\n\n# === CREATE PROMPT ===\ndef create_prompt(name: str, tags: list, country: str) -> str:\n tags_str = \", \".join(tags[:5]) if tags else \"none\"\n country_str = country if country else \"unknown\"\n \n return f\"\"\"You are an expert at identifying public figures.\n\nGiven: Name: {name}, Tags: {tags_str}, Country: {country_str}\n\nProvide in JSON format:\n{{\n \"full_name\": \"<full name>\",\n \"gender\": \"<Male/Female/Other/Unknown>\",\n \"professions\": [\"<profession 1>\", \"<profession 2>\", \"<profession 3>\"],\n \"country\": \"<country>\"\n}}\n\nChoose professions ONLY from: {\", \".join(PROFESSION_CATEGORIES)}\n- Max 3 professions, ordered by relevance\n- \"online personality\" includes streamers, cosplayers, influencers\n- Return \"Unknown\" if uncertain\n\nReturn ONLY JSON, no extra text.\"\"\"\n\n# === QUERY GEMMA ===\ndef query_gemma(prompt: str) -> dict:\n url = \"https://api.together.xyz/v1/chat/completions\"\n \n headers = {\n \"Authorization\": f\"Bearer {api_key}\",\n \"Content-Type\": \"application/json\"\n }\n \n data = {\n \"model\": \"google/gemma-2-27b-it\",\n \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n \"temperature\": 0.1,\n \"max_tokens\": 500\n }\n \n for attempt in range(3):\n try:\n response = requests.post(url, headers=headers, json=data, timeout=30)\n response.raise_for_status()\n result = response.json()\n \n if 'choices' in result:\n content = result['choices'][0]['message']['content']\n json_match = re.search(r'\\{[^}]+\\}', content, re.DOTALL)\n if json_match:\n return json.loads(json_match.group())\n return None\n except Exception as e:\n print(f\"Gemma error (attempt {attempt+1}): {e}\")\n if attempt < 2:\n time.sleep(2 ** attempt)\n return None\n\n# === PROCESS ===\noutput_file = current_dir.parent / f\"data/CSV/gemma_annotated_POI{'_test' if TEST_MODE else ''}.csv\"\nindex_file = current_dir.parent / \"misc/gemma_query_index.txt\"\n\ncurrent_index = 0\nif index_file.exists():\n with open(index_file) as f:\n current_index = int(f.read().strip())\n\nfor col in ['full_name', 'gender', 'profession_llm', 'country']:\n if col not in df.columns:\n df[col] = 'Unknown'\n\nprint(f\"\\nAnnotating with GEMMA 2 27B (Google) - rows {current_index} to {len(df)}...\")\n\ntry:\n for i in tqdm(range(current_index, len(df)), desc=\"Gemma\"):\n row = df.iloc[i]\n \n tags = [str(row[f'tag_{j}']).lower() for j in range(1, 8)\n if f'tag_{j}' in row and pd.notna(row[f'tag_{j}'])]\n \n prompt = create_prompt(\n row.get('real_name', row.get('name', '')),\n tags,\n row.get('likely_country', '')\n )\n \n result = query_gemma(prompt)\n \n if result:\n df.at[i, 'full_name'] = result.get('full_name', 'Unknown')\n df.at[i, 'gender'] = result.get('gender', 'Unknown')\n profs = result.get('professions', [])\n df.at[i, 'profession_llm'] = \", \".join(profs[:3]) if isinstance(profs, list) else str(profs)\n df.at[i, 'country'] = result.get('country', 'Unknown')\n \n current_index = i + 1\n \n if (i + 1) % SAVE_INTERVAL == 0 or (i + 1) == len(df):\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))\n print(f\"β
Saved after {i+1} rows\")\n \n time.sleep(0.5)\n \n print(f\"\\nβ
Done! Results: {output_file}\")\n print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n \nexcept Exception as e:\n print(f\"β οΈ Error: {e}\")\n df.to_csv(output_file, index=False)\n with open(index_file, 'w') as f:\n f.write(str(current_index))"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1031 |
},
|
| 1032 |
{
|
| 1033 |
"cell_type": "markdown",
|
|
|
|
| 1058 |
"```\n",
|
| 1059 |
"\n",
|
| 1060 |
"**Advantages:**\n",
|
| 1061 |
+
"- β
FREE - No API costs\n",
|
| 1062 |
+
"- β
Fast - Local inference on A100\n",
|
| 1063 |
+
"- β
Privacy - Data never leaves your machine\n",
|
| 1064 |
+
"- β
Offline - Works without internet\n",
|
| 1065 |
+
"- β
High quality - 32B parameter model\n",
|
| 1066 |
"\n",
|
| 1067 |
"**Performance:**\n",
|
| 1068 |
"- Speed: ~5-10 tokens/sec on A100\n",
|
|
|
|
| 1115 |
" )\n",
|
| 1116 |
" \n",
|
| 1117 |
" if result.returncode == 0:\n",
|
| 1118 |
+
" print(\"β
Ollama is installed\")\n",
|
| 1119 |
" \n",
|
| 1120 |
" # Check if model is available\n",
|
| 1121 |
" if MODEL_NAME in result.stdout or \"qwen2.5\" in result.stdout:\n",
|
| 1122 |
+
" print(f\"β
Model {MODEL_NAME} is available\")\n",
|
| 1123 |
" return True\n",
|
| 1124 |
" else:\n",
|
| 1125 |
+
" print(f\"β οΈ Model {MODEL_NAME} not found\")\n",
|
| 1126 |
" print(f\" Run: ollama pull {MODEL_NAME}\")\n",
|
| 1127 |
" return False\n",
|
| 1128 |
" else:\n",
|
| 1129 |
+
" print(\"β Ollama command failed\")\n",
|
| 1130 |
" return False\n",
|
| 1131 |
" except FileNotFoundError:\n",
|
| 1132 |
+
" print(\"β Ollama not installed\")\n",
|
| 1133 |
" print(\" Install: curl -fsSL https://ollama.com/install.sh | sh\")\n",
|
| 1134 |
" return False\n",
|
| 1135 |
" except Exception as e:\n",
|
| 1136 |
+
" print(f\"β Error checking Ollama: {e}\")\n",
|
| 1137 |
" return False\n",
|
| 1138 |
"\n",
|
| 1139 |
"# Check Ollama before proceeding\n",
|
|
|
|
| 1272 |
" samples_done = i + 1 - (current_index - (i + 1))\n",
|
| 1273 |
" samples_per_hour = (samples_done / elapsed) * 3600 if elapsed > 0 else 0\n",
|
| 1274 |
" \n",
|
| 1275 |
+
" print(f\"β
Saved after {i+1} rows (~{samples_per_hour:.1f} samples/hour)\")\n",
|
| 1276 |
" \n",
|
| 1277 |
" elapsed_total = time.time() - start_time\n",
|
| 1278 |
+
" print(f\"\\nβ
Done! Results: {output_file}\")\n",
|
| 1279 |
" print(f\"Total time: {elapsed_total/60:.1f} minutes\")\n",
|
| 1280 |
" print(f\"Average speed: {len(df)/(elapsed_total/3600):.1f} samples/hour\")\n",
|
| 1281 |
" \n",
|
| 1282 |
" print(f\"\\nTop professions:\\n{df['profession_llm'].value_counts().head(10)}\")\n",
|
| 1283 |
"\n",
|
| 1284 |
"except KeyboardInterrupt:\n",
|
| 1285 |
+
" print(f\"\\nβ οΈ Interrupted by user\")\n",
|
| 1286 |
" df.to_csv(output_file, index=False)\n",
|
| 1287 |
" with open(index_file, 'w') as f:\n",
|
| 1288 |
" f.write(str(current_index))\n",
|
| 1289 |
" print(f\"Progress saved up to row {current_index}\")\n",
|
| 1290 |
"\n",
|
| 1291 |
"except Exception as e:\n",
|
| 1292 |
+
" print(f\"β οΈ Error: {e}\")\n",
|
| 1293 |
" df.to_csv(output_file, index=False)\n",
|
| 1294 |
" with open(index_file, 'w') as f:\n",
|
| 1295 |
" f.write(str(current_index))\n",
|