mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-08-08 23:35:29 +00:00
fix: improve perf (#2322)
* fix: improve perf * Revert "fix: improve perf" This reverts commitf558dd431c. * Revert "fix: avoid duplicating deltas (#2321)" This reverts commitb6be07c2ae.
This commit is contained in:
@@ -19,9 +19,6 @@ from private_gpt.server.chat.interceptors.configure_tool_execution_interceptor i
|
||||
from private_gpt.server.chat.interceptors.configure_tool_interceptor import (
|
||||
ConfigureToolRequestInterceptor,
|
||||
)
|
||||
from private_gpt.server.chat.interceptors.deduplicate_event_interceptor import (
|
||||
DeduplicateEventInterceptor,
|
||||
)
|
||||
from private_gpt.server.chat.interceptors.default_values_interceptor import (
|
||||
DefaultValuesRequestInterceptor,
|
||||
)
|
||||
@@ -108,7 +105,6 @@ class ChatInterceptorService:
|
||||
# --- response interceptors (run each iteration, order matters) ---
|
||||
extract_citation_response_interceptor: ExtractCitationInterceptor,
|
||||
filter_event_by_type_interceptor: FilterZylonInterceptor,
|
||||
deduplicate_event_interceptor: DeduplicateEventInterceptor,
|
||||
) -> None:
|
||||
self._prompt_builder_service = prompt_builder_service
|
||||
|
||||
@@ -202,7 +198,6 @@ class ChatInterceptorService:
|
||||
"sanity",
|
||||
responses=[
|
||||
filter_event_by_type_interceptor,
|
||||
deduplicate_event_interceptor,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from private_gpt.components.engines.chat.interceptors.chat_interceptor import (
|
||||
ChatResponseLoopInterceptor,
|
||||
)
|
||||
from private_gpt.components.engines.chat.models.chat_interceptor_context import (
|
||||
ChatInterceptorContext,
|
||||
)
|
||||
from private_gpt.events.models import Event, PingEvent
|
||||
|
||||
|
||||
class DeduplicateEventInterceptor(ChatResponseLoopInterceptor):
|
||||
"""Drop consecutive duplicate streamed events (except pings).
|
||||
|
||||
Some providers re-emit identical ``content_block_delta`` payloads (e.g.
|
||||
``input_json_delta`` with an unchanged ``partial_json_obj``). Those
|
||||
duplicates add noise for clients without changing state, so they are
|
||||
suppressed. Ping keepalives are always forwarded.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._last_fingerprint: str | None = None
|
||||
|
||||
async def on_iteration_start(self, context: ChatInterceptorContext) -> None:
|
||||
self._last_fingerprint = None
|
||||
|
||||
async def on_iteration_end(self, context: ChatInterceptorContext) -> None:
|
||||
self._last_fingerprint = None
|
||||
|
||||
async def intercept_event(
|
||||
self,
|
||||
event: Event,
|
||||
context: ChatInterceptorContext,
|
||||
) -> Event | None:
|
||||
if isinstance(event, PingEvent):
|
||||
return event
|
||||
|
||||
fingerprint = event.model_dump_json()
|
||||
if fingerprint == self._last_fingerprint:
|
||||
return None
|
||||
|
||||
self._last_fingerprint = fingerprint
|
||||
return event
|
||||
|
||||
def model_copy(
|
||||
self, *, update: Mapping[str, Any] | None | None = None, deep: bool = False
|
||||
) -> "DeduplicateEventInterceptor":
|
||||
return DeduplicateEventInterceptor()
|
||||
@@ -55,9 +55,6 @@ from private_gpt.events.models import (
|
||||
ToolUseBlock,
|
||||
Usage,
|
||||
)
|
||||
from private_gpt.server.chat.interceptors.deduplicate_event_interceptor import (
|
||||
DeduplicateEventInterceptor,
|
||||
)
|
||||
from private_gpt.server.chat.interceptors.filter_event_by_type_interceptor import (
|
||||
FilterZylonInterceptor,
|
||||
)
|
||||
@@ -84,10 +81,7 @@ async def _collect_from_gen(
|
||||
ping_interval: float | None = None,
|
||||
) -> list:
|
||||
"""Pipe a hand-crafted event generator through the interceptor pipeline."""
|
||||
interceptors: list[ChatResponseLoopInterceptor] = [
|
||||
FilterZylonInterceptor(),
|
||||
DeduplicateEventInterceptor(),
|
||||
]
|
||||
interceptors: list[ChatResponseLoopInterceptor] = [FilterZylonInterceptor()]
|
||||
if ping_interval:
|
||||
gen = await PingEventInterceptor(ping_interval).intercept(gen)
|
||||
|
||||
@@ -146,10 +140,7 @@ def _make_engine(
|
||||
) -> ChatLoopEngine:
|
||||
llm_component = MagicMock(spec=LLMComponent)
|
||||
llm_component.get_llm.return_value = mock_llm
|
||||
interceptors: list[ChatResponseLoopInterceptor] = [
|
||||
FilterZylonInterceptor(),
|
||||
DeduplicateEventInterceptor(),
|
||||
]
|
||||
interceptors: list[ChatResponseLoopInterceptor] = [FilterZylonInterceptor()]
|
||||
return ChatLoopEngine(
|
||||
llm_component=llm_component,
|
||||
response_interceptors=interceptors,
|
||||
@@ -639,62 +630,6 @@ async def test_integration_ping_injected_between_slow_llm_chunks() -> None:
|
||||
assert sum(1 for e in events if isinstance(e, PingEvent)) >= 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unit_duplicate_content_block_deltas_are_dropped() -> None:
|
||||
"""Identical consecutive content_block_delta events are suppressed."""
|
||||
from private_gpt.events.models import InputJSONDelta
|
||||
|
||||
bid = _block_id()
|
||||
delta = InputJSONDelta(
|
||||
partial_json="",
|
||||
partial_json_obj={"object": "deals", "query": None},
|
||||
)
|
||||
|
||||
async def gen() -> AsyncGenerator:
|
||||
yield RawMessageStartEvent.from_defaults()
|
||||
yield RawContentBlockStartEvent(
|
||||
index=1,
|
||||
block_id=bid,
|
||||
content_block=ToolUseBlock(id="tool_1", name="search", input={}),
|
||||
)
|
||||
for _ in range(5):
|
||||
yield RawContentBlockDeltaEvent(
|
||||
index=1,
|
||||
block_id=bid,
|
||||
delta=delta.model_copy(deep=True),
|
||||
)
|
||||
yield RawContentBlockDeltaEvent(
|
||||
index=1,
|
||||
block_id=bid,
|
||||
delta=InputJSONDelta(
|
||||
partial_json='{"object":"deals","query":"x"}',
|
||||
partial_json_obj={"object": "deals", "query": "x"},
|
||||
),
|
||||
)
|
||||
yield RawContentBlockStopEvent(index=1, block_id=bid)
|
||||
yield RawMessageStopEvent()
|
||||
|
||||
events = await _collect_from_gen(gen())
|
||||
deltas = [e for e in events if isinstance(e, RawContentBlockDeltaEvent)]
|
||||
assert len(deltas) == 2
|
||||
assert deltas[0].delta.partial_json_obj == {"object": "deals", "query": None}
|
||||
assert deltas[1].delta.partial_json_obj == {"object": "deals", "query": "x"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unit_ping_events_are_never_deduplicated() -> None:
|
||||
"""Ping keepalives always pass through even when consecutive."""
|
||||
|
||||
async def gen() -> AsyncGenerator:
|
||||
yield PingEvent()
|
||||
yield PingEvent()
|
||||
yield PingEvent()
|
||||
|
||||
events = await _collect_from_gen(gen())
|
||||
assert len(events) == 3
|
||||
assert all(isinstance(e, PingEvent) for e in events)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Private factory helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user