File size: 7,926 Bytes
0413dd6
7ec107d
 
3f49c4a
 
7ec107d
3f49c4a
7ec107d
adcb9db
888953a
7ec107d
3f49c4a
0413dd6
3f49c4a
 
adcb9db
 
3f49c4a
 
 
 
 
514a39a
 
 
 
 
 
3f49c4a
 
7ec107d
514a39a
 
 
 
3f49c4a
7ec107d
514a39a
 
 
 
3f49c4a
7ec107d
514a39a
 
 
 
 
3f49c4a
7ec107d
514a39a
 
 
 
 
 
 
 
3f49c4a
0413dd6
514a39a
adcb9db
 
3f49c4a
 
 
ec4a7eb
adcb9db
0413dd6
 
 
 
adcb9db
ec4a7eb
514a39a
3f49c4a
7ec107d
 
0413dd6
 
7ec107d
 
 
 
 
0413dd6
 
7ec107d
 
 
3f49c4a
514a39a
3f49c4a
 
7ec107d
 
 
3f49c4a
514a39a
3f49c4a
7ec107d
 
 
 
 
 
 
 
 
3f49c4a
7ec107d
 
3f49c4a
 
 
 
ec4a7eb
 
888953a
 
 
0413dd6
5dc54c6
888953a
 
 
 
 
3f49c4a
 
 
 
 
0413dd6
 
7ec107d
 
0413dd6
 
7ec107d
 
0413dd6
 
7ec107d
 
0413dd6
 
7ec107d
 
0413dd6
 
3f49c4a
7ec107d
514a39a
 
 
 
adcb9db
0413dd6
adcb9db
 
 
 
 
 
 
0413dd6
adcb9db
 
 
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
from langchain import callbacks, hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_community.tools.tavily_search import TavilyAnswer
from langchain_core.messages import SystemMessage
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field, UUID4
from typing import List, Optional
import os
import pprint


class TilCrew:
    def kickoff(self, inputs={}):
        print("Human Message:")
        pprint.pp(inputs)
        self.content = inputs["content"]
        self._gather_feedback()
        return self._final_call_on_feedback()

    def _final_call_on_feedback(self):
        final_results = []
        for feedback in self.feedback_results:
            print("Final analysis of:")
            pprint.pp(feedback)
            result = {
                "til": feedback.get('til', ""),
                "feedback": "not_ok",
            }
            if feedback["factuality_categorization"] != 'High':
                result["feedback_criteria"] = "factuality_feedback"
                result["reason"] = feedback["factuality_reason"]
                final_results = final_results + [result]
                continue

            if feedback["insightful_categorization"] != 'High':
                result["feedback_criteria"] = "insightful_feedback"
                result["reason"] = feedback["insightful_reason"]
                final_results = final_results + [result]
                continue

            if feedback["simplicity_categorization"] == 'Low':
                result["feedback_criteria"] = "simplicity_feedback"
                result["reason"] = feedback["simplicity_reason"]
                result["suggestion"] = feedback["final_suggestion"]
                final_results = final_results + [result]
                continue

            if feedback["grammatical_categorization"] == 'Low':
                result["feedback_criteria"] = "grammatical_feedback"
                result["reason"] = feedback["grammatical_reason"]
                result["suggestion"] = feedback["final_suggestion"]
                final_results = final_results + [result]
                continue

            result["feedback"] = "ok"
            final_results = final_results + [result]

        response = {"feedback": final_results, "run_id": self.run_id}
        print("Final Results:")
        pprint.pp(response)
        return response

    def _gather_feedback(self):
        feedback_chain = self._build_feedback_chain()
        pprint.pp("Analysing the TIL.....")
        with callbacks.collect_runs() as cb:
            self.feedback_results = feedback_chain.invoke(
                {"til_content": self.content})['tils']
            self.run_id = cb.traced_runs[0].id
            print("Run ID: ", self.run_id)

        print("Feedback: ")
        pprint.pp(self.feedback_results)

    # Deprecated: Not using this as we are getting similar results by using or without using this
    def _gather_facts(self):
        facts_prompt = PromptTemplate.from_template(
            "What are the facts on the topics mentioned the following user's TILs: {content}")
        tools = [TavilyAnswer()]
        llm = ChatOpenAI(model=os.environ['OPENAI_MODEL'], temperature=0.2)
        prompt = hub.pull("hwchase17/react")
        agent = create_react_agent(llm, tools, prompt)
        agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
        self.facts = agent_executor.invoke(
            {"input": facts_prompt.format(content=self.content)})['output']
        print("Gathered Facts: ")
        pprint.pp(self.facts)

    def _build_feedback_chain(self):
        feedback_parser = JsonOutputParser(pydantic_object=TilFeedbackResults)
        feedback_prompt = ChatPromptTemplate.from_messages([
            SystemMessage(
                "You are a 'Personal TIL Reviewer' who works in a Product Engineering Services company. "
                "You are an expert in writing TILs which are Insightful, Factually correct, Easy to read and grammatically correct."
                "Your goal is to review user's TILs and categorize their correctness as High, Medium, or Low based on the following metrics:"
                "1. Is the TIL insightful?"
                "2. Is the TIL factually correct and accurate?"
                "3. Is the TIL written in simple english?"
                "4. Is the TIL grammatically correct?\n\n"

                "The criteria to use for assessing if they are insightful or not are:\n"
                "* They TIL shouldn't just be a outright statement, it should contain even the reason on why the statement is true."
                "* It should showcase the understanding of the user on the subject.\n\n"

                "The criteria to use for assessing if they are factual or not are:\n"
                "* They are related to facts."
                "* You are able to find a source which agrees to the fact from reputable websites.\n\n"

                "Give reason for your assessment in one or two sentences for each metric and And also rewrite the TIL if you were given the option to write it. "
                "Evaluate each TIL in the context of all the user's TILs."
                f"Formatting Instructions: {feedback_parser.get_format_instructions()}"
            ),
            HumanMessagePromptTemplate.from_template("{til_content}")
        ])
        print("Prompt: ")
        pprint.pp(feedback_prompt, width=80)
        llm = ChatOpenAI(model=os.environ['OPENAI_MODEL'], temperature=0.2)
        analysis_chain = (feedback_prompt | llm | feedback_parser).with_config({
            "tags": ["til"], "run_name": "Analysing TIL",
            "metadata": {
                "version": "v1.0.0",
                "growth_activity": "til",
                "env": os.environ["ENV"],
                "model": os.environ["OPENAI_MODEL"],
            }
        })

        return analysis_chain


class TilFeedbackResult(BaseModel):
    til: str = Field(
        description="TIL as exactly captured by the user without any modifications.")
    insightful_categorization: str = Field(
        description="TIL categorization as High/Medium/Low based on correctness on the insightful metric.")
    insightful_reason: str = Field(
        description="Reason for your assessment in one or two sentences on insightful metric for the user.")
    factuality_categorization: str = Field(
        description="TIL categorization as High/Medium/Low based on correctness on the factuality metric.")
    factuality_reason: str = Field(
        description="Reason for your assessment in one or two sentences on factuality metric for the user.")
    simplicity_categorization: str = Field(
        description="TIL categorization as High/Medium/Low based on correctness on the simplicity metric.")
    simplicity_reason: str = Field(
        description="Reason for your assessment in one or two sentences on simplicity metric for the user.")
    grammatical_categorization: str = Field(
        description="TIL categorization as High/Medium/Low based on correctness on the grammatical metric.")
    grammatical_reason: str = Field(
        description="Reason for your assessment in one or two sentences on grammatical metric for the user.")
    final_suggestion: str = Field(
        description="Rewrite the TIL if you were given the option to write it which should score High on all the metrics.")


class TilFeedbackResults(BaseModel):
    tils: List[TilFeedbackResult]


class TilFinalFeedback(BaseModel):
    til: str
    feedback: str
    feedback_criteria: Optional[str] = None
    reason: Optional[str] = None
    suggestion: Optional[str] = None


class TilFeedbackResponse(BaseModel):
    run_id: UUID4
    feedback: List[TilFinalFeedback]