# Implementation
All utvecklad implementation utöver mindre exempel och "proof-of-concepts" bor i en gemensam [GitHub grupp](https://github.com/orgs/lnu-askit/repositories).
Ovanstående grupp i GitHub hålls automatisk uppdaterad genom projektets utveckling. Nedanstående presentationer av implementation kan sannolikt vara informationsmässigt utdaterade och peka på fel resurser.
## Full Demo
Ett lokalt demo-system har utvecklats i formen av dockerisering av systemets olika delar. De olika docker-containrarna orkestreras med docker-compose och tillåter användaren att lokalt drifta chattsystemet på valfri dator med docker desktop installerat.
Följande bilder visar exempel på hur chattbotten kan besvara IT-relaterade frågor utifrån kunskap från serviceportalens artiklar
#### Glömt Lösenord

#### Anslutning till trådlöst nätverk med följdfråga

[GitHub-repository](https://github.com/lnu-askit/full-local-demo)
## Klient
Ett gränssnitt behöver utvecklas för att göra det möjligt att interagera i chatbotten.
Den nuvarande implementationen existerar främst för att laborera med gränssnittets utseende & stilsättning, men den kan ändå fullt funktionellt kommunicera med en gpt-3.5-turbo språkmodell.

[GitHub-repository](https://github.com/lnu-askit/askit-client)
## Vektoriserare / Databas-uppladdare
#### Proof-of-concept | Prototyp
För att vektorisera och göra embeddings av chattbottens kunskap behöver vi förhålla oss till OpenAI Rate limits. Detta åstadkommer vi genom användning av en `api_request_parallel_processor` som OpenAI har tillgängliggjort på deras GitHub. Datan behöver förberedas ganska noga för att parallel_processorn kan läsa det, och datan måste sedan laddas upp i Pinecone, vårt val av vektordatabas.
[Parallel-processor source](https://github.com/openai/openai-cookbook/blob/main/examples/api_request_parallel_processor.py)
[GitHub-repository](https://github.com/wernersson/upload-to-pinecone)
#### Aktuellt | Drift-redo
Vi använder oss av Openais Retrieval Plugin som underlättar när man vill avgränsa den information som en chatbot ska använda sig av i sina svar. Pluginet i det här projektet vektoriserar det som skrapats fram, sparar det till Pinecone och sedan matchar det insparade med frågor från användare.
[GitHub-repository](https://github.com/openai/chatgpt-retrieval-plugin/tree/7f1b8c26bb395afd5af0ec809cb4288b35da53ed)
## Webbskrapa
För att bygga en aktuell kunskapsdatabas för AskIT:s användning kan webbskrapning av serviceportalens artiklar tillämpas.
Den nuvarande implementationen påvisar att det är möjligt att skrapa serviceportalens artiklar.
[GitHub-repository](https://github.com/CoderSeb/askit-scraper)
## Städa HTML från IT-avdelningens kunskapsartiklar
De kunskapsartiklar från IT-avdelningen som chat-AI:n kan komma att använda som kunskapsdatabas behöver tvättas från HTML och annan “skräp”-data. Vi har identifierat ett flertal olika arbetsuppgifter därinom:
1. HTML-taggar ska avlägsnas
2. HTML-entiteter ska avkodas
3. Base64-kodade bilder behöver hanteras
Den nuvarande implementationen har förmågan att rensa texten på HTML-taggar och att avkoda HTML-entiteter, samt att spara undan hela datasetet i en mer användbar databas. De base64-kodade bilderna extraheras från lösningsförslaget och sparas undan i databasen.
[GitHub-repository](https://github.com/wernersson/parse-and-store-xslx)
## Konversation med ChatGPT-modell
De olika GPT-3 språkmodellerna som är tillgängliggjorda av OpenAI har inget naturligt stöd för konversationer, då de i grund och botten endast kompletterar inmatad text. För att en GPT-3 textkompletteringsmodell ska kunna hantera en konversation som om den vore en chatbot så behöver den:
1. Veta att den ska komplettera texten som om den gav ett svar ifrån en chatbot
2. Minnas vad som har sagts tidigare i konversationen.
För att åstadkomma dessa krav kan varje fråga (prompt) till språkmodellen inledas med en kontextförklaring (primer), alltså en förklaring att modellen befinner sig inuti en konversation mellan en användare och en IT-support chatbot. Utöver detta inkluderas även hela historiken av den nuvarande konversationen mellan användaren och chatbotten.
Den nuvarande implementationen påvisar att det är praktiskt möjligt att få en ChatGPT språkmodell att agera chatbot, samt att den har förmågan att “minnas” vad som har sagts tidigare i konversationen.
[GitHub-repository](https://github.com/wernersson/openai-chat-messing-around)
## Experiment
### 001 - Användning av kontext i varje fråga till OpenAI
**Kod:**
```python=
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
COMPLETIONS_MODEL = "text-davinci-003"
prompt = """Tänk dig att du är en första linjens supporttekniker vid Linnéuniversitetet (LNU). Svara på frågan så sanningsenligt som möjligt, om du inte vet så svara: "Jag ber om ursäkt, jag vet inte." Svara på samma språk som frågan är ställd på. Användaren kommer inte att ha tillgång till informationen i Context:. Om ditt svar är en fråga för att få mer information från användaren, inkludera ett frågetecken i svaret. Om du kan hänvisa till en url i serviceportalen så gör det i första hand.
Context:
Zoom är ett utmärkt verktyg för att sköta kommunikation med kollegor (student eller personal), hålla möten eller seminarier.
Både studenter och personal har samma åtkomst till Zoom och kan använda det på exakt samma sätt. Den enda skillnaden är att studenter inte kan söka upp personal på Lnu via Zoom, däremot kan personal söka upp studenter och starta en kommunikation. Känner du som student däremot till din lärares e-postadress så kan du skicka en inbjudan via epost till ett möte (läs mer om detta i andra artiklar).
En bra källa för information om hur man installerar Zoom är här: https://serviceportalen.lnu.se/sv-se/article/1320496
History: <HISTORY>
Q: <QUESTION>
A:"""
history = ""
def ask(question, currentHistory):
prompt.replace("<HISTORY>", currentHistory)
return openai.Completion.create(
model=COMPLETIONS_MODEL,
prompt=prompt.replace("<QUESTION>", question),
temperature=0,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
max_tokens=300,
)["choices"][0]["text"].strip(" \n")
question = input("Ask a question/Ställ en fråga:\n")
response = ask(question, history)
history = history + response
print(response)
while "?" in response:
followQuestion = input()
response = ask(followQuestion, history)
history = history + response
print(response)
```
**Output:**
```bash
Ask a question/Ställ en fråga:
Jag har problem med zoom, håller på att bli galen!
Hej, jag förstår att du har problem med Zoom. Jag skulle vilja hjälpa dig att lösa det. Kan du berätta mer om problemet? Har du försökt att installera Zoom enligt instruktionerna som finns på serviceportalen? (https://serviceportalen.lnu.se/sv-se/article/1320496)
Jag har försökt installera men kan inte logga in!
Försök att följa instruktionerna som finns på den här länken: https://serviceportalen.lnu.se/sv-se/article/1320496. Om du fortfarande har problem med att logga in, kontakta oss så hjälper vi dig.
```
**Reflektioner:**
I det här exemplet använder vi ett kontext för att "lära" davinci modellen området Zoom via lnu. Informationen finns på serviceportalen och davinci använder informationen till att formulera sina svar till användaren. Vi skickar även med en historik över vad som sagts så att modellen inte upprepar sig i onödan.
Med detta exemplet kan vi skrapa serviceportalen på information och länkar för att spara undan i en databas uppdelat efter ämne. När användaren först öppnar chatbotten får denne då välja ämne, därefter ställer användaren sin fråga. Det kontext som då finns i det ämnet skickas med frågan för att ge modellen förutsättningen att svara på frågan.
*Fördelar*
1. Informationen kan skrapas någon/några gång(er) i veckan och sparas i databas. Informationen kommer alltså alltid att vara uppdaterad.
2. Endast en betaltjänst används (OpenAI).
3. Svaren blir mer exakta och minskar risken för fel svar, modellen kan i detta fallet endast det som finns i kontexten.
4. Man slipper att faktiskt träna en språkmodell (Fine-Tuning), vilket hade blivit dyrt ifall kunskapen ska hållas uppdaterad.
*Nackdelar*
1. Det blir dyrare för varje fråga som skickas, då den växande konversationshistoriken behöver inkluderas i varje följdfråga. Vi behöver dock inte träna om en egen modell så fort resurserna uppdateras (se fördel #4).
### 002 - OpenAI Moderation API för att upptäcka skadlig text
**Kod:**
```python=
import os
import openai
openai.api_key = os.getenv('OPENAI_API_KEY')
COMPLETIONS_MODEL = "text-davinci-003"
def evaluateHarm(content):
return openai.Moderation.create(input=content)
content = input("Enter phrase to evaluate:\n")
response = evaluateHarm(content)
print(response)
```
OpenAI repository: [Moderation API Exempel Skadliga Fraser](https://github.com/openai/moderation-api-release)
**Output:**
```bash
Enter phrase to evaluate:
# User Input Redacted #
{
"id": "modr-6i2ZVt5hjNuVPqFl2cyorNJGwlBx4",
"model": "text-moderation-004",
"results": [
{
"categories": {
"hate": false,
"hate/threatening": false,
"self-harm": false,
"sexual": false,
"sexual/minors": false,
"violence": true,
"violence/graphic": true
},
"category_scores": {
"hate": 0.01952902413904667,
"hate/threatening": 6.338306093311985e-07,
"self-harm": 9.898778080241755e-05,
"sexual": 7.864450708439108e-06,
"sexual/minors": 2.0931265964918566e-07,
"violence": 0.9748616218566895,
"violence/graphic": 0.9737775921821594
},
"flagged": true
}
]
}
```
**Reflektioner:**
I det här exemplet använder vi Moderation API:et från OpenAI för att upptäcka ifall en text kan anses vara skadlig. Moderation-modellen mäter och klassificerar text enligt 7 kategorier, och har bedömt den inmatade texten att vara skadlig enligt två kategorier, ``violence`` & ``violence/graphic``. Texten blir därmed flaggad som skadlig och användaren av API:et (projektutvecklare) kan använda flaggan för att hantera situationen programmatiskt.