{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Intro til språkmodeller"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Spørsmål\n",
    "- Vi trenger at dte går fortere å kalle på modellen :)\n",
    "- Hvordan gjør vi det med nøkler? Per nå leser denne fortsatt fra .env-filen da jeg ikke ville pushe de til github.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tanker\n",
    "\n",
    "- Gi mer info i prompt om situasjonen rundt spørreundersøkelsen og hva det har blitt spurt om. Spesielt i situasjonen hvor vi øsnker å oppsummere den generelle viben av feedbacken i hver kategori. Var folk fornøyde? Ønsker de tiltak for forbedring?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# AzureChatOpenAI\n",
    "### Språkmodellene"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import AzureChatOpenAI\n",
    "from dotenv import find_dotenv, load_dotenv\n",
    "import os\n",
    "\n",
    "\n",
    "# Get environment variables\n",
    "load_dotenv(find_dotenv(), override=True)\n",
    "\n",
    "\n",
    "# Variabler heller enn klasser\n",
    "class Llm:\n",
    "    \"\"\"\n",
    "    Class containing the language model.\n",
    "    \"\"\"\n",
    "\n",
    "    llm = AzureChatOpenAI(\n",
    "        azure_deployment=os.environ[\"AZURE_OPENAI_DEPLOYMENT_GPT_4O_MINI\"],\n",
    "        model=os.environ.get(\"OPENAI_MODEL_GPT_4O-MINI\", default=\"gpt-4o-mini\"),\n",
    "        temperature=0,\n",
    "    )\n",
    "\n",
    "\n",
    "class LlmRes:\n",
    "    \"\"\"\n",
    "    Class containing the language model.\n",
    "    \"\"\"\n",
    "\n",
    "    llm = AzureChatOpenAI(\n",
    "        azure_deployment=os.environ[\"AZURE_OPENAI_DEPLOYMENT_GPT_3O_MINI\"],\n",
    "        model=os.environ.get(\"OPENAI_MODEL_GPT_3O-MINI\", default=\"o3-mini\"),\n",
    "        reasoning_effort=\"high\",\n",
    "    )\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Den enkleste måten å bruke AzureChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = 'Hei!'\n",
    "response = Llm.llm.invoke(prompt)\n",
    "\n",
    "print(response)\n",
    "\n",
    "print(response.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Structured output\n",
    "### Pydantic-objekter\n",
    "- Gå igjennom hva disse objektene er, hva kan du kreve av outputen?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Enkel bruk av structured output \n",
    "# Hva i alle dager er pydantic? :D\n",
    "# Lag en enkel klasse og kjør\n",
    "\n",
    "class Categorize(BaseModel):\n",
    "    \"Categorization of feedback on IT-services.\"\n",
    "\n",
    "    # Thoughts: Forklar tankegangen din.\n",
    "    category : str = Field(description=\"The best fitting general category. Only one.\")\n",
    "   \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "structured_llm = Llm.llm.with_structured_output(   #Gå igjennom denne, hvordan bruker man structured output?\n",
    "        Categorize, method=\"function_calling\"\n",
    "    )\n",
    "\n",
    "response = structured_llm.invoke(\"Send inn prompt + data\")\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CategorizeFromOptions(BaseModel):\n",
    "    \"\"\"Categorization of IT-questionaire feedback.\"\"\"\n",
    "\n",
    "    category: Literal[\n",
    "        \"Network\",\n",
    "        \"IT Training\",\n",
    "        \"IT Support\",\n",
    "        'Other'\n",
    "    ] = Field(\n",
    "        description=\"Categorize the feedback into the most fitting category. If the categories provided are not a perfect fit, default to 'Other'.\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Chain of thought"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Find potential new categories based on feedback categorized as others"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CategorizeFromOptions2(BaseModel):\n",
    "    \"\"\"Categorization of IT-questionaire feedback.\"\"\"\n",
    "\n",
    "    category: Literal[\n",
    "       # Insert the categories you found while exploring the feedback initially categorized as 'Other'.\n",
    "    ] = Field(\n",
    "        description=\"Categorize the feedback into the most fitting category. If the categories provided are not a perfect fit, default to 'Other'.\"\n",
    "    )\n",
    "    reason : str = Field(description=\"Why do you believe this category is the most fitting one? Explain.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Oppgave??"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydantic import BaseModel, Field\n",
    "from typing import Literal, Optional\n",
    "\n",
    "# Kan de mekke på disse selv? Hvordan kan vi gjøre dette steget mer interaktivt\n",
    "\n",
    "\n",
    "class Categorize_search(BaseModel):\n",
    "    \"\"\"Categorization of IT-questionaire feedback.\"\"\"\n",
    "\n",
    "    categories: Literal[\n",
    "        \"Network\",\n",
    "        \"IT Training\",\n",
    "        \"IT Support\",\n",
    "        'Other'\n",
    "    ] = Field(\n",
    "        description=\"Categorize the feedback into the most fitting category. If the categories provided are not a perfect fit, default to 'Other'.\"\n",
    "    )\n",
    "    #if_other: str = Field(\n",
    "        #description=\"If you chose to categorize the feedback as 'Other', return an explanation as to why and what category you think would be the best fit for the feedback.\"\n",
    "    #)\n",
    "\n",
    "\n",
    "class Categorize_bound(BaseModel):\n",
    "    # Begrenser kategoriene modellen kan velge mellom. Den får kun lov til å putte feedbacken i en av de forhåndsbestemte kategoriene.\n",
    "    \"\"\"Categorization of IT-questionaire feedback.\"\"\"\n",
    "\n",
    "    categories: Literal[\n",
    "        \"Cyber security\",\n",
    "        \"IT training\",\n",
    "        \"IT support\",\n",
    "        \"Quality of technology\",\n",
    "        \"Data quality\",\n",
    "        \"Network\",\n",
    "    ] = Field(description=\"Categorize the feedback into the most fitting category.\")\n",
    "   # rating: Optional[int] = Field(\n",
    "       # description=\"Your certainty of the corectness of the best category on a scale from 1-10\"\n",
    "  #  )\n",
    "    #reason: str = Field(\n",
    "    #    description=\"Give a short scentence as to why you think this category is the best fit.\"\n",
    "   # )\n",
    "\n",
    "\n",
    "\n",
    "class Categorize(BaseModel):\n",
    "    \"Categorization of feedback on IT-services.\"\n",
    "\n",
    "    # Thoughts: Forklar tankegangen din.\n",
    "    cat_1: str = Field(description=\"The best fitting general category. Only one.\")\n",
    "    \n",
    "class Summarize(BaseModel):\n",
    "\n",
    "    # 1. Oppsummer kategori, tar inn alle feedbacks under 1 kategori\n",
    "    # 2. Likely underlying causes of recurring issues or praises\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Case"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Datasettet (FLYTT TIL INTRO)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "\n",
    "class FeedbackData:\n",
    "    \"\"\"\n",
    "    Class containing fake datasets by us :)\n",
    "    \"\"\"\n",
    "\n",
    "    # Load a DataFrame with a specific version of a CSV\n",
    "\n",
    "    enr_path = \"../files/forslag_1.csv\"\n",
    "    df = pd.read_csv(enr_path)#.head(20)\n",
    "    df_mini = df.head(5)\n",
    "\n",
    "\n",
    "# print(FeedbackData.df[\"Feedback\"][0])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Kategorisering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Lag en funksjon som tar inn enten full prompt eller data fra undersøkelsen + pydantic objekt (struct) + modell og returnerer output fra modell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## KURS\n",
    "def categorize_feedback(feedback_txt : str, struktur, llm_model) -> dict:\n",
    "    # Prompt\n",
    "    task = f\"\"\"\n",
    "    PROMT\n",
    "    Catgorize the feedback: {feedback_txt}.\n",
    "    \"\"\"\n",
    "\n",
    "    # Defining structured output for the model\n",
    "    structured_llm = llm_model.with_structured_output(   #Gå igjennom denne, hvordan bruker man structured output?\n",
    "        struktur, method=\"function_calling\"\n",
    "    )\n",
    "\n",
    "    # Prompt model\n",
    "    response = structured_llm.invoke(task)\n",
    "    # Return the response\n",
    "    return response.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def categorize_feedback(feedback_txt : str, struktur, llm_model) -> dict:\n",
    "    # Prompt\n",
    "    task = f\"\"\"\n",
    "    The following feedback is from an internal survey at 'IT and Things Company' where they asked their employees for feedback on their IT-services in general.\n",
    "    Catgorize the feedback: {feedback_txt}.\n",
    "    \"\"\"\n",
    "\n",
    "    # Defining structured output for the model\n",
    "    structured_llm = llm_model.with_structured_output(\n",
    "        struktur, method=\"function_calling\"\n",
    "    )\n",
    "\n",
    "    # Prompt model\n",
    "    response = structured_llm.invoke(task)\n",
    "    # Return the response\n",
    "    return response.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Din tur"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Returner en dataframe med kategoriserte feedback \n",
    "# 1. Be den kategorisere uten begrensninger\n",
    "# 2. Gi den et sett med forhåndsdefinerte kategorier\n",
    "# 3. La 'other' være et alternativ. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## returnerer kategorisert feedback\n",
    "\n",
    "responses = []\n",
    "i = 0\n",
    "for f in FeedbackData.df[\"Feedback\"]:\n",
    "    feedback_4O = categorize_feedback(feedback_txt = f, struktur = Categorize_search, llm_model = Llm.llm)\n",
    "    feedback_3O = categorize_feedback(feedback_txt = f, struktur = Categorize_search, llm_model = LlmRes.llm)\n",
    "    responses.append({'Feedback': f, 'Category_4O': feedback_4O['categories'], 'Category_3O': feedback_3O['categories']})\n",
    "    i += 1\n",
    "    print(i)\n",
    "\n",
    "    \n",
    "cat_df = pd.DataFrame(responses)\n",
    "print(cat_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Identifiser de som ble identifisert som 'other' og finn kategori for de. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "others_df = cat_df[(cat_df['Category_3O'] == 'Other') | (cat_df['Category_4O'] == 'Other')]\n",
    "print(others_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CategorizeOther(BaseModel):\n",
    "    \"Categorization of feedback on IT services.\"\n",
    "\n",
    "    category : str = Field(\n",
    "        description=\"Three distinct, one-word categories that best summarize the key themes of the feedback.\"\n",
    "    )\n",
    "    reason : str = Field(\n",
    "        description=\"Explain briefly why these three categories are the best choices to organize the feedback. Highlight how each captures a key, non-overlapping aspect of the feedback.\"\n",
    "    )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataa = others_df[\"Feedback\"]\n",
    "f = \"\"\"Analyze the following IT service feedback carefully. Identify and suggest three categories that best organize the feedback into clear, distinct, and non-overlapping topics (MECE: Mutually Exclusive, Collectively Exhaustive). \n",
    "- Each category should be a single, specific, and meaningful word.\n",
    "- Focus on summarizing the *main themes* of the feedback, not specific examples.\n",
    "- Categories should not be too generic.\n",
    "- Think critically about overlaps — categories must not cover much of the same ground.\n",
    "- Only propose categories that are necessary to describe the core content.\n",
    "\n",
    "Feedback: {dataa}\"\"\"\n",
    "\n",
    "\n",
    "feedback_4O = categorize_feedback(feedback_txt = f, struktur = CategorizeOther, llm_model = Llm.llm)\n",
    "print(feedback_4O)\n",
    "\n",
    "feedback_3O = categorize_feedback(feedback_txt = f, struktur = CategorizeOther, llm_model = LlmRes.llm)\n",
    "print(feedback_3O)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## returnerer kategorisert feedback\n",
    "\n",
    "# Heller send inn alle others-feedback samtidig og be den finne X nye kategorier. \n",
    "responses_new_cat = []\n",
    "\n",
    "for f in others_df[\"Feedback\"]:\n",
    "    output_i = categorize_feedback(feedback_txt = f, struktur = Categorize, llm_model = Llm.llm)\n",
    "    responses_new_cat.append({'Feedback': f,'Category': output_i[\"cat_1\"]})\n",
    "\n",
    "new_cat_df = pd.DataFrame(responses_new_cat)\n",
    "print(new_cat_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Ny kategorisering hvor vi gir den grunnkategorier + de modellen har gjenkjent under other "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reasoning models - when we want the LLM to return logic analyzation across rows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nå vil vi teste resoneringsmodellen, sammenlikne?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summarization per category"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Få modellen til å oppsummere per kategori."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Now that we have defined fitting categories for the feedback, we can use a reasoning model to create a summary of the rows per category to provide an overall overview\n",
    "def summarize(feedback_txt : str, struktur, llm_model) -> dict:\n",
    "\n",
    "    # Prompt\n",
    "    task = f\"\"\"\n",
    "You are a domain expert in internal IT operations and organizational analysis. You will be provided with a dataset containing qualitative feedback from employees in an IT company. \n",
    "Each row in the dataset represents a feedback entry and is associated with a specific category.\n",
    "\n",
    "For each category, carefully:\n",
    "1. Read and interpret the feedback entries assigned to that category.\n",
    "2. Identify core themes, recurring patterns, and contrasting opinions within that category.\n",
    "3. Evaluate the feedback logically: What are the likely underlying causes of recurring issues or praises? Are there signs of systemic problems, isolated incidents, or misaligned expectations?\n",
    "4. Summarize each category in 3 to 6 bullet points, highlighting key sentiments (positive and negative), representative concerns or compliments, and any significant outliers\n",
    "\n",
    "Present your findings in a clean, professional way with one section per category. \n",
    "\n",
    "This is the employee feedback data: {feedback_txt}\n",
    "    \"\"\"\n",
    "\n",
    "    # Defining structured output for the model\n",
    "    structured_llm = llm_model.with_structured_output(\n",
    "        struktur, method=\"function_calling\"\n",
    "    )\n",
    "\n",
    "    # Prompt model\n",
    "    response_sum = structured_llm.invoke(task)\n",
    "    # Return the response\n",
    "    return response_sum.__dict__\n",
    "\n",
    "# Print head of response\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating a report for the leadership"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Bruk oppsummeringen til å generere en en rapport til ledelsen med forlag til forbedringspotensiale i IT. Hvilke tiltak bør bedriften gjøre?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def report(feedback_txt : str, struktur, llm_model) -> dict:\n",
    "\n",
    "    # Prompt\n",
    "    task = f\"\"\"\n",
    "You are an expert HR and technical operations analyst. I will provide you with a dataset of employee feedback collected from an IT company.\n",
    "\n",
    "Your task is to deeply analyze this feedback and generate a concise executive-level summary report in markdown format that includes:\n",
    "\n",
    "1. Key Takeaways\n",
    "Provide a short summary of the overall feedback in 3-5 bullet points. Focus only on the main issues or areas of satisfaction.\n",
    "Include both positive and negative themes, but prioritize the most important and impactful points.\n",
    "Limit each point to 1-2 sentences.\n",
    "Before finalizing each point, take a moment to reflect on why each issue might be present (e.g., systemic problems, temporary issues, resource constraints, etc.)\n",
    "\n",
    "2. Suggested Improvements\n",
    "Based on the overall feedback, propose 2-3 high-level, actionable measures that the company could take to address the most pressing issues and enhance overall performance or satisfaction.\n",
    "Each suggestion should be brief, directly tied to the feedback, and strategic in nature.\n",
    "Think about short-term vs long-term solutions and consider the feasibility of each suggestion.\n",
    "\n",
    "3. Output\n",
    "Present your findings in a structured way with clear section headings, bullet points for easy scanning, and a consise, direct and professional tone suitable for leadership review.\n",
    "\n",
    "This is the employee feedback data: {feedback_txt}\n",
    "    \"\"\"\n",
    "\n",
    "    # Defining structured output for the model\n",
    "    structured_llm = llm_model.with_structured_output(\n",
    "        struktur, method=\"function_calling\"\n",
    "    )\n",
    "\n",
    "    # Prompt model\n",
    "    response = structured_llm.invoke(task)\n",
    "    # Return the response\n",
    "    return response.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Skulle man hatt en oppgave til slutt for de som er fort ferdig hvor de sender inn hele undersøkelsen og ber modellen velge beste kategorier før vi igjen bruker de kategoriene i structured output for å kategorisere. kjør så hele på nytt og se om du synes resultatene ble bedre. \n",
    "\n",
    "2. Hvordan kunne dette vært gjort bedre? Er det "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "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.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
