{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Hämta temperatur från SMHI (enklare demo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import datetime\n",
    "\n",
    "# Koordinater (Halmstad)\n",
    "lat = 56.6745\n",
    "lon = 12.8570\n",
    "\n",
    "url = f\"https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/{lon}/lat/{lat}/data.json\"\n",
    "\n",
    "response = requests.get(url)\n",
    "\n",
    "if response.status_code == 200:\n",
    "    data = response.json()\n",
    "    print(\"Första prognosen:\")\n",
    "    first_time = data[\"timeSeries\"][0]\n",
    "    valid_time = first_time[\"validTime\"]\n",
    "    temperature = next(p for p in first_time[\"parameters\"] if p[\"name\"] == \"t\")[\"values\"][0]\n",
    "    print(f\"Tidpunkt: {valid_time}\")\n",
    "    print(f\"Temperatur: {temperature} °C\")\n",
    "else:\n",
    "    print(f\"Fel vid API-anrop: {response.status_code}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Hämta temperatur från SMHI (demo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import pandas as pd\n",
    "from datetime import datetime, timedelta\n",
    "from geopy.distance import distance\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.dates as mdates\n",
    "\n",
    "lat = 58.51\n",
    "lon = 12.49\n",
    "\n",
    "station_url = \"https://opendata-download-metobs.smhi.se/api/version/latest/parameter/1.json\"\n",
    "r = requests.get(station_url)\n",
    "if r.status_code != 200:\n",
    "    raise Exception(f\"Fel vid hämtning av stationsdata: {r.status_code}\")\n",
    "stations = r.json()[\"station\"]\n",
    "\n",
    "def find_working_station(lat, lon, stations, max_candidates=10):\n",
    "    sorted_stations = sorted(\n",
    "        stations, key=lambda s: distance((lat, lon), (s[\"latitude\"], s[\"longitude\"])).km\n",
    "    )\n",
    "    for station in sorted_stations[:max_candidates]:\n",
    "        station_id = station[\"id\"]\n",
    "        url = f\"https://opendata-download-metobs.smhi.se/api/version/latest/parameter/1/station/{station_id}/period/latest-months/data.json\"\n",
    "        r = requests.get(url)\n",
    "        if r.status_code == 200:\n",
    "            try:\n",
    "                r.json()  # Kontrollera att det verkligen är JSON\n",
    "                return station\n",
    "            except ValueError:\n",
    "                continue\n",
    "    raise Exception(\"Hittade ingen närliggande station med fungerande observationsdata.\")\n",
    "\n",
    "closest_station = find_working_station(lat, lon, stations)\n",
    "print(\"Närmaste fungerande station:\", closest_station[\"name\"])\n",
    "\n",
    "station_id = closest_station[\"id\"]\n",
    "\n",
    "obs_url = f\"https://opendata-download-metobs.smhi.se/api/version/latest/parameter/1/station/{station_id}/period/latest-months/data.json\"\n",
    "obs_response = requests.get(obs_url)\n",
    "if obs_response.status_code != 200:\n",
    "    raise Exception(f\"Fel vid hämtning av observationsdata: {obs_response.status_code}\")\n",
    "try:\n",
    "    obs_data = obs_response.json()\n",
    "except ValueError:\n",
    "    raise Exception(\"Kunde inte tolka observationssvar som JSON.\")\n",
    "\n",
    "temps = []\n",
    "for item in obs_data.get(\"value\", []):\n",
    "    if item[\"value\"] is not None:\n",
    "        timestamp = pd.to_datetime(item[\"date\"], unit=\"ms\")\n",
    "        temps.append((timestamp, item[\"value\"]))\n",
    "\n",
    "df_hist = pd.DataFrame(temps, columns=[\"time\", \"temperature\"])\n",
    "df_hist[\"typ\"] = \"Observation\"\n",
    "\n",
    "forecast_url = f\"https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/{lon}/lat/{lat}/data.json\"\n",
    "forecast_response = requests.get(forecast_url)\n",
    "if forecast_response.status_code != 200:\n",
    "    raise Exception(f\"Fel vid hämtning av prognos: {forecast_response.status_code}\")\n",
    "forecast = forecast_response.json()\n",
    "\n",
    "forecast_data = []\n",
    "for item in forecast[\"timeSeries\"]:\n",
    "    timestamp = pd.to_datetime(item[\"validTime\"])\n",
    "    temp = next((p for p in item[\"parameters\"] if p[\"name\"] == \"t\"), None)\n",
    "    if temp:\n",
    "        forecast_data.append((timestamp, temp[\"values\"][0]))\n",
    "\n",
    "df_forecast = pd.DataFrame(forecast_data, columns=[\"time\", \"temperature\"])\n",
    "df_forecast[\"typ\"] = \"Prognos\"\n",
    "\n",
    "nn = 100 # nn senaste datapunkterna\n",
    "df_hist = df_hist.sort_values(\"time\").tail(nn)\n",
    "df_forecast = df_forecast.sort_values(\"time\").head(nn)\n",
    "\n",
    "df_all = pd.concat([df_hist, df_forecast])\n",
    "\n",
    "# konvertera temperaturvärdena till float\n",
    "df_all[\"temperature\"] = pd.to_numeric(df_all[\"temperature\"], errors='coerce')\n",
    "\n",
    "# Ta bort rader med NaN-värden (ogiltiga temperaturvärden)\n",
    "df_all = df_all.dropna(subset=[\"temperature\"])\n",
    "\n",
    "plt.figure(figsize=(12, 6))\n",
    "for typ, grp in df_all.groupby(\"typ\"):\n",
    "    plt.plot(grp[\"time\"], grp[\"temperature\"], '-*', label=typ)\n",
    "\n",
    "min_temp = df_all[\"temperature\"].values.min()\n",
    "max_temp = df_all[\"temperature\"].values.max()\n",
    "min_time = df_hist[\"time\"].min()\n",
    "max_time = df_forecast[\"time\"].max()\n",
    "\n",
    "plt.ylim(min_temp - 2, max_temp + 2)\n",
    "plt.xlim(min_time, max_time)\n",
    "plt.yticks(range(int(min_temp) - 2, int(max_temp) + 3, 2))\n",
    "plt.title(f\"Temperatur i {closest_station['name']} – senaste tiden + prognos\")\n",
    "plt.ylabel(\"Temperatur (°C)\")\n",
    "plt.grid(True)\n",
    "plt.legend()\n",
    "\n",
    "ax = plt.gca()\n",
    "ax.xaxis.set_major_locator(mdates.AutoDateLocator())\n",
    "ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "url = \"https://api.thecatapi.com/v1/images/search\"\n",
    "response = requests.get(url)\n",
    "\n",
    "if response.status_code == 200:\n",
    "    data = response.json()\n",
    "    print(\"Här är en kattbild:\", data[0][\"url\"])\n",
    "else:\n",
    "    print(\"Något gick fel:\", response.status_code)\n",
    "\n",
    "# print(data[0][\"url\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Demo - hämta många bilder för att skapa kollage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "from PIL import Image\n",
    "from io import BytesIO\n",
    "import matplotlib.pyplot as plt\n",
    "import random\n",
    "import numpy as np\n",
    "\n",
    "# Hämta 50 kattbilder från The Cat API\n",
    "\n",
    "all_data = []\n",
    "for _ in range(5):  # 5 requests med 10 bilder vardera\n",
    "    response = requests.get(\"https://api.thecatapi.com/v1/images/search?limit=10\")\n",
    "    if response.status_code == 200:\n",
    "        all_data.extend(response.json())\n",
    "    else:\n",
    "        print(\"Något gick fel med API-förfrågan:\", response.status_code)\n",
    "data = all_data\n",
    "\n",
    "images = []\n",
    "for item in data:\n",
    "    image_url = item['url']\n",
    "    img_response = requests.get(image_url)\n",
    "    try:\n",
    "        img = Image.open(BytesIO(img_response.content)).convert(\"RGBA\")\n",
    "        img.thumbnail((150, 150))  # Gör bilderna mindre enligt önskemål\n",
    "        images.append(img)\n",
    "    except:\n",
    "        print(\"Kunde inte läsa en bild:\", image_url)\n",
    "\n",
    "# Skapa en figur med svart bakgrund\n",
    "fig, ax = plt.subplots(figsize=(10, 6))\n",
    "ax.set_facecolor(\"black\")\n",
    "ax.set_xlim(0, 800)\n",
    "ax.set_ylim(0, 500)\n",
    "ax.axis('off')\n",
    "\n",
    "# Lägg ut bilder slumpmässigt och med rotation\n",
    "for img in images:\n",
    "    x = random.randint(0, 650)\n",
    "    y = random.randint(0, 350)\n",
    "    angle = random.uniform(-30, 30)\n",
    "\n",
    "    # Rotera bild runt centrum (expand=True så att den inte kapas)\n",
    "    rotated = img.rotate(angle, expand=True)\n",
    "\n",
    "    # Omvandla till numpy-array för att kunna visa i matplotlib\n",
    "    img_array = np.array(rotated)\n",
    "\n",
    "    ax.imshow(img_array, extent=(x, x + rotated.width, y, y + rotated.height), zorder=1)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"cats\", dpi=500)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "# Läs JSON från fil\n",
    "with open('exempel.json', 'r', encoding='utf-8') as f:\n",
    "    data = json.load(f)\n",
    "\n",
    "# Hämta ägarinformation\n",
    "ägare = data.get('owner', {})\n",
    "namn = ägare.get('name')\n",
    "plats = ägare.get('location')\n",
    "\n",
    "print(f\"Ägare: {namn}, Plats: {plats}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LLM via API\n",
    " (i denna kodsnutt behöver ni någon betalvariant av OpenAI så ni får tillgång till en API-nyckel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from openai import OpenAI\n",
    "\n",
    "with open(\"config.json\", \"r\", encoding=\"utf-8\") as f:\n",
    "    api_key = json.load(f).get(\"openai_api_key\")\n",
    "\n",
    "client = OpenAI(api_key=api_key)\n",
    "\n",
    "# Systemprompt/instruktion och användarfråga\n",
    "system_prompt = \"Svara så att en nioåring förstår.\"\n",
    "user_question = \"Hur fungerar en 3D-skrivare?\"\n",
    "\n",
    "# Skicka API-förfrågan\n",
    "response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-mini\",\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": system_prompt},\n",
    "        {\"role\": \"user\", \"content\": user_question}\n",
    "    ],\n",
    "    temperature=0.1  # Högre temp -> mer slumpmässig/kreativ\n",
    ")\n",
    "\n",
    "print(\"\\nSvar från GPT:\\n\")\n",
    "print(response.choices[0].message.content.strip())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**config.json - json-fil med namn config.json och API-nyckel. Ska se ut så här:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "{\n",
    "    \"openai_api_key\": \"sk-asdflökjasdflkjasdflsdökjflöaskjdflökasjdf\"   # klistra in API-nyckel mellan citations-tecknen\n",
    "  }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Primtalsskript med olika abstraktionsgrad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Funktion för att kontrollera om ett tal är ett primtal\n",
    "def är_primtal(n):\n",
    "    if n < 2:\n",
    "        return False\n",
    "    for i in range(2, int(n**0.5) + 1):\n",
    "        if n % i == 0:\n",
    "            return False\n",
    "    return True\n",
    "\n",
    "# Lista för att spara primtalen\n",
    "primtal = []\n",
    "\n",
    "# Gå igenom alla tal från 0 till 100\n",
    "for tal in range(101):\n",
    "    if är_primtal(tal):\n",
    "        primtal.append(tal)\n",
    "\n",
    "# Skriv ut resultatet\n",
    "print(\"Primtal mellan 0 och 100:\")\n",
    "print(primtal)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Kompakt motsv. skript**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print([n for n in range(2, 101) if all(n % d != 0 for d in range(2, int(n**0.5)+1))])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Inför medveten bugg**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print([n for n in range(2, 101) if All(n % d != 0 for d in range(2, int(n**0.5)+1))])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Anropa lokal LLM i ipynb-fil\n",
    "\n",
    "(se ollama.com för instruktioner kring att komma igång med ex.vis Llama-modellerna)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "response = requests.post(\n",
    "    'http://localhost:11434/api/chat',\n",
    "    json={\n",
    "        'model': 'llama3.1',\n",
    "        'messages': [\n",
    "            {\"role\": \"system\", \"content\": \"Answer like Arnold in Terminator 2.\"},\n",
    "            {\"role\": \"user\", \"content\": \"What's the point of life?\"}\n",
    "        ],\n",
    "        'stream': False\n",
    "    }\n",
    ")\n",
    "\n",
    "result = response.json()\n",
    "print(result['message']['content'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (venv)",
   "language": "python",
   "name": "venv"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
