File size: 5,958 Bytes
7a8b33f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import argparse
import json
import multiprocessing as mp
from zsvision.zs_multiproc import starmap_with_kwargs
from pathlib import Path
from zsvision.zs_utils import BlockTimer
from typing import List, Dict
from llm_api_utils import (
    call_openai_with_exponetial_backoff,
    estimate_cost_of_text_generation_api_call,
    init_openai_with_api_key,
)


class CheckClaimAgainstEvidence:
    def __init__(
        self,
        temperature=0.0,
        max_num_evidences=2,
        model="gpt-3.5-turbo",
        src_dir=Path("data/raw"),
        dest_dir=Path("data/extracted_claims"),
        filter_str="",
        processes=1,
        refresh=False,
    ):
        self.temperature = temperature
        self.max_num_evidences = max_num_evidences
        self.model = model
        self.src_dir = src_dir
        self.dest_dir = dest_dir
        self.filter_str = filter_str
        self.processes = processes
        self.refresh = refresh

    def check_claim_against_evidence(
        self,
        claim: str,
        evidences: List[Dict[str, str]],
    ):
        init_openai_with_api_key()
        evidence_str = ""
        for evidence in evidences:
            # avoid linebreaks in each piece of evidence, else it can create a confusing prompt
            text_evidence = evidence["text"].replace("\n", " ")
            evidence_str += f"{text_evidence}\n"
            evidence_str += f"URL: {evidence['link']}'\n"
            evidence_str += f"Date accessed: {evidence['date_accessed']}\n\n"

        prompt = f"""\
Your task is to assess whether a claim is correct based on the given pieces of evidence.

Your answer should be in json format as follows:
{{
    "verdict": "<verdict>",
    "justification": "<justification for the verdict>",
    "quotes": ["<most relevant verbatim quotes from evidence>"],
    "URLs": "<URL sources for verbatim quotes>",
    "date_accessed": "<access dates for URL quotes>"
}}
The <verdict> label should be one of the following:
"Fully supported", "Partially supported", "Unsupported"

When quoting the relevant sentence from the evidence, be careful to copy it **EXACTLY** (with no edits).
---
## Example

**Claim**:
Hannah Arendt was born in 1906.

**Pieces of evidence**:
Hannah Arendt was a 20th-century German-Jewish political thinker and philosopher. She was born in Linden, Hanover, Germany in 1906. When she was three her family moved to Königsberg so that her father’s syphilis could be treated. He died when she was seven years old. Königsberg was where Immanuel Kant was born, right?

Königsberg was where Immanuel Kant was born, right?
URL: https://fivebooks.com/best-books/hannah-arendt-samantha-rose-hill/'
Date accessed: 2023-05-10

Hannah Arendt was born as Johanna Arendt in 1906, in the Wilhelmine period. Her German Jewish family were comfortable, educated and secular in Linden, Prussia (now a part of Hanover). They were merchants of Russian extraction from Königsberg.[a] Her grandparents were members of the Reform Jewish community. Her paternal grandfather, Max Arendt [de] (1843–1913), was a prominent businessman, local politician, a leader of the Königsberg Jewish community and a member of the Centralverein deutscher
URL: https://en.wikipedia.org/wiki/Hannah_Arendt'
Date accessed: 2023-05-10


**Assessment**:
{{
    "verdict": "Fully supported",
    "justification": "The claim about Hannah Arendt's birth date is directly supported by the evidence."
    "quote": "Hannah Arendt was born as Johanna Arendt in 1906, in the Wilhelmine period.",
    "URL": "https://en.wikipedia.org/wiki/Hannah_Arendt",
    "date_accessed": "2023-05-10"
}}
---
**Claim**:
{claim}

**Pieces of evidence**:
{evidence_str}
**Assessment**:\
"""
        persona = "You are a careful research assistant who helps with fact-checking and editing informative articles."
        system_message = {"role": "system", "content": persona}
        user_message = {"role": "user", "content": prompt}
        messages = [system_message, user_message]

        with BlockTimer(
            f"Using OpenAI API to check claims against evidence {self.model}"
        ):
            response = call_openai_with_exponetial_backoff(
                model=self.model,
                temperature=self.temperature,
                messages=messages,
                response_format={"type": "json_object"},
            )

        cost = estimate_cost_of_text_generation_api_call(
            model=self.model, response=response, verbose=True
        )

        assessment = response.choices[0].message.content
        assessment_dict = json.loads(assessment)
        return {"assessment": assessment_dict, "cost": cost}

    def check_claims_against_evidence(self, claims_with_evidence):
        """
        Checks claims against evidence.
        """
        kwarg_list = []
        results = []
        for idx, item in enumerate(claims_with_evidence):
            kwarg_list.append(
                {
                    "claim": item["claim"],
                    "evidences": item["evidences"][: self.max_num_evidences],
                }
            )
        if self.processes == 1:
            for kwargs in kwarg_list:
                results.append(self.check_claim_against_evidence(**kwargs))
        else:  # multiprocess
            func = self.check_claim_against_evidence
            with mp.Pool(processes=self.processes) as pool:
                results = starmap_with_kwargs(
                    pool=pool, func=func, kwargs_iter=kwarg_list
                )
        costs = [result["cost"] for result in results]
        print(f"Total cost: {sum(costs)} USD")
        assessed_claims = []
        for result, item in zip(results, claims_with_evidence):
            item["assessment"] = result["assessment"]
            item["verdict_model"] = self.model
            assessed_claims.append(item)

        print(f"Writing {len(assessed_claims)} assessed claims")
        return assessed_claims