Upload 17 files
Browse files- api.py +2 -2
- requirements.txt +2 -1
- services/__pycache__/audio_gemini.cpython-311.pyc +0 -0
- services/__pycache__/audio_whisper.cpython-311.pyc +0 -0
- services/__pycache__/text_processor.cpython-311.pyc +0 -0
- services/audio_gemini.py +14 -3
- services/audio_whisper.py +21 -5
- services/text_processor.py +27 -27
api.py
CHANGED
@@ -38,7 +38,7 @@ app.add_middleware(
|
|
38 |
async def docs():
|
39 |
return RedirectResponse(url="/docs")
|
40 |
|
41 |
-
@app.post("/audio/whisper", response_model=Dict[str,
|
42 |
async def audio_whisper(audio: UploadFile = File(...)):
|
43 |
"""
|
44 |
Transcribes and translates an audio file using OpenAI's Whisper model.
|
@@ -64,7 +64,7 @@ async def audio_whisper(audio: UploadFile = File(...)):
|
|
64 |
# Catch exceptions from the audio processing service or file reading
|
65 |
raise HTTPException(status_code=500, detail=f"Audio processing failed: {str(e)}")
|
66 |
|
67 |
-
@app.post("/audio/gemini", response_model=Dict[str,
|
68 |
async def audio_gemini(audio: UploadFile = File(...)):
|
69 |
"""
|
70 |
Receives an audio file, transcribes it, and translates the transcription
|
|
|
38 |
async def docs():
|
39 |
return RedirectResponse(url="/docs")
|
40 |
|
41 |
+
@app.post("/audio/whisper", response_model=Dict[str, Any])
|
42 |
async def audio_whisper(audio: UploadFile = File(...)):
|
43 |
"""
|
44 |
Transcribes and translates an audio file using OpenAI's Whisper model.
|
|
|
64 |
# Catch exceptions from the audio processing service or file reading
|
65 |
raise HTTPException(status_code=500, detail=f"Audio processing failed: {str(e)}")
|
66 |
|
67 |
+
@app.post("/audio/gemini", response_model=Dict[str, Any])
|
68 |
async def audio_gemini(audio: UploadFile = File(...)):
|
69 |
"""
|
70 |
Receives an audio file, transcribes it, and translates the transcription
|
requirements.txt
CHANGED
@@ -26,4 +26,5 @@ soundfile
|
|
26 |
openai-whisper
|
27 |
pydantic
|
28 |
langchain-google-genai
|
29 |
-
langchain
|
|
|
|
26 |
openai-whisper
|
27 |
pydantic
|
28 |
langchain-google-genai
|
29 |
+
langchain
|
30 |
+
tqdm
|
services/__pycache__/audio_gemini.cpython-311.pyc
CHANGED
Binary files a/services/__pycache__/audio_gemini.cpython-311.pyc and b/services/__pycache__/audio_gemini.cpython-311.pyc differ
|
|
services/__pycache__/audio_whisper.cpython-311.pyc
CHANGED
Binary files a/services/__pycache__/audio_whisper.cpython-311.pyc and b/services/__pycache__/audio_whisper.cpython-311.pyc differ
|
|
services/__pycache__/text_processor.cpython-311.pyc
CHANGED
Binary files a/services/__pycache__/text_processor.cpython-311.pyc and b/services/__pycache__/text_processor.cpython-311.pyc differ
|
|
services/audio_gemini.py
CHANGED
@@ -4,6 +4,13 @@ from typing import Dict
|
|
4 |
import google.genai as genai
|
5 |
from dotenv import load_dotenv
|
6 |
from google.genai.types import Part
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
# Load environment variables from a .env file in the root directory
|
9 |
load_dotenv()
|
@@ -59,7 +66,7 @@ def _translate_to_english(text: str) -> str:
|
|
59 |
return resp.text.strip() # type: ignore
|
60 |
|
61 |
|
62 |
-
def process_audio_with_gemini(audio_bytes: bytes) -> Dict[str,
|
63 |
"""
|
64 |
Processes an audio file by first transcribing it and then translating the
|
65 |
resulting text to English using the Gemini model.
|
@@ -84,8 +91,12 @@ def process_audio_with_gemini(audio_bytes: bytes) -> Dict[str, str]:
|
|
84 |
translation = ""
|
85 |
if transcription:
|
86 |
translation = _translate_to_english(transcription)
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
89 |
except Exception as e:
|
90 |
# Re-raise the exception with more context to be caught by the API endpoint
|
91 |
raise Exception(f"Error processing audio with Gemini: {str(e)}")
|
|
|
4 |
import google.genai as genai
|
5 |
from dotenv import load_dotenv
|
6 |
from google.genai.types import Part
|
7 |
+
from pydantic import BaseModel
|
8 |
+
|
9 |
+
from services.text_processor import process_text_to_insight
|
10 |
+
|
11 |
+
# Add the TextRequest model definition here or import it
|
12 |
+
class TextRequest(BaseModel):
|
13 |
+
text: str
|
14 |
|
15 |
# Load environment variables from a .env file in the root directory
|
16 |
load_dotenv()
|
|
|
66 |
return resp.text.strip() # type: ignore
|
67 |
|
68 |
|
69 |
+
def process_audio_with_gemini(audio_bytes: bytes) -> Dict[str, any]:
|
70 |
"""
|
71 |
Processes an audio file by first transcribing it and then translating the
|
72 |
resulting text to English using the Gemini model.
|
|
|
91 |
translation = ""
|
92 |
if transcription:
|
93 |
translation = _translate_to_english(transcription)
|
94 |
+
|
95 |
+
# Step 3: Generate insights using TextRequest object
|
96 |
+
text_request = TextRequest(text=transcription)
|
97 |
+
audio_text_insights = process_text_to_insight(text_request)
|
98 |
+
|
99 |
+
return {"transcription": transcription, "translation": translation, "insights": audio_text_insights}
|
100 |
except Exception as e:
|
101 |
# Re-raise the exception with more context to be caught by the API endpoint
|
102 |
raise Exception(f"Error processing audio with Gemini: {str(e)}")
|
services/audio_whisper.py
CHANGED
@@ -3,6 +3,12 @@ import torch
|
|
3 |
import tempfile
|
4 |
import os
|
5 |
from typing import Dict
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
# Determine the most efficient device available (CUDA if possible, otherwise CPU)
|
8 |
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
@@ -17,7 +23,7 @@ except Exception as e:
|
|
17 |
print(f"Fatal: Error loading Whisper model: {e}")
|
18 |
model = None
|
19 |
|
20 |
-
def process_audio_with_whisper(audio_bytes: bytes)
|
21 |
"""
|
22 |
Transcribes and translates a given audio file's bytes using the Whisper model.
|
23 |
|
@@ -30,7 +36,7 @@ def process_audio_with_whisper(audio_bytes: bytes) -> Dict[str, str]:
|
|
30 |
|
31 |
Returns:
|
32 |
A dictionary containing the Tagalog transcription and English translation.
|
33 |
-
Example: {"transcription": "...", "translation": "..."}
|
34 |
|
35 |
Raises:
|
36 |
ValueError: If the Whisper model was not loaded successfully.
|
@@ -67,10 +73,18 @@ def process_audio_with_whisper(audio_bytes: bytes) -> Dict[str, str]:
|
|
67 |
task="translate"
|
68 |
)
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
return {
|
71 |
-
"transcription":
|
72 |
-
"translation": translation_result.get('text', '').strip()
|
|
|
73 |
}
|
|
|
74 |
except Exception as e:
|
75 |
# Log and re-raise any exceptions to be handled by the FastAPI endpoint
|
76 |
print(f"An error occurred during Whisper processing: {e}")
|
@@ -78,4 +92,6 @@ def process_audio_with_whisper(audio_bytes: bytes) -> Dict[str, str]:
|
|
78 |
finally:
|
79 |
# Ensure the temporary file is deleted after processing
|
80 |
if 'temp_path' in locals() and os.path.exists(temp_path):
|
81 |
-
os.remove(temp_path)
|
|
|
|
|
|
3 |
import tempfile
|
4 |
import os
|
5 |
from typing import Dict
|
6 |
+
from services.text_processor import process_text_to_insight
|
7 |
+
from pydantic import BaseModel
|
8 |
+
|
9 |
+
# Add the TextRequest model definition here or import it
|
10 |
+
class TextRequest(BaseModel):
|
11 |
+
text: str
|
12 |
|
13 |
# Determine the most efficient device available (CUDA if possible, otherwise CPU)
|
14 |
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
|
|
|
23 |
print(f"Fatal: Error loading Whisper model: {e}")
|
24 |
model = None
|
25 |
|
26 |
+
def process_audio_with_whisper(audio_bytes: bytes):
|
27 |
"""
|
28 |
Transcribes and translates a given audio file's bytes using the Whisper model.
|
29 |
|
|
|
36 |
|
37 |
Returns:
|
38 |
A dictionary containing the Tagalog transcription and English translation.
|
39 |
+
Example: {"transcription": "...", "translation": "...", "insights": "..."}
|
40 |
|
41 |
Raises:
|
42 |
ValueError: If the Whisper model was not loaded successfully.
|
|
|
73 |
task="translate"
|
74 |
)
|
75 |
|
76 |
+
# Get the transcribed text
|
77 |
+
transcribed_text = transcription_result.get('text', '').strip()
|
78 |
+
|
79 |
+
insights = process_text_to_insight(transcribed_text)
|
80 |
+
|
81 |
+
|
82 |
return {
|
83 |
+
"transcription": transcribed_text,
|
84 |
+
"translation": translation_result.get('text', '').strip(),
|
85 |
+
"insights": insights
|
86 |
}
|
87 |
+
|
88 |
except Exception as e:
|
89 |
# Log and re-raise any exceptions to be handled by the FastAPI endpoint
|
90 |
print(f"An error occurred during Whisper processing: {e}")
|
|
|
92 |
finally:
|
93 |
# Ensure the temporary file is deleted after processing
|
94 |
if 'temp_path' in locals() and os.path.exists(temp_path):
|
95 |
+
os.remove(temp_path)
|
96 |
+
|
97 |
+
print("=== Debug Whisper Output ===")
|
services/text_processor.py
CHANGED
@@ -10,11 +10,11 @@ from langchain.output_parsers import OutputFixingParser
|
|
10 |
from langchain.prompts import PromptTemplate, FewShotPromptTemplate
|
11 |
from datetime import datetime
|
12 |
import time
|
|
|
13 |
|
14 |
|
15 |
import os
|
16 |
from dotenv import load_dotenv
|
17 |
-
import tqdm
|
18 |
|
19 |
# Load environment variables from a .env file in the root directory
|
20 |
load_dotenv()
|
@@ -140,39 +140,39 @@ sentiment_examples = [{'input': 'There is an unauthorized charge on my BPI Famil
|
|
140 |
# --- Pydantic Models
|
141 |
class GeneralInfo(BaseModel):
|
142 |
case_id: Optional[str] = Field(None, description="An unique identifier given to each case message")
|
143 |
-
raw_message: str = Field(None, description="The raw and unstructured form of the original message or conversation")
|
144 |
-
message_source: Literal['Email', 'Phone', 'Branch', 'Facebook'] = Field(None, description="The channel to which the text was received from")
|
145 |
customer_tier: Optional[Literal['High', 'Mid', 'Low']] = Field(None, description="The tier of the customer sending the message")
|
146 |
status: Optional[Literal['New', 'Assigned', 'Closed']] = Field(None, description="The status of the message, whether it was new, already assigned, or closed")
|
147 |
start_date: Optional[datetime] = Field(None, description="The date and time when the message was initiated or received.")
|
148 |
close_date: Optional[datetime] = Field(None, description="The date and time when the message was marked as closed or resolved.")
|
149 |
|
150 |
class TextOverview(BaseModel):
|
151 |
-
summary: str = Field(None, description="A one liner summary of the text provided. Indicates the main purpose and intention of the text. Use proper case.")
|
152 |
-
tags: List[str] = Field(None, description="A list of keywords that can be used to tag and classify the message meaningfuly. Use lowercase")
|
153 |
|
154 |
class TransactionType(BaseModel):
|
155 |
-
interaction_type: Literal['Request', 'Inquiry', 'Complaint'] = Field(None, description="The interaction type of the message, indicates whether the customer is inquiring, complaining, or requesting to the bank")
|
156 |
-
product_type: Literal['Credit Cards', 'Deposits', 'Loans'] = Field(None, description="The product that is best connected to the purpose of the message. Indicates if the message is related to Credit Cards, Deposits, or Loans")
|
157 |
|
158 |
class SentimentConfidence(BaseModel):
|
159 |
-
sentiment_tag: str = Field(None, description="The sentiment tag being assessed. Can be either 'Positivee', 'Negative', or 'Neutral")
|
160 |
sentiment_confidence_score: Optional[float] = Field(None, ge=0.0, le=1.0, description="how confident the given sentiment category is when associated with the intent of the message. Use two decimal points for the score")
|
161 |
emotional_indicators: Optional[List[str]] = Field(None, description="Bigrams or trigrams that best display the particular sentiment of the message. Use lowercase. Use 'Blank' if there is no good keyword.")
|
162 |
|
163 |
class Sentiment(BaseModel):
|
164 |
-
sentiment_category: Literal['Negative', 'Neutral', 'Positive'] = Field(None, description="the sentiment demonstrated within the message. Indicates whether the message has negative, positive, or neutral connotations")
|
165 |
sentiment_reasoning: Optional[str] = Field(None, description="A one liner that depicts main reason why the text was categorized as a certain sentiment. No need to add any emphases on keywords. Use proper case.")
|
166 |
sentiment_distribution: List[SentimentConfidence] = Field(description="A distribution that shows how likely each sentiment (Positive, Neutral, and Negative). Note that the sum of the confidence scores should be equal to 1.0 since it's a probability distribution")
|
167 |
|
168 |
class Urgency(BaseModel):
|
169 |
-
priority_category: Literal['High', 'Medium', 'Low'] = Field(None, description = "Describes how urgent a message needs to be addressed.")
|
170 |
priority_reason: Optional[str] = Field(None, description = "An explanation of why the priority level of a message is the way it is.")
|
171 |
|
172 |
class ChatLogEntry(BaseModel):
|
173 |
-
turn_id: int = Field(None, description="A number that indicates the order in which the message is found in the conversation")
|
174 |
-
speaker: Literal['Customer', 'Bank Agent', 'Chatbot'] = Field(None, description="The entity who sent the message during the specified turn")
|
175 |
-
text: str = Field(None, description="The message sent within the turn of the speaker")
|
176 |
|
177 |
class DialogueHistory(BaseModel):
|
178 |
dialogue_history: List[ChatLogEntry] = Field(
|
@@ -232,7 +232,7 @@ ctt_fewshot_prompt = FewShotPromptTemplate(
|
|
232 |
ctt_chain_fs = ctt_fewshot_prompt | llm_text_insights
|
233 |
|
234 |
ctt_chain_wrapped = RunnableLambda(lambda x: {
|
235 |
-
"text_to_classify": x["text"]
|
236 |
}) | ctt_chain_fs
|
237 |
|
238 |
|
@@ -267,8 +267,8 @@ cpl_fewshot_prompt = FewShotPromptTemplate(
|
|
267 |
cpl_chain_fs = cpl_fewshot_prompt | llm_text_insights
|
268 |
|
269 |
cpl_chain_wrapped = RunnableLambda(lambda x: {
|
270 |
-
"text_to_classify": x["text"]
|
271 |
-
}) | cpl_chain_fs | RunnableLambda(lambda x: urgency_parser.parse(x.content).model_dump_json(indent=2))
|
272 |
|
273 |
ct_prompt = PromptTemplate.from_template(
|
274 |
"""You are an expert contact center operations agent and analyst at a banking firm. Your task is to review customer messages and classify each message by selecting exactly one label from the following services/products offered by the bank: "labels": ['Credit Cards', 'Loans', 'Deposits'].
|
@@ -290,7 +290,7 @@ ct_fewshot_prompt = FewShotPromptTemplate(
|
|
290 |
ct_chain_fs = ct_fewshot_prompt | llm_text_insights
|
291 |
|
292 |
ct_chain_wrapped = RunnableLambda(lambda x: {
|
293 |
-
"text_to_classify": x["text"]
|
294 |
}) | ct_chain_fs
|
295 |
|
296 |
sentiment_prompt = PromptTemplate.from_template(
|
@@ -322,7 +322,7 @@ sentiment_fewshot_prompt = FewShotPromptTemplate(
|
|
322 |
|
323 |
sentiment_chain_fs = sentiment_fewshot_prompt | llm_text_insights
|
324 |
|
325 |
-
sentiment_chain_wrapped = RunnableLambda(lambda x: {"text_to_classify": x["text"]}) | sentiment_chain_fs | RunnableLambda(lambda x: sentiment_parser.parse(x.content).model_dump_json(indent=2))
|
326 |
|
327 |
summary_prompt = PromptTemplate.from_template(
|
328 |
"""You are an expert contact center operations agent and analyst at a banking firm.
|
@@ -336,7 +336,7 @@ summary_prompt = PromptTemplate.from_template(
|
|
336 |
summary_chain = summary_prompt | llm_text_insights
|
337 |
|
338 |
summary_chain_wrapped = RunnableLambda(lambda x: {
|
339 |
-
"text_to_summarize": x["text"]
|
340 |
}) | summary_chain
|
341 |
|
342 |
kw_prompt = PromptTemplate.from_template(
|
@@ -353,7 +353,7 @@ kw_prompt = PromptTemplate.from_template(
|
|
353 |
kw_chain = kw_prompt | llm_text_insights
|
354 |
|
355 |
kw_chain_wrapped = RunnableLambda(lambda x: {
|
356 |
-
"text_to_extract": x["text"]
|
357 |
}) | kw_chain
|
358 |
|
359 |
|
@@ -392,35 +392,35 @@ dialogue_history_prompt = PromptTemplate(
|
|
392 |
dialogue_history_chain = dialogue_history_prompt | llm_text_insights
|
393 |
|
394 |
dialogue_history_chain_wrapped = RunnableLambda(lambda x: {
|
395 |
-
"sample_text": x["text"]
|
396 |
-
}) | dialogue_history_chain | RunnableLambda(lambda x: dialogue_history_parser.parse(x.content).model_dump_json(indent=2))
|
397 |
|
398 |
|
399 |
def process_text_to_insight(text, sleep_time_req = 5):
|
400 |
try:
|
401 |
result = {}
|
402 |
|
403 |
-
result['case_transaction_type'] = ctt_chain_wrapped.invoke({'text': text}).content.strip()
|
404 |
time.sleep(sleep_time_req)
|
405 |
|
406 |
result['case_priority_level'] = cpl_chain_wrapped.invoke({'text': text})
|
407 |
time.sleep(sleep_time_req)
|
408 |
|
409 |
-
result['case_type'] = ct_chain_wrapped.invoke({'text': text}).content.strip()
|
410 |
time.sleep(sleep_time_req)
|
411 |
|
412 |
result['sentiment'] = sentiment_chain_wrapped.invoke({'text': text})
|
413 |
time.sleep(sleep_time_req)
|
414 |
|
415 |
-
result['summary'] = summary_chain_wrapped.invoke({'text': text}).content.strip()
|
416 |
time.sleep(sleep_time_req)
|
417 |
|
418 |
-
result['keywords'] = kw_chain_wrapped.invoke({'text': text}).content.strip()
|
419 |
|
420 |
result['dialogue_history'] = dialogue_history_chain_wrapped.invoke({'text': text})
|
421 |
|
422 |
except Exception as e:
|
423 |
-
tqdm.write(f"[error] Skipping row due to: {e}")
|
424 |
result = {
|
425 |
"case_text": text,
|
426 |
"case_transaction_type": None,
|
|
|
10 |
from langchain.prompts import PromptTemplate, FewShotPromptTemplate
|
11 |
from datetime import datetime
|
12 |
import time
|
13 |
+
from tqdm import tqdm
|
14 |
|
15 |
|
16 |
import os
|
17 |
from dotenv import load_dotenv
|
|
|
18 |
|
19 |
# Load environment variables from a .env file in the root directory
|
20 |
load_dotenv()
|
|
|
140 |
# --- Pydantic Models
|
141 |
class GeneralInfo(BaseModel):
|
142 |
case_id: Optional[str] = Field(None, description="An unique identifier given to each case message")
|
143 |
+
raw_message: str = Field(None, description="The raw and unstructured form of the original message or conversation")
|
144 |
+
message_source: Literal['Email', 'Phone', 'Branch', 'Facebook'] = Field(None, description="The channel to which the text was received from")
|
145 |
customer_tier: Optional[Literal['High', 'Mid', 'Low']] = Field(None, description="The tier of the customer sending the message")
|
146 |
status: Optional[Literal['New', 'Assigned', 'Closed']] = Field(None, description="The status of the message, whether it was new, already assigned, or closed")
|
147 |
start_date: Optional[datetime] = Field(None, description="The date and time when the message was initiated or received.")
|
148 |
close_date: Optional[datetime] = Field(None, description="The date and time when the message was marked as closed or resolved.")
|
149 |
|
150 |
class TextOverview(BaseModel):
|
151 |
+
summary: str = Field(None, description="A one liner summary of the text provided. Indicates the main purpose and intention of the text. Use proper case.")
|
152 |
+
tags: List[str] = Field(None, description="A list of keywords that can be used to tag and classify the message meaningfuly. Use lowercase")
|
153 |
|
154 |
class TransactionType(BaseModel):
|
155 |
+
interaction_type: Literal['Request', 'Inquiry', 'Complaint'] = Field(None, description="The interaction type of the message, indicates whether the customer is inquiring, complaining, or requesting to the bank")
|
156 |
+
product_type: Literal['Credit Cards', 'Deposits', 'Loans'] = Field(None, description="The product that is best connected to the purpose of the message. Indicates if the message is related to Credit Cards, Deposits, or Loans")
|
157 |
|
158 |
class SentimentConfidence(BaseModel):
|
159 |
+
sentiment_tag: str = Field(None, description="The sentiment tag being assessed. Can be either 'Positivee', 'Negative', or 'Neutral")
|
160 |
sentiment_confidence_score: Optional[float] = Field(None, ge=0.0, le=1.0, description="how confident the given sentiment category is when associated with the intent of the message. Use two decimal points for the score")
|
161 |
emotional_indicators: Optional[List[str]] = Field(None, description="Bigrams or trigrams that best display the particular sentiment of the message. Use lowercase. Use 'Blank' if there is no good keyword.")
|
162 |
|
163 |
class Sentiment(BaseModel):
|
164 |
+
sentiment_category: Literal['Negative', 'Neutral', 'Positive'] = Field(None, description="the sentiment demonstrated within the message. Indicates whether the message has negative, positive, or neutral connotations")
|
165 |
sentiment_reasoning: Optional[str] = Field(None, description="A one liner that depicts main reason why the text was categorized as a certain sentiment. No need to add any emphases on keywords. Use proper case.")
|
166 |
sentiment_distribution: List[SentimentConfidence] = Field(description="A distribution that shows how likely each sentiment (Positive, Neutral, and Negative). Note that the sum of the confidence scores should be equal to 1.0 since it's a probability distribution")
|
167 |
|
168 |
class Urgency(BaseModel):
|
169 |
+
priority_category: Literal['High', 'Medium', 'Low'] = Field(None, description = "Describes how urgent a message needs to be addressed.")
|
170 |
priority_reason: Optional[str] = Field(None, description = "An explanation of why the priority level of a message is the way it is.")
|
171 |
|
172 |
class ChatLogEntry(BaseModel):
|
173 |
+
turn_id: int = Field(None, description="A number that indicates the order in which the message is found in the conversation")
|
174 |
+
speaker: Literal['Customer', 'Bank Agent', 'Chatbot'] = Field(None, description="The entity who sent the message during the specified turn")
|
175 |
+
text: str = Field(None, description="The message sent within the turn of the speaker")
|
176 |
|
177 |
class DialogueHistory(BaseModel):
|
178 |
dialogue_history: List[ChatLogEntry] = Field(
|
|
|
232 |
ctt_chain_fs = ctt_fewshot_prompt | llm_text_insights
|
233 |
|
234 |
ctt_chain_wrapped = RunnableLambda(lambda x: {
|
235 |
+
"text_to_classify": x["text"]
|
236 |
}) | ctt_chain_fs
|
237 |
|
238 |
|
|
|
267 |
cpl_chain_fs = cpl_fewshot_prompt | llm_text_insights
|
268 |
|
269 |
cpl_chain_wrapped = RunnableLambda(lambda x: {
|
270 |
+
"text_to_classify": x["text"]
|
271 |
+
}) | cpl_chain_fs | RunnableLambda(lambda x: urgency_parser.parse(x.content).model_dump_json(indent=2))
|
272 |
|
273 |
ct_prompt = PromptTemplate.from_template(
|
274 |
"""You are an expert contact center operations agent and analyst at a banking firm. Your task is to review customer messages and classify each message by selecting exactly one label from the following services/products offered by the bank: "labels": ['Credit Cards', 'Loans', 'Deposits'].
|
|
|
290 |
ct_chain_fs = ct_fewshot_prompt | llm_text_insights
|
291 |
|
292 |
ct_chain_wrapped = RunnableLambda(lambda x: {
|
293 |
+
"text_to_classify": x["text"]
|
294 |
}) | ct_chain_fs
|
295 |
|
296 |
sentiment_prompt = PromptTemplate.from_template(
|
|
|
322 |
|
323 |
sentiment_chain_fs = sentiment_fewshot_prompt | llm_text_insights
|
324 |
|
325 |
+
sentiment_chain_wrapped = RunnableLambda(lambda x: {"text_to_classify": x["text"]}) | sentiment_chain_fs | RunnableLambda(lambda x: sentiment_parser.parse(x.content).model_dump_json(indent=2))
|
326 |
|
327 |
summary_prompt = PromptTemplate.from_template(
|
328 |
"""You are an expert contact center operations agent and analyst at a banking firm.
|
|
|
336 |
summary_chain = summary_prompt | llm_text_insights
|
337 |
|
338 |
summary_chain_wrapped = RunnableLambda(lambda x: {
|
339 |
+
"text_to_summarize": x["text"]
|
340 |
}) | summary_chain
|
341 |
|
342 |
kw_prompt = PromptTemplate.from_template(
|
|
|
353 |
kw_chain = kw_prompt | llm_text_insights
|
354 |
|
355 |
kw_chain_wrapped = RunnableLambda(lambda x: {
|
356 |
+
"text_to_extract": x["text"]
|
357 |
}) | kw_chain
|
358 |
|
359 |
|
|
|
392 |
dialogue_history_chain = dialogue_history_prompt | llm_text_insights
|
393 |
|
394 |
dialogue_history_chain_wrapped = RunnableLambda(lambda x: {
|
395 |
+
"sample_text": x["text"]
|
396 |
+
}) | dialogue_history_chain | RunnableLambda(lambda x: dialogue_history_parser.parse(x.content).model_dump_json(indent=2))
|
397 |
|
398 |
|
399 |
def process_text_to_insight(text, sleep_time_req = 5):
|
400 |
try:
|
401 |
result = {}
|
402 |
|
403 |
+
result['case_transaction_type'] = ctt_chain_wrapped.invoke({'text': text}).content.strip()
|
404 |
time.sleep(sleep_time_req)
|
405 |
|
406 |
result['case_priority_level'] = cpl_chain_wrapped.invoke({'text': text})
|
407 |
time.sleep(sleep_time_req)
|
408 |
|
409 |
+
result['case_type'] = ct_chain_wrapped.invoke({'text': text}).content.strip()
|
410 |
time.sleep(sleep_time_req)
|
411 |
|
412 |
result['sentiment'] = sentiment_chain_wrapped.invoke({'text': text})
|
413 |
time.sleep(sleep_time_req)
|
414 |
|
415 |
+
result['summary'] = summary_chain_wrapped.invoke({'text': text}).content.strip()
|
416 |
time.sleep(sleep_time_req)
|
417 |
|
418 |
+
result['keywords'] = kw_chain_wrapped.invoke({'text': text}).content.strip()
|
419 |
|
420 |
result['dialogue_history'] = dialogue_history_chain_wrapped.invoke({'text': text})
|
421 |
|
422 |
except Exception as e:
|
423 |
+
tqdm.write(f"[error] Skipping row due to: {e}")
|
424 |
result = {
|
425 |
"case_text": text,
|
426 |
"case_transaction_type": None,
|