Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix LLM-Events Tab to Display Only Conversations Matching a filter #30

Open
wants to merge 6 commits into
base: llm-main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions frontend/src/scenes/trends/persons-modal/PersonsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ export function PersonsModal({
}

function getSessionId(event: Record<string, string>): string {
return event['$session_id'] ? event['$session_id'] : ``
return event['$session_id'] ? event['$session_id'] : `${event['id']}`
}

function processArrayInput(event: [], timestamp: any, output: string): ProcessedMessage {
Expand Down Expand Up @@ -409,10 +409,10 @@ export function ActorRow({ actor, onOpenRecording, propertiesTimelineFilter }: A
const [expanded, setExpanded] = useState(false)

const { ['$llm-events']: convs, ...remaining_props } = actor.properties
let segmentedConvs = {}
let grpConvs = {}
if (convs) {
// @ts-expect-error
segmentedConvs = preProcessEvents(convs, actor.distinct_ids[0])
grpConvs = preProcessEvents(convs, actor.distinct_ids[0])
}

const [tab, setTab] = useState('properties')
Expand Down Expand Up @@ -557,10 +557,10 @@ export function ActorRow({ actor, onOpenRecording, propertiesTimelineFilter }: A
<div className="p-2 space-y-2 font-medium mt-1">
<div className="flex justify-between items-center px-2">
<span>
{pluralize(Object.keys(segmentedConvs).length, 'matched session')}
{pluralize(Object.keys(grpConvs).length, 'matched session')}
</span>
</div>
{Object.entries(segmentedConvs).map(([sessionId, conversation], index) => (
{Object.entries(grpConvs).map(([sessionId, conversation], index) => (
<ConvRow
key={index}
convId={`Session - ${sessionId}`}
Expand All @@ -573,8 +573,8 @@ export function ActorRow({ actor, onOpenRecording, propertiesTimelineFilter }: A
metadata: Record<string, any>
}[]
}
expand={Object.keys(segmentedConvs).length === 1}
setBorder={index !== Object.keys(segmentedConvs).length - 1} // Don't set border for the last conversation
expand={Object.keys(grpConvs).length === 1}
setBorder={index !== Object.keys(grpConvs).length - 1} // Don't set border for the last conversation
/>
))}
</div>
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,10 @@ export interface CommonActorType {
/** @format date-time */
created_at: string
matched_recordings: MatchedRecording[]
/* has all sessions UUIDs that match a query filter. Used to display llm-events
Might contain event UUIDs if the event has no session UUID. Events with no session UUID are treated as sessions themselves.
*/
matched_sessions: string[]
value_at_data_point: number | null
}

Expand Down
18 changes: 18 additions & 0 deletions posthog/api/person.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,23 @@ def funnel(self, request: request.Request, **kwargs) -> response.Response:

return self._respond_with_cached_results(self.calculate_funnel_persons(request))

def filter_llm_results(self, actors: List[Person], llm_results: Dict) -> List[Dict]:
# Filters conversations by session or event UUIDs to display in the llm-events tab.

all_matched_sessions = []
for actor in actors:
all_matched_sessions.extend(actor["matched_sessions"])

filtered_results = []
for event in llm_results:
# events without $session_id prop are treated as a sessions
# since they appear as a standalone conversation in the llm-events tab
session_id = event["properties"].get("$session_id", event.get("id"))
if session_id in all_matched_sessions:
filtered_results.append(event)

return filtered_results

def extend_actors_with_llm_events(self, filter, serialized_actors, request):
from posthog.models.event.query_event_list import query_events_list
from posthog.models.event.util import ClickhouseEventSerializer
Expand Down Expand Up @@ -733,6 +750,7 @@ def extend_actors_with_llm_events(self, filter, serialized_actors, request):
query_result[0:10000],
many=True,
).data
llm_ev_result = self.filter_llm_results(serialized_actors, llm_ev_result)
serialized_actors = set_people_events(serialized_actors, llm_ev_result)

return serialized_actors
Expand Down
1 change: 1 addition & 0 deletions posthog/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ def set_people_events(s_people, s_events):
or k in ["$session_id", "input", "output"]
}
props["timestamp"] = ev["timestamp"]
props["id"] = ev["id"]
grouped_events.setdefault(person_id, []).append(props)

# set the person event list in a property
Expand Down
19 changes: 18 additions & 1 deletion posthog/queries/actor_base_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,27 @@ def add_matched_recordings_to_serialized_actors(
).values_list("session_id", flat=True)
)
session_ids_with_recordings = session_ids_with_all_recordings.difference(session_ids_with_deleted_recordings)

matched_session_ids_by_actor_id: Dict[Union[uuid.UUID, str], Set[str]] = {
actor["id"]: set() for actor in serialized_actors
}
matched_events_ids_by_actor_id: Dict[Union[uuid.UUID, str], Set[str]] = {
actor["id"]: set() for actor in serialized_actors
}
matched_recordings_by_actor_id: Dict[Union[uuid.UUID, str], List[MatchedRecording]] = {}

for row in raw_result:
actor_id = row[0]
recording_events_by_session_id: Dict[str, List[EventInfoForRecording]] = {}
if len(row) > session_events_column_index - 1:
for event in row[session_events_column_index]:
event_id = event[1]
event_session_id = event[2]
# if the event has a session ID, add it to matched_session_ids_by_actor_id
if event_session_id:
matched_session_ids_by_actor_id[actor_id].add(str(event_session_id))
else:
# else, add the event ID to matched_events_ids_by_actor_id
matched_events_ids_by_actor_id[actor_id].add(str(event_id))
if event_session_id and event_session_id in session_ids_with_recordings:
recording_events_by_session_id.setdefault(event_session_id, []).append(
EventInfoForRecording(timestamp=event[0], uuid=event[1], window_id=event[3])
Expand All @@ -215,6 +229,9 @@ def add_matched_recordings_to_serialized_actors(
serialized_actors_with_recordings = []
for actor in serialized_actors:
actor["matched_recordings"] = matched_recordings_by_actor_id[actor["id"]]
actor["matched_sessions"] = list(matched_session_ids_by_actor_id[actor["id"]]) + list(
matched_events_ids_by_actor_id[actor["id"]]
)
serialized_actors_with_recordings.append(actor)

return serialized_actors_with_recordings
Expand Down