File size: 9,624 Bytes
5d20be3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d25611b
5d20be3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d25611b
5d20be3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import torch
from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
from transformers import StoppingCriteriaList, StoppingCriteria
import warnings
from ragas import evaluate
from datasets import Dataset
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_recall,
    context_precision,
)
import os
import pandas as pd
from sentence_transformers import SentenceTransformer
from pinecone import Pinecone
import warnings

warnings.filterwarnings("ignore", category=UserWarning)

# Initialize Variables
# model_name = "AI-Sweden-Models/gpt-sw3-126m-instruct"
model_name = "AI-Sweden-Models/gpt-sw3-1.3b-instruct"
# model_name = "AI-Sweden-Models/gpt-sw3-6.7b-v2-instruct"


with open("language_model\pinecone\key.txt", "r") as f:
    os.environ["OPENAI_API_KEY"] = f.read().strip()

device = "cuda:0" if torch.cuda.is_available() else "cpu"

# Initialize Tokenizer & Model
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
model.eval()
model.to(device)

document_encoder_model = SentenceTransformer("KBLab/sentence-bert-swedish-cased")


def read_file(file_path: str) -> str:
    """Read the contents of a file."""
    with open(file_path, "r") as file:
        return file.read()


# Note: 'index1' has been pre-created in the pinecone console
# read the pinecone api key from a file
pinecone_api_key = read_file("language_model\pinecone\pincecone_api_key.txt")
pc = Pinecone(api_key=pinecone_api_key)
index = pc.Index("index1")


questions = [
    "Har ett barn rätt att få veta ifall det tillkommit genom insemination eller befruktning utanför kroppen som har utförts med andra könsceller än föräldrarnas egna?",
    "Vem ska anses vara förälder till barnet om modern är gift med en kvinna?",
    "Hur går det till ifall en man vill avsäga sig faderskapet till ett barn som han fått på grund av att han var gift med kvinnan som födde barnet?",
    "Vem får adoptera i Sverige?",
    "Får ett gift par adoptera på egen hand?",
    "Får man adoptera ett barn som fyllt 12 år utan barnets samtycke?",
    "Måste man försörja sina barn livet ut?",
    "Om en TV-reparatör har sönder min Tv-apparat, blir denna då ersättningsskyldig för detta?",
    "Vem äger rätten till ett fotografi?",
    "Hur mycket lagstadgat semester har man i Sverige?",
    "Min dotter är 19 år och hon går i gymnasieskolan. Jag är förälder men inte vårdnadshavare för henne. Hon bor inte hos mig utan hos sin mamma. Är jag fortfarande underhållsskyldig?",
    "Min son är adopterad och har börjat undra varför han inte är lik sina syskon, borde jag förklara för honom att han är adopterad? När och hur borde jag göra det?",
    "Min före detta man som efter vår skilsmässa inte längre har vårdnanden för våra barn kräver att jag ska betala för resorna bär barnen besöker honom. Kan detta verkligen stämma?  Det handlar inte om kostnaden från min sida, utan att det känns som han gör allt för att bråka med mig och pallar inte vika mig hela tiden för honom!",
    "Mina barn är så irriterande, får jag lov att slå dem som straff?",
    "Om jag vill göra en rymdresa med mina barn till månen, måste jag då be om min mans tillåtelse?",
]

ground_truths = [
    "Ja. Ett barn som har tillkommit genom en sådan insemination eller befruktning utanför kroppen som har utförts med andra könsceller än föräldrarnas egna har rätt att av sina föräldrar få veta det. Föräldrarna ska så snart det är lämpligt upplysa barnet om att han eller hon har tillkommit genom en sådan behandling.",
    "Om modern är gift med en kvinna eller är registrerad partner vid barnets födelse, ska hennes make eller registrerade partner anses som barnets förälder.",
    "Vill en man som på grund av äktenskap ska anses som far till ett barn att rätten ska förklara att han inte är far till barnet, ska han väcka talan om detta mot barnet eller, om barnet har avlidit, barnets arvingar.",
    "Den som har fyllt 18 år får adoptera.",
    "Nej, makar och sambor får endast adoptera gemensamt.",
    "Nej, den som har fyllt 12 år får adopteras endast om han eller hon samtycker till adoptionen.",
    "Nej, underhållsskyldigheten upphör när barnet fyller arton år. Går barnet i skolan efter denna tidpunkt, är föräldrarna underhållsskyldiga under den tid som skolgången pågår, dock längst intill dess barnet fyller tjugoett år. Till skolgång räknas studier i grundskolan eller gymnasieskolan och annan jämförlig grundutbildning.",
    "Jag har ingen information om detta.",
    "Den som har skapat ett litterärt eller konstnärligt verk har upphovsrätt till verket, exempel på verk är fotografiskt verk eller något annat alster av bildkonst.",
    "Enligt semesterlagen har alla anställda rätt till 25 dagars semester under ett år.",
    "Ja, du är underhållsskyldig. Föräldrarna är underhållsskyldiga under den tid som skolgången pågår (till skolgång räknas studier i grundskolan eller gymnasieskolan och annan jämförlig grundutbildning), dock längst intill dess barnet fyller tjugoett år. Detta gäller oavsett om föräldern har vårdnaden om barnet eller inte, men hänsyn tas till förälderns ekonomiska förmåga samt barnets egna inkomster.",
    "Ett barn som är adopterat har rätt att av sina föräldrar få veta det. Föräldrarna ska så snart det är lämpligt upplysa barnet om att han eller hon är adopterad.",
    "Ja, det stämmer. Om barnet bor tillsammans med endast en förälder, skall den föräldern ta del i kostnaderna för de resor som föranleds av barnets behov av umgänge med den andra föräldern. Det skall ske efter vad som är skäligt med hänsyn till föräldrarnas ekonomiska förmåga och övriga omständigheter.",
    "Nej, barnaga har varit förbjudet i Sverige sen 1979.",
    "Ja, enligt lagen måste båda föräldrarna vara överrens innan rymdresor med barnen görs.",
]


def query_pincecone_namespace(
    vector_databse_index: Pinecone, q_embedding: str, namespace: str
) -> str:
    result = vector_databse_index.query(
        namespace=namespace,
        vector=q_embedding.tolist(),
        top_k=1,
        include_values=True,
        include_metadata=True,
    )
    results = []
    for match in result.matches:
        results.append(match.metadata["paragraph"])
    return results[0]


def generate_prompt(prompt: str) -> str:
    """Generates a prompt for the GPT-3 model"""
    start_token = "<|endoftext|><s>"
    end_token = "<s>"
    return f"{start_token}\nUser:\n{prompt}\n{end_token}\nBot:\n".strip()


def encode_query(query: str) -> torch.Tensor:
    """Encode the query using the model's tokenizer"""
    return document_encoder_model.encode(query)


class StopOnTokenCriteria(StoppingCriteria):
    def __init__(self, stop_token_id):
        self.stop_token_id = stop_token_id

    def __call__(self, input_ids, scores, **kwargs):
        return input_ids[0, -1] == self.stop_token_id


stop_on_token_criteria = StopOnTokenCriteria(stop_token_id=tokenizer.bos_token_id)
answers = []
contexts = []


# på ett sakligt, kortfattat och formellt vis. Svara
def run_rag_system(with_rag=True):
    for question in questions:
        if with_rag:
            query = query_pincecone_namespace(
                vector_databse_index=index,
                q_embedding=encode_query(query=question),
                namespace="ns-parent-balk",
            )
            prompt = (
                "Besvara följande fråga med max tre meningar och använd och referera till den kontext med lagar du fått nedan: \n"
                + "Fråga: \n"
                + question
                + "\n"
                + "Kontext: \n"
                + query
            )
        else:
            prompt = (
                "Besvara följande fråga med max tre meningar. \n"
                + "Fråga: \n"
                + question
            )

        prompt = generate_prompt(prompt=prompt)
        print(prompt)
        print("-" * 50)

        # # Convert prompt to tokens
        input_ids = tokenizer(prompt, return_tensors="pt")["input_ids"].to(device)

        # Genqerate tokens based om prompt
        generated_token_ids = model.generate(
            inputs=input_ids,
            max_new_tokens=200,
            do_sample=False,
            temperature=0.3,
            top_p=1,
            stopping_criteria=StoppingCriteriaList([stop_on_token_criteria]),
        )[0]

        # Decode the generated tokens
        print("Generated answer: ")
        print("#" * 50)
        generated_text = tokenizer.decode(generated_token_ids[len(input_ids[0]) : -1])

        if with_rag:
            contexts.append([query.strip()])
        answers.append(generated_text.strip())
        print(generated_text)


run_rag_system(with_rag=True)
data = {
    "question": questions,
    "answer": answers,
    "contexts": contexts,
    "ground_truth": ground_truths,
}

# Convert dict to dataset
dataset = Dataset.from_dict(data)

result = evaluate(
    dataset=dataset,
    metrics=[
        context_precision,
        context_recall,
        faithfulness,
        answer_relevancy,
    ],
)

df = result.to_pandas()
print(df)
df.to_csv("ragas_results_two_documents.csv")
print("Results saved to ragas_results_two_documents.csv")

answers = []
run_rag_system(with_rag=False)
data = {
    "question": questions,
    "answer": answers,
    "ground_truth": ground_truths,
}

# create data frama from dict data
df = pd.DataFrame(data)
df.to_csv("gpt_results_no_rag.csv")