kevinhug commited on
Commit
8e73b66
·
1 Parent(s): f4f1a71
Files changed (3) hide show
  1. app.py +15 -10
  2. classify.py +37 -7
  3. judge.py +89 -0
app.py CHANGED
@@ -4,7 +4,7 @@ from tool import rival_product
4
  from graphrag import reasoning
5
  from knowledge import graph
6
  from pii import derisk
7
- from classify import bucket
8
 
9
  # Define the Google Analytics script
10
  head = """
@@ -24,7 +24,7 @@ with gr.Blocks(head=head) as demo:
24
  gr.Markdown("""
25
  If you're experiencing declining market share, inefficiencies in your operations, here's how I can help:
26
  ==============
27
- Marketing/Client Experience
28
  ------------
29
  - GraphRAG: Models customer-product relationship networks for next-best-action predictions
30
  - DSPy: Optimizes cross-sell/upsell prompt variations through A/B testing
@@ -179,8 +179,10 @@ Uses customer data and behavior to craft messages that resonate with specific se
179
 
180
  with gr.Tab("Knowledge Graph"):
181
  gr.Markdown("""
182
- Objective: Explain concept in knowledge graph structured output
183
- ================================================
 
 
184
  """)
185
  in_verbatim = gr.Textbox(label="Question")
186
  out_product = gr.JSON(label="Knowledge Graph")
@@ -251,20 +253,23 @@ Allows downstream tasks (like sentiment analysis or topic modeling) to focus on
251
  """)
252
 
253
 
254
- with gr.Tab("multi class classification"):
255
  gr.Markdown("""
256
  Objective: Classify customer feedback into product bucket
257
  ================================================
 
 
 
258
  """)
259
  in_verbatim = gr.Textbox(label="Customer Feedback separate by ;")
260
- out_product = gr.Textbox(label="Classification")
261
 
262
  gr.Examples(
263
  [
264
  [
265
  """
266
- "The online portal makes managing my mortgage payments so convenient."
267
- ;"RBC offer great mortgage for my home with competitive rate thank you";
268
  "Low interest rate compared to other cards I’ve used. Highly recommend for responsible spenders.";
269
  "The mobile check deposit feature saves me so much time. Banking made easy!";
270
  "Affordable premiums with great coverage. Switched from my old provider and saved!"
@@ -273,8 +278,8 @@ Allows downstream tasks (like sentiment analysis or topic modeling) to focus on
273
  ],
274
  [in_verbatim]
275
  )
276
- btn_recommend = gr.Button("Classify")
277
- btn_recommend.click(fn=bucket, inputs=in_verbatim, outputs=out_product)
278
  gr.Markdown("""
279
  Benefits of Multi Class Classification
280
  ==================
 
4
  from graphrag import reasoning
5
  from knowledge import graph
6
  from pii import derisk
7
+ from classify import judge
8
 
9
  # Define the Google Analytics script
10
  head = """
 
24
  gr.Markdown("""
25
  If you're experiencing declining market share, inefficiencies in your operations, here's how I can help:
26
  ==============
27
+ Marketing & Client Experience
28
  ------------
29
  - GraphRAG: Models customer-product relationship networks for next-best-action predictions
30
  - DSPy: Optimizes cross-sell/upsell prompt variations through A/B testing
 
179
 
180
  with gr.Tab("Knowledge Graph"):
181
  gr.Markdown("""
182
+ Objective: Explain concept in knowledge graph structured output
183
+ =====================================
184
+ - We create query plan by breaking down into subquery
185
+ - Using those subquery to create knowledge graph
186
  """)
187
  in_verbatim = gr.Textbox(label="Question")
188
  out_product = gr.JSON(label="Knowledge Graph")
 
253
  """)
254
 
255
 
256
+ with gr.Tab("classification"):
257
  gr.Markdown("""
258
  Objective: Classify customer feedback into product bucket
259
  ================================================
260
+ - multi class classification, could have multiple label for 1 feedback
261
+ - fix classification in this use case: online banking, card, auto finance, mortgage, insurance
262
+ - LLM Judge to evaluate relevancy
263
  """)
264
  in_verbatim = gr.Textbox(label="Customer Feedback separate by ;")
265
+ out_product = gr.Textbox(label="Classification & Evaluation")
266
 
267
  gr.Examples(
268
  [
269
  [
270
  """
271
+ "The online portal makes managing my mortgage payments so convenient.";
272
+ "RBC offer great mortgage for my home with competitive rate thank you";
273
  "Low interest rate compared to other cards I’ve used. Highly recommend for responsible spenders.";
274
  "The mobile check deposit feature saves me so much time. Banking made easy!";
275
  "Affordable premiums with great coverage. Switched from my old provider and saved!"
 
278
  ],
279
  [in_verbatim]
280
  )
281
+ btn_recommend = gr.Button("Classify & Evaluation")
282
+ btn_recommend.click(fn=judge, inputs=in_verbatim, outputs=out_product)
283
  gr.Markdown("""
284
  Benefits of Multi Class Classification
285
  ==================
classify.py CHANGED
@@ -22,15 +22,13 @@ client = instructor.from_openai(
22
  ),
23
  mode=instructor.Mode.JSON,
24
  )
25
-
26
- chain_of_thought:List[str]= Field(default_factory=list, description="the chain of thought led to the prediction", examples=["Let's think step by step. the customer explicitly mention donation, and there is a tag name with donation, tag the text with donation"])
27
  """
28
- llm = 'llama-3.1-8b-instant' if os.getenv("GROQ_API_KEY") else "deepseek-r1"
29
 
30
 
31
  class Tag(BaseModel):
32
 
33
-
34
  name: str
35
  id: int= Field(..., description="id for the specific tag")
36
  confidence: float = Field(
@@ -73,10 +71,27 @@ class TagRequest(BaseModel):
73
  texts: List[str]
74
  tags: List[TagWithInstructions]
75
 
76
-
77
  class TagResponse(BaseModel):
78
  texts: List[str]
79
- predictions: List[Optional[Iterable[Tag]]]=Field(...,default_factory=list)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  sem = asyncio.Semaphore(2)
82
 
@@ -158,6 +173,19 @@ texts = """
158
  "Affordable premiums with great coverage. Switched from my old provider and saved!"
159
  """
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  def bucket(texts):
162
  texts=map(lambda t: t.strip(), texts.split(";"))
163
  request = TagRequest(texts=texts, tags=tags)
@@ -166,4 +194,6 @@ def bucket(texts):
166
  return response.model_dump_json(indent=2)
167
 
168
  if __name__=="__main__":
169
- print(bucket(texts))
 
 
 
22
  ),
23
  mode=instructor.Mode.JSON,
24
  )
 
 
25
  """
26
+ llm = 'llama-3.1-8b-instant' if os.getenv("GROQ_API_KEY") else "qwen2.5" #"gemma3:12b" #"llama3.2" #"deepseek-r1"
27
 
28
 
29
  class Tag(BaseModel):
30
 
31
+ chain_of_thought:List[str]= Field(default_factory=list, description="the chain of thought led to the prediction", examples=["Let's think step by step. the customer explicitly mention donation, and there is a tag name with donation, tag the text with donation"])
32
  name: str
33
  id: int= Field(..., description="id for the specific tag")
34
  confidence: float = Field(
 
71
  texts: List[str]
72
  tags: List[TagWithInstructions]
73
 
74
+ from judge import judge_relevance, Judgment
75
  class TagResponse(BaseModel):
76
  texts: List[str]
77
+ predictions: List[Optional[List[Tag]]]=Field(...,default_factory=list)
78
+ judgment: List[Optional[List[Judgment]]]=Field(...,default_factory=list)
79
+
80
+ async def judge(self):
81
+ for i in range(len(self.texts)):
82
+ p=self.predictions[i]
83
+ if p:
84
+ self.judgment.append(
85
+ await asyncio.gather(*[
86
+ judge_relevance(
87
+ " ".join(t.chain_of_thought),
88
+ texts[i],
89
+ t.name
90
+ ) for t in p
91
+ ])
92
+ )
93
+ else:
94
+ self.judgment.append(None)
95
 
96
  sem = asyncio.Semaphore(2)
97
 
 
173
  "Affordable premiums with great coverage. Switched from my old provider and saved!"
174
  """
175
 
176
+ def judge_response(response):
177
+ response.judge()
178
+
179
+ def judge(texts):
180
+ texts=map(lambda t: t.strip(), texts.split(";"))
181
+ request = TagRequest(texts=texts, tags=tags)
182
+
183
+ response = asyncio.run(tag_request(request))
184
+ #print(response.model_dump_json(indent=2))
185
+ asyncio.run(response.judge())
186
+ #[print(r.model_dump_json(indent=2)) for r in response]
187
+ return response.model_dump_json(indent=2)
188
+
189
  def bucket(texts):
190
  texts=map(lambda t: t.strip(), texts.split(";"))
191
  request = TagRequest(texts=texts, tags=tags)
 
194
  return response.model_dump_json(indent=2)
195
 
196
  if __name__=="__main__":
197
+ from pprint import pprint
198
+ #print(bucket(texts))
199
+ print(judge(texts))
judge.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Iterable, Optional
2
+ from pydantic import BaseModel, ValidationInfo, model_validator, Field, field_validator
3
+ import instructor
4
+ import openai
5
+ import asyncio
6
+ import os
7
+
8
+
9
+ from groq import AsyncGroq
10
+ # Initialize with API key
11
+ client = AsyncGroq(api_key=os.getenv("GROQ_API_KEY"))
12
+
13
+ # Enable instructor patches for Groq client
14
+ client = instructor.from_groq(client)
15
+
16
+ """
17
+ client = instructor.from_openai(
18
+ openai.AsyncOpenAI(
19
+ base_url="http://localhost:11434/v1",
20
+ api_key="ollama",
21
+ ),
22
+ mode=instructor.Mode.JSON,
23
+ )
24
+ """
25
+ llm = 'llama-3.1-8b-instant' if os.getenv("GROQ_API_KEY") else "qwen2.5" #"gemma3:12b" #"llama3.2" #"deepseek-r1"
26
+
27
+ class Judgment(BaseModel):
28
+ thought: str = Field(...,
29
+ description="The step-by-step reasoning process used to analyze the reasoning and the answer", examples=["Let's think step by step...context explicit stated donation, therefore answer should be donation"]
30
+ )
31
+ justification: str = Field(...,
32
+ description="Explanation for the logical judgment, detailing key factors that led to the conclusion", examples=["sound reasoning if context stated donation, it is valid and logical for answer to be donation"]
33
+ )
34
+ logical: bool = Field(...,
35
+ description="Boolean judgment indicating whether the reasoning and the answer are logical or relevant (True) or not (False)", examples=[True, False]
36
+ )
37
+
38
+ #MaybeJudgment=instructor.Maybe(Judgment)
39
+ async def judge_relevance(reasoning: str, context:str, answer: str) -> Judgment:
40
+ return await client.chat.create(
41
+ model=llm, #"gpt-4",
42
+ temperature=0.3,
43
+ max_retries=3,
44
+ messages=[
45
+ {
46
+ "role": "system",
47
+ "content": """
48
+ You are tasked with comparing a (reasoning + context) and a answer to determine if they are relevant to each other or logical in some way. Your goal is to analyze the content, context, and potential connections between the two.
49
+
50
+ To determine if the (reasoning + context) and answer are relevant or logical, please follow these steps:
51
+
52
+ 1. Carefully read and understand both the reasoning and the answer.
53
+ 2. Identify the main topic, keywords, and concepts in the (reasoning + context).
54
+ 3. Analyze the answer for any mention of these topics, keywords, or concepts in <thought> tag
55
+ 4. Consider any potential indirect connections or implications that might link the reasoning and the answer. Deductive reasoning need to be valid and sound in <justification> tag
56
+ 5. Evaluate the overall logic and soundness in both the reasoning + context that lead to the answer in <logical> tag
57
+
58
+ As you go through this process, please use a chain of thought approach. Write out your reasoning for each step inside <thought> tags.
59
+
60
+ After your analysis, provide a boolean judgment on whether the reasoning and the answer are logical or relevant to each other. Use "true" if they are logical or relevant, and "false" if they are not.
61
+
62
+ Before giving your final judgment, provide a justification for your decision. Explain the key factors that led to your conclusion.
63
+
64
+ Please ensure your analysis is thorough, impartial, and based on the content provided.
65
+ """,
66
+ },
67
+ {
68
+ "role": "user",
69
+ "content": """
70
+ Here is the question + context:
71
+
72
+ <reasoning>
73
+ {{reasoning}}
74
+ </reasoning>
75
+
76
+ <context>
77
+ {{context}}
78
+ </context>
79
+
80
+ Here is the text:
81
+ <answer>
82
+ {{answer}}
83
+ </answer>
84
+ """,
85
+ },
86
+ ],
87
+ response_model=Judgment, #(reasoning=reasoning, context=context, answer=answer)
88
+ context={"reasoning": reasoning, "context": context, "answer": answer},
89
+ )