theRealNG commited on
Commit
e34773c
·
1 Parent(s): 4f0e866

initial TIL v2

Browse files
Files changed (3) hide show
  1. endpoints.py +28 -4
  2. requirements.txt +1 -0
  3. workflows/til_v2.py +133 -0
endpoints.py CHANGED
@@ -1,17 +1,21 @@
1
  from dotenv import load_dotenv
2
  load_dotenv()
3
 
 
 
 
 
 
4
  from .workflows.courses.expectation_revision import ExpectationRevision, Inputs as ExpectationRevisionInputs, Response as ExpectationRevisionResponse
5
  from .workflows.courses.suggest_check_question import SuggestCheckQuestion, Inputs as SuggestCheckQuestionInputs, Response as SuggestCheckQuestionResponse
6
  from .workflows.courses.suggest_expectations import SuggestExpectations, Inputs as SuggestExpectationsInputs, Expectation, Response as SuggestExpectationsResponse
7
  from .workflows.til import TilCrew, TilFeedbackResponse
 
8
  from .workflows.utils.feedback import Feedback, post_feedback
9
- from fastapi import FastAPI, Query
10
- from fastapi.middleware.cors import CORSMiddleware
11
- from pydantic import UUID4, BaseModel
12
- from typing import List, Optional
13
  import uvicorn
14
 
 
 
15
 
16
  description = """
17
  API helps you do awesome stuff. 🚀
@@ -56,6 +60,26 @@ async def til_feedback_kickoff(content: List[str]) -> TilFeedbackResponse:
56
  return result
57
 
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  @app.post("/til_feedback/{run_id}/feedback", tags=["til_feedback"])
60
  async def capture_feedback(run_id: UUID4, feedback: Feedback) -> str:
61
  print("Metric Type: ", feedback.metric_type)
 
1
  from dotenv import load_dotenv
2
  load_dotenv()
3
 
4
+ from fastapi import FastAPI, Query
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from pydantic import UUID4
7
+ from typing import List
8
+ from tempenv import TemporaryEnvironment
9
  from .workflows.courses.expectation_revision import ExpectationRevision, Inputs as ExpectationRevisionInputs, Response as ExpectationRevisionResponse
10
  from .workflows.courses.suggest_check_question import SuggestCheckQuestion, Inputs as SuggestCheckQuestionInputs, Response as SuggestCheckQuestionResponse
11
  from .workflows.courses.suggest_expectations import SuggestExpectations, Inputs as SuggestExpectationsInputs, Expectation, Response as SuggestExpectationsResponse
12
  from .workflows.til import TilCrew, TilFeedbackResponse
13
+ from .workflows.til_v2 import TilV2, TilV2FeedbackResponse
14
  from .workflows.utils.feedback import Feedback, post_feedback
 
 
 
 
15
  import uvicorn
16
 
17
+ LANGSMITH_STAGING_PROJECT = "customer_agent"
18
+ LANGSMITH_PROD_PROJECT = "growthy-agents"
19
 
20
  description = """
21
  API helps you do awesome stuff. 🚀
 
60
  return result
61
 
62
 
63
+ def til_v2_logic(llm_model, langsmith_project, content) -> TilV2FeedbackResponse:
64
+ separator = "\n* "
65
+ content[0] = "* " + content[0]
66
+ inputs = {"content": separator.join(content)}
67
+ result = TilV2(llm_model, langsmith_project).kickoff(inputs)
68
+ return result
69
+
70
+
71
+ @app.post("/v2/til_feedback", tags=["til_feedback"])
72
+ async def til_v2_feedback_kickoff(content: List[str]) -> TilV2FeedbackResponse:
73
+ with TemporaryEnvironment({"LANGCHAIN_PROJECT": LANGSMITH_PROD_PROJECT}):
74
+ return til_v2_logic("gpt-4o", "growthy-agents", content)
75
+
76
+
77
+ @app.post("/staging/v2/til_feedback", tags=["til_feedback", "staging"])
78
+ async def til_v2_feedback_kickoff(content: List[str]) -> TilV2FeedbackResponse:
79
+ with TemporaryEnvironment({"LANGCHAIN_PROJECT": LANGSMITH_STAGING_PROJECT}):
80
+ return til_v2_logic("gpt-4o-mini", "customer_agent", content)
81
+
82
+
83
  @app.post("/til_feedback/{run_id}/feedback", tags=["til_feedback"])
84
  async def capture_feedback(run_id: UUID4, feedback: Feedback) -> str:
85
  print("Metric Type: ", feedback.metric_type)
requirements.txt CHANGED
@@ -19,5 +19,6 @@ semanticscholar
19
  streamlit
20
  streamlit-extras
21
  tavily-python
 
22
  unstructured
23
  uvicorn
 
19
  streamlit
20
  streamlit-extras
21
  tavily-python
22
+ tempenv
23
  unstructured
24
  uvicorn
workflows/til_v2.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain import callbacks
2
+ from langchain_core.messages import SystemMessage
3
+ from langchain_core.output_parsers import JsonOutputParser
4
+ from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
5
+ from langchain_openai import ChatOpenAI
6
+ from pydantic import BaseModel, Field, UUID4
7
+ from typing import List, Optional
8
+ import os
9
+ import pprint
10
+
11
+
12
+ class TilV2:
13
+
14
+ def __init__(self, llm_model, langsmith_project):
15
+ self.llm_model = llm_model
16
+ self.langsmith_project = langsmith_project
17
+
18
+ def kickoff(self, inputs={}):
19
+ print("Human Message:")
20
+ pprint.pp(inputs)
21
+ self.content = inputs["content"]
22
+ self._gather_feedback()
23
+ return self._final_call_on_feedback()
24
+
25
+ def _final_call_on_feedback(self):
26
+ final_results = []
27
+ for feedback in self.feedback_results:
28
+ print("Final analysis of:")
29
+ pprint.pp(feedback)
30
+ result = {
31
+ "til": feedback.get('til', ""),
32
+ "feedback": "not_ok",
33
+ }
34
+ if feedback["factuality_categorization"] != 'High':
35
+ result["feedback_criteria"] = "factuality_feedback"
36
+ result["reason"] = feedback["factuality_reason"]
37
+ final_results = final_results + [result]
38
+ continue
39
+
40
+ if feedback["insightful_categorization"] != 'High':
41
+ result["feedback_criteria"] = "insightful_feedback"
42
+ result["reason"] = feedback["insightful_reason"]
43
+ final_results = final_results + [result]
44
+ continue
45
+
46
+ result["feedback"] = "ok"
47
+ final_results = final_results + [result]
48
+
49
+ response = {"feedback": final_results, "run_id": self.run_id}
50
+ print("Final Results:")
51
+ pprint.pp(response)
52
+ return response
53
+
54
+ def _gather_feedback(self):
55
+ feedback_chain = self._build_feedback_chain()
56
+ pprint.pp("Analysing the TIL.....")
57
+ with callbacks.collect_runs() as cb:
58
+ self.feedback_results = feedback_chain.invoke(
59
+ {"til_content": self.content})['tils']
60
+ self.run_id = cb.traced_runs[0].id
61
+ print("Run ID: ", self.run_id)
62
+
63
+ print("Feedback: ")
64
+ pprint.pp(self.feedback_results)
65
+
66
+ def _build_feedback_chain(self):
67
+ feedback_parser = JsonOutputParser(pydantic_object=TilV2FeedbackResults)
68
+ feedback_prompt = ChatPromptTemplate.from_messages([
69
+ SystemMessage(
70
+ "You are a 'Personal TIL Reviewer' who works in a Product Engineering Services company. "
71
+ "You are an expert in writing TILs which are Insightful, Factually correct, Easy to read and grammatically correct."
72
+ "Your goal is to review user's TILs and categorize their correctness as High, Medium, or Low based on the following metrics:"
73
+ "1. Is the TIL insightful?"
74
+ "2. Is the TIL factually correct and accurate?"
75
+
76
+ "The criteria to use for assessing if they are insightful or not are:\n"
77
+ "* They TIL shouldn't just be a outright statement, it should contain even the reason on why the statement is true."
78
+ "* It should showcase the understanding of the user on the subject.\n\n"
79
+
80
+ "The criteria to use for assessing if they are factual or not are:\n"
81
+ "* They are related to facts."
82
+ "* You are able to find a source which agrees to the fact from reputable websites.\n\n"
83
+
84
+ "Give reason for your assessment in one or two sentences for each metric. "
85
+ "Evaluate each TIL in the context of all the user's TILs."
86
+ f"Formatting Instructions: {feedback_parser.get_format_instructions()}"
87
+ ),
88
+ HumanMessagePromptTemplate.from_template("{til_content}")
89
+ ])
90
+ print("Prompt: ")
91
+ pprint.pp(feedback_prompt, width=80)
92
+ llm = ChatOpenAI(model=self.llm_model, temperature=0.2)
93
+ analysis_chain = (feedback_prompt | llm | feedback_parser).with_config({
94
+ "tags": ["til"], "run_name": "Analysing TIL v2",
95
+ "metadata": {
96
+ "versoin": "v2.0.0",
97
+ "growth_activity": "til",
98
+ "env": os.environ["ENV"],
99
+ "model": self.llm_model,
100
+ }
101
+ })
102
+
103
+ return analysis_chain
104
+
105
+
106
+ class TilV2FeedbackResult(BaseModel):
107
+ til: str = Field(
108
+ description="TIL as exactly captured by the user without any modifications.")
109
+ insightful_categorization: str = Field(
110
+ description="TIL categorization as High/Medium/Low based on correctness on the insightful metric.")
111
+ insightful_reason: str = Field(
112
+ description="Reason for your assessment in one or two sentences on insightful metric for the user.")
113
+ factuality_categorization: str = Field(
114
+ description="TIL categorization as High/Medium/Low based on correctness on the factuality metric.")
115
+ factuality_reason: str = Field(
116
+ description="Reason for your assessment in one or two sentences on factuality metric for the user.")
117
+
118
+
119
+ class TilV2FeedbackResults(BaseModel):
120
+ tils: List[TilV2FeedbackResult]
121
+
122
+
123
+ class TilV2FinalFeedback(BaseModel):
124
+ til: str
125
+ feedback: str
126
+ feedback_criteria: Optional[str] = None
127
+ reason: Optional[str] = None
128
+ suggestion: Optional[str] = None
129
+
130
+
131
+ class TilV2FeedbackResponse(BaseModel):
132
+ run_id: UUID4
133
+ feedback: List[TilV2FinalFeedback]