forked from microsoft/PyRIT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconversation_analytics.py
More file actions
110 lines (86 loc) · 3.87 KB
/
Copy pathconversation_analytics.py
File metadata and controls
110 lines (86 loc) · 3.87 KB
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
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
import numpy as np
from pyrit.memory.memory_interface import MemoryInterface
from pyrit.memory.memory_models import (
ConversationMessageWithSimilarity,
EmbeddingMessageWithSimilarity,
)
class ConversationAnalytics:
"""
Handles analytics operations on conversation data, such as finding similar chat messages
based on conversation history or embedding similarity.
"""
def __init__(self, *, memory_interface: MemoryInterface) -> None:
"""
Initialize the ConversationAnalytics with a memory interface for data access.
Args:
memory_interface (MemoryInterface): An instance of MemoryInterface for accessing conversation data.
"""
self.memory_interface = memory_interface
def get_prompt_entries_with_same_converted_content(
self, *, chat_message_content: str
) -> list[ConversationMessageWithSimilarity]:
"""
Retrieve chat messages that have the same converted content.
Args:
chat_message_content (str): The content of the chat message to find similar messages for.
Returns:
list[ConversationMessageWithSimilarity]: A list of ConversationMessageWithSimilarity objects representing
the similar chat messages based on content.
"""
all_memories = self.memory_interface.get_message_pieces()
return [
ConversationMessageWithSimilarity(
score=1.0,
role=memory.api_role,
content=memory.converted_value,
metric="exact_match", # Exact match
)
for memory in all_memories
if memory.converted_value == chat_message_content
]
def get_similar_chat_messages_by_embedding(
self, *, chat_message_embedding: list[float], threshold: float = 0.8
) -> list[EmbeddingMessageWithSimilarity]:
"""
Retrieve chat messages that are similar to the given embedding based on cosine similarity.
Args:
chat_message_embedding (List[float]): The embedding of the chat message to find similar messages for.
threshold (float): The similarity threshold for considering messages as similar. Defaults to 0.8.
Returns:
List[ConversationMessageWithSimilarity]: A list of ConversationMessageWithSimilarity objects representing
the similar chat messages based on embedding similarity.
"""
all_embdedding_memory = self.memory_interface.get_all_embeddings()
similar_messages = []
target_embedding = np.array(chat_message_embedding).reshape(-1)
for memory in all_embdedding_memory:
if not hasattr(memory, "embedding") or memory.embedding is None:
continue
memory_embedding = np.array(memory.embedding).reshape(-1)
similarity_score = cosine_similarity(target_embedding, memory_embedding)
if similarity_score >= threshold:
similar_messages.append(
EmbeddingMessageWithSimilarity(
score=float(similarity_score), uuid=memory.id, metric="cosine_similarity"
)
)
return similar_messages
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
"""
Calculate the cosine similarity between two 1D vectors.
Args:
a (np.ndarray): The first vector.
b (np.ndarray): The second vector.
Returns:
float: The cosine similarity between the two 1D vectors.
Raises:
ValueError: If the input vectors are not 1D.
"""
# Ensure we are dealing with 1D vectors
if a.ndim != 1 or b.ndim != 1:
raise ValueError("Inputs must be 1D vectors")
dot_product = np.dot(a, b)
norms = np.linalg.norm(a) * np.linalg.norm(b)
return float(dot_product / norms)