{"cells":[{"cell_type":"code","source":["import json\n","import random\n","import math\n","\n","# ------------------------------\n","# 1. Wczytanie danych treningowych\n","# ------------------------------\n","def load_email_data(spam_path, ham_path):\n","    with open(spam_path, encoding=\"utf-8\") as f1, open(ham_path, encoding=\"utf-8\") as f2:\n","        spam_data = json.load(f1)\n","        ham_data = json.load(f2)\n","    return spam_data + ham_data\n","\n","\n","def train_test_split(data, test_ratio=0.2):\n","    random.shuffle(data)\n","    cut = int(len(data) * (1 - test_ratio))\n","    return data[:cut], data[cut:]\n"],"metadata":{"id":"vOgNA2SVBlDA"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["\n","# ------------------------------\n","# 2. Trenowanie klasyfikatora Bayesa\n","# ------------------------------\n","def preprocess(text):\n","    return text.lower().replace(\"–\", \" \").replace(\"-\", \" \").replace(\",\", \" \")\\\n","        .replace(\".\", \" \").replace(\"!\", \" \").replace(\"?\", \" \").split()\n","\n","def train_naive_bayes(train_data, alpha=1.0):\n","    class_counts = {}\n","    word_counts = {}\n","    total_words = {}\n","\n","    for rec in train_data:\n","        label = rec[\"label\"]\n","        class_counts[label] = class_counts.get(label, 0) + 1\n","        word_counts.setdefault(label, {})\n","        total_words.setdefault(label, 0)\n","\n","        words = preprocess(rec[\"text\"])\n","        for word in words:\n","            word_counts[label][word] = word_counts[label].get(word, 0) + 1\n","            total_words[label] += 1\n","\n","    vocab = set()\n","    for wc in word_counts.values():\n","        vocab.update(wc.keys())\n","\n","    return {\n","        \"class_counts\": class_counts,\n","        \"word_counts\": word_counts,\n","        \"total_words\": total_words,\n","        \"vocab\": vocab,\n","        \"alpha\": alpha,\n","        \"total_docs\": len(train_data)\n","    }\n","\n"],"metadata":{"id":"Qhn3rY-HDD7B"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# ------------------------------\n","# 3. Klasyfikacja wiadomości\n","# ------------------------------\n","def log_prob(model, words, class_name):\n","    logp = math.log(model[\"class_counts\"][class_name] / model[\"total_docs\"])\n","    V = len(model[\"vocab\"])\n","    a = model[\"alpha\"]\n","    for word in words:\n","        wc = model[\"word_counts\"][class_name].get(word, 0)\n","        logp += math.log((wc + a) / (model[\"total_words\"][class_name] + a * V))\n","    return logp\n","\n","def predict(model, text):\n","    words = preprocess(text)\n","    best_class, best_log = None, -float(\"inf\")\n","    for c in model[\"class_counts\"]:\n","        lp = log_prob(model, words, c)\n","        if lp > best_log:\n","            best_class, best_log = c, lp\n","    return best_class\n","\n","def evaluate_model(model, test_data):\n","    correct = 0\n","    for rec in test_data:\n","        prediction = predict(model, rec[\"text\"])\n","        if prediction == rec[\"label\"]:\n","            correct += 1\n","    accuracy = correct / len(test_data)\n","    print(f\"Skuteczność na zbiorze testowym: {accuracy * 100:.2f}%\")\n","    return accuracy"],"metadata":{"id":"A-nSjvVJDI6V"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# ------------------------------\n","# 4. Główna funkcja\n","# ------------------------------\n","from pprint import pprint\n","\n","\n","def main():\n","    data = load_email_data(\"spam_emails.json\", \"ham_emails.json\")\n","\n","    train, test = train_test_split(data)\n","\n","\n","    model = train_naive_bayes(train)\n","\n","    #pprint(model)\n","\n","    evaluate_model(model, test)\n","\n","    while True:\n","        user_input = input(\"Wpisz wiadomość do klasyfikacji (lub 'exit' aby zakończyć):\\n> \")\n","        if user_input.lower() == \"exit\":\n","            print(\"Zakończono.\")\n","            break\n","        prediction = predict(model, user_input)\n","        print(f\"Klasyfikacja: {prediction.upper()}\")\n","\n","# ------------------------------\n","# 5. Uruchomienie\n","# ------------------------------\n","if __name__ == \"__main__\":\n","    main()"],"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":522},"id":"qOyG62y9DMi1","executionInfo":{"status":"error","timestamp":1747339387102,"user_tz":-120,"elapsed":773008,"user":{"displayName":"Łukasz Pawlowski","userId":"08418866654738771767"}},"outputId":"471be853-3475-4074-8af6-4e2c58a84228"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Skuteczność na zbiorze testowym: 85.71%\n","Wpisz wiadomość do klasyfikacji (lub 'exit' aby zakończyć):\n","> Weź udział w konkursie, 200zł czeka\n","Klasyfikacja: SPAM\n","Wpisz wiadomość do klasyfikacji (lub 'exit' aby zakończyć):\n","> Spotkajmy się jutro o 12\n","Klasyfikacja: HAM\n","Wpisz wiadomość do klasyfikacji (lub 'exit' aby zakończyć):\n","> Łatwa kasa, do 1000 zł bez ryzyka\n","Klasyfikacja: SPAM\n"]},{"output_type":"error","ename":"KeyboardInterrupt","evalue":"Interrupted by user","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)","\u001b[0;32m<ipython-input-8-9138d5a391a8>\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     29\u001b[0m \u001b[0;31m# ------------------------------\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     30\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"__main__\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m     \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;32m<ipython-input-8-9138d5a391a8>\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m     18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     19\u001b[0m     \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m         \u001b[0muser_input\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Wpisz wiadomość do klasyfikacji (lub 'exit' aby zakończyć):\\n> \"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     21\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0muser_input\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlower\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"exit\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     22\u001b[0m             \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Zakończono.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.11/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m   1175\u001b[0m                 \u001b[0;34m\"raw_input was called, but this frontend does not support input requests.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1176\u001b[0m             )\n\u001b[0;32m-> 1177\u001b[0;31m         return self._input_request(\n\u001b[0m\u001b[1;32m   1178\u001b[0m             \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprompt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1179\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"shell\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.11/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m   1217\u001b[0m             \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1218\u001b[0m                 \u001b[0;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1219\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Interrupted by user\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1220\u001b[0m             \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1221\u001b[0m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarning\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid Message:\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mexc_info\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user"]}]}],"metadata":{"colab":{"provenance":[{"file_id":"1SGFz8WH-PhdgXvSxpq4vrp5cZvwUaD6j","timestamp":1747814600491}]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}