File size: 8,385 Bytes
37d3a3b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
222
223
224
225
226
227
228
229
230
231
232
233
234
import openai;
import json, os,sys
from dotenv import load_dotenv
load_dotenv()
# openai.api_key = os.environ.get("OPENAI_API_KEY")
import openai; openai.api_key = "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"
from Candidate import JobCandidate


import litellm
from litellm import completion


import xml.etree.ElementTree as ET







def printc(obj, color="cyan"):
    color_code = {
        "black": "30", "red": "31", "green": "32", "yellow": "33",
        "blue": "34", "magenta": "35", "cyan": "36", "white": "37"
    }
    colored_text = f"\033[{color_code[color]}m{obj}\033[0m" if color in color_code else obj
    print(colored_text)



LLM=os.environ.get("COMPARATOR_LLM","chat-bison")
# LLM=os.environ.get("COMPARATOR_LLM","gpt-3.5-turbo-1106")
def getContent(candidateA, candidateB) -> str:
    return (
        "Given the following two candidates, choose between the two. Here is the rubric: "
        + get_rubric()
        + "Candidate A: "
        + "\nRESUME:\n" +candidateA.resume_text+"\nEND Resume\n"
        + "\nGITHUB:\n" +candidateA.github_text+"\nEND GITHUB\n"
        + " END OF Candidate A"
        + "\n\nCandidate B: "
        + "\nRESUME:\n" +candidateB.resume_text+"\nEND Resume\n"
        + "\nGITHUB:\n" +candidateB.github_text+"\nEND GITHUB\n"
        + " END OF Candidate B"

    )



def google_compare_resumes(content:str, nameA="", nameB=""):
    choice =0
    messages=[
        {"role": "user", "content": "You are an LLM recrutier who will choose between two candidates based on an provided rubric"},
        {"role": "user", "content":         
            """
            You are an LLM recrutier who will choose between two candidates based on an provided rubric,
            you will only use bullet point and broken english instead of proper english to be more concise
            """
        },
        {"role": "assistant", "content":         
            """
            I can assist you in evaluating two candidates based on a provided rubric. 
            Provide me with the rubric or the criteria you'd like to use for the evaluation, 
            and I'll help you assess the candidates accordingly and explain myself in less that 50 words
            """
        },
        {"role": "user", "content": content}
        ]

    response =completion(model=LLM, messages=messages,max_tokens=170,)
    printc(response["choices"][0]["message"],'red')

    messages=[
        {"role": "assistant","content":str(response["choices"][0]["message"])},
        {"role": "user","content":"okay so now with just a single token select A or B, <select>choice letter goes here</select>"}
    ]
    retries=3
    while retries >0:
        response =completion(model=LLM, messages=messages,max_tokens=5,temperature=0.01)
        # printc(response,'cyan')
        html=''.join(str(response["choices"][0]["message"]['content']).split())
        if "<select>" in html:
            xml_content = f'<root>{html}</root>'
            root = ET.fromstring(xml_content)
            select_element = root.find('select')
            letter = str(select_element.text)
        else:
            letter = str(html)[0]

        
        if letter == 'A':
            printc(nameA+" wins over "+nameB,"cyan")
            return -1
        elif letter == 'B':
            printc(nameB+" wins over "+nameA,"green")
            return 1

                
        retries-=1

    

    return choice
    

def compare_resumes(content:str, nameA="", nameB=""):
    retries = 3
    choice = 0

    while retries > 0:
        try:
            response = openai.ChatCompletion.create(
                model='gpt-4-0613',
                messages=[
        {"role": "user", "content":         
            """
            You are an LLM recrutier who will choose between two candidates based on an provided rubric,
            you will only use bullet point and broken english instead of proper english to be more concise in your justification
            You will also provide args for selectCandidate
            """
        },
        {"role": "assistant", "content":         
            """
            I can assist you in evaluating two candidates based on a provided rubric. 
            Provide me with the rubric or the criteria you'd like to use for the evaluation, 
            and I'll help you assess the candidates accordingly and explain myself conscisely and will
            provide args for selectCandidate
            """
        },
        {"role": "user", "content": content}

                ],
                functions=[
                    {
                        "name": "selectCanidate",
                        "description": "choose between the two canidates",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "choice_num": {
                                    "type": "integer",
                                    "description": "1 for Candidate A is the best fit, 2 for Candidate B is the best fit",
                                    "required": ["choice_num"],
                                },
                                "justifcation": {
                                    "type": "string",
                                    "description": "justifcation for why you chose the candidate",
                                    "required": ["justifcation"],
                                },
                            }
                        },
                    }
                ],
                function_call="auto",
            )

            message = response["choices"][0]["message"]

            if message.get("function_call"):
                function_name = message["function_call"]["name"]
                function_args = json.loads(message["function_call"]["arguments"])
                choice = (int(function_args["choice_num"]))

                if function_name == "selectCanidate":
                    if choice == 1:
                        choice = -1
                        printc(nameA+" wins over "+nameB, "cyan")
                    elif choice == 2:
                        choice = 1
                        printc(nameB+" wins over "+nameA, "green")

                    printc(function_args["justifcation"], "yellow")

            break  # Break the loop if everything went well

        except Exception as e:
            printc("Error: " + str(e), "red")
            retries -= 1
            if retries == 0:
                printc("Maximum retries reached.", "red")
                return 0  # Or any other default value or error indicator

    return choice

    


def get_rubric():
    text = open("rubric.txt","r").read()
    return "\nRubric:\n" +str(text)+"\nEND Rubric\n"





def comp(candidateA:JobCandidate, candidateB:JobCandidate, rub_id:int=0 ) -> int:
    comp_table= json.load(open("comparisons.json","r"))
    tag= (candidateA.email+"#"+candidateB.email+"#"+str(rub_id))
    inv_tag= (candidateB.email+"#"+candidateA.email+"#"+str(rub_id))
    if tag in comp_table:
        if comp_table[tag]==1:
            printc(candidateA.name+" wins over "+candidateB.name,"magenta")
        elif comp_table[tag]==-1:
            printc(candidateB.name+" wins over "+candidateA.name,"magenta")

        return comp_table[tag]
    elif inv_tag in comp_table:
        if comp_table[inv_tag]==1:
            printc(candidateA.name+" wins over "+candidateB.name,"magenta")
        elif comp_table[inv_tag]==-1:
            printc(candidateB.name+" wins over "+candidateA.name,"magenta")
    else:
        choice = compare_resumes(getContent(candidateA, candidateB), candidateA.name, candidateB.name)   
        comp_table[tag]=choice
        comp_table[inv_tag]=choice*-1

        json.dump(comp_table, open("comparisons.json","w"))
        return choice


def compute_scores(candidates):
    scores = {candidate.email: 0 for candidate in candidates}
    for i, candidateA in enumerate(candidates):
        for candidateB in candidates[i+1:]:
            result = comp(candidateA, candidateB)
            scores[candidateA.email] += result
            scores[candidateB.email] -= result
    print(scores)
    return scores

def bubble_sort(candidates: list) -> list:
    scores = compute_scores(candidates)
    return sorted(candidates, key=lambda x: scores[x.email])