Spaces:
Sleeping
Sleeping
GitHub Actions commited on
Commit ·
a09abbb
1
Parent(s): 5cae756
Deploy 698d58f
Browse files
app/pipeline/nodes/generate.py
CHANGED
|
@@ -235,6 +235,15 @@ def _format_history(state: "PipelineState") -> str:
|
|
| 235 |
return "Prior conversation (oldest first):\n" + "\n".join(lines) + "\n\n"
|
| 236 |
|
| 237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
def _merge_by_source(chunks: list) -> list[dict]:
|
| 239 |
"""
|
| 240 |
Collapse chunks that share the same source_url + section (or source_title
|
|
@@ -448,6 +457,7 @@ def make_generate_node(llm_client: LLMClient, gemini_client=None) -> Callable[[P
|
|
| 448 |
)
|
| 449 |
)
|
| 450 |
context_block_enum = "\n\n".join(enum_context_parts)
|
|
|
|
| 451 |
prompt_enum = f"Items fetched from database:\n{context_block_enum}\n\nVisitor request: {query}"
|
| 452 |
stream = llm_client.complete_with_complexity(
|
| 453 |
prompt=prompt_enum,
|
|
@@ -497,6 +507,7 @@ def make_generate_node(llm_client: LLMClient, gemini_client=None) -> Callable[[P
|
|
| 497 |
)
|
| 498 |
|
| 499 |
context_block = "\n\n".join(context_parts)
|
|
|
|
| 500 |
|
| 501 |
history_prefix = _format_history(state)
|
| 502 |
is_criticism = state.get("is_criticism", False)
|
|
|
|
| 235 |
return "Prior conversation (oldest first):\n" + "\n".join(lines) + "\n\n"
|
| 236 |
|
| 237 |
|
| 238 |
+
def _numbered_sources_event(source_refs: list[SourceRef]) -> dict:
|
| 239 |
+
"""
|
| 240 |
+
The sources the streamed answer's [n] markers count from 1 in, sent before its first token.
|
| 241 |
+
Retrieval's sources event lists chunks before they are merged by document, and the done
|
| 242 |
+
event's list is renumbered for the stored answer, so neither matches the streamed words.
|
| 243 |
+
"""
|
| 244 |
+
return {"type": "sources", "sources": [ref.model_dump() for ref in source_refs]}
|
| 245 |
+
|
| 246 |
+
|
| 247 |
def _merge_by_source(chunks: list) -> list[dict]:
|
| 248 |
"""
|
| 249 |
Collapse chunks that share the same source_url + section (or source_title
|
|
|
|
| 457 |
)
|
| 458 |
)
|
| 459 |
context_block_enum = "\n\n".join(enum_context_parts)
|
| 460 |
+
writer(_numbered_sources_event(source_refs))
|
| 461 |
prompt_enum = f"Items fetched from database:\n{context_block_enum}\n\nVisitor request: {query}"
|
| 462 |
stream = llm_client.complete_with_complexity(
|
| 463 |
prompt=prompt_enum,
|
|
|
|
| 507 |
)
|
| 508 |
|
| 509 |
context_block = "\n\n".join(context_parts)
|
| 510 |
+
writer(_numbered_sources_event(source_refs))
|
| 511 |
|
| 512 |
history_prefix = _format_history(state)
|
| 513 |
is_criticism = state.get("is_criticism", False)
|
tests/test_generate_numbered_sources.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from unittest.mock import patch
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from app.pipeline.nodes.generate import make_generate_node
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _chunk(title: str, url: str, text: str) -> dict:
|
| 9 |
+
return {
|
| 10 |
+
"text": text,
|
| 11 |
+
"metadata": {"source_title": title, "source_url": url, "section": "Overview", "source_type": "github_readme", "doc_id": title.lower(), "chunk_index": 0},
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class _StreamingLLM:
|
| 16 |
+
suggests_follow_ups = True
|
| 17 |
+
|
| 18 |
+
def __init__(self) -> None:
|
| 19 |
+
self.prompt = ""
|
| 20 |
+
|
| 21 |
+
async def complete_with_complexity(self, prompt, system, stream, complexity):
|
| 22 |
+
self.prompt = prompt
|
| 23 |
+
yield "Cortex maps a codebase into a graph [2]."
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@pytest.mark.asyncio
|
| 27 |
+
async def test_streamed_citations_count_in_the_sources_sent_before_the_answer():
|
| 28 |
+
# Two chunks of one document share a number in the prompt, so Cortex is [2], not [3].
|
| 29 |
+
chunks = [
|
| 30 |
+
_chunk("AimBuddy", "https://github.com/1337Xcode/AimBuddy", "AimBuddy tracks targets on Android in real time."),
|
| 31 |
+
_chunk("AimBuddy", "https://github.com/1337Xcode/AimBuddy", "It runs a YOLO model on the phone's GPU through NCNN."),
|
| 32 |
+
_chunk("Cortex", "https://github.com/1337Xcode/Cortex", "Cortex maps a codebase into a SQLite graph for coding agents."),
|
| 33 |
+
]
|
| 34 |
+
events: list[dict] = []
|
| 35 |
+
llm = _StreamingLLM()
|
| 36 |
+
|
| 37 |
+
with patch("app.pipeline.nodes.generate.get_stream_writer", return_value=events.append):
|
| 38 |
+
await make_generate_node(llm)({"query": "What is Cortex?", "reranked_chunks": chunks, "query_complexity": "simple"})
|
| 39 |
+
|
| 40 |
+
kinds = [event["type"] for event in events]
|
| 41 |
+
[sources] = [event["sources"] for event in events if event["type"] == "sources"]
|
| 42 |
+
assert [source["title"] for source in sources] == ["AimBuddy", "Cortex"]
|
| 43 |
+
assert "[2] Cortex" in llm.prompt
|
| 44 |
+
assert kinds.index("sources") < kinds.index("token")
|
tests/test_site_profile.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
ROOT = Path(__file__).resolve().parents[2]
|
| 5 |
+
if str(ROOT) not in sys.path:
|
| 6 |
+
sys.path.insert(0, str(ROOT))
|
| 7 |
+
|
| 8 |
+
from ingestion.site_profile import profile_documents
|
| 9 |
+
|
| 10 |
+
LLMS_TXT = """# Darshan Chheda
|
| 11 |
+
|
| 12 |
+
> London-based software engineer.
|
| 13 |
+
|
| 14 |
+
## Availability
|
| 15 |
+
Open to software engineering roles in the UK
|
| 16 |
+
|
| 17 |
+
## Links
|
| 18 |
+
- [Website](https://www.darshanchheda.com): Canonical portfolio and profile
|
| 19 |
+
- [Email](mailto:me@darshanchheda.com): Direct contact
|
| 20 |
+
- [GitHub](https://github.com/1337XCode)
|
| 21 |
+
- [LinkedIn](https://linkedin.com/in/darshchheda)
|
| 22 |
+
|
| 23 |
+
## Pages
|
| 24 |
+
- [Photos](https://www.darshanchheda.com/photos): Photographs.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_the_page_is_one_profile_and_each_off_site_profile_its_own_document() -> None:
|
| 29 |
+
documents = profile_documents(LLMS_TXT)
|
| 30 |
+
|
| 31 |
+
assert [(d["title"], d["url"], d["slug"]) for d in documents] == [
|
| 32 |
+
("darshanchheda.com", "https://www.darshanchheda.com/", "site-profile"),
|
| 33 |
+
("GitHub", "https://github.com/1337XCode", "profile-github"),
|
| 34 |
+
("LinkedIn", "https://linkedin.com/in/darshchheda", "profile-linkedin"),
|
| 35 |
+
]
|
| 36 |
+
assert "Open to software engineering roles in the UK" in documents[0]["clean_content"]
|
| 37 |
+
assert documents[2]["clean_content"].endswith("https://linkedin.com/in/darshchheda")
|
| 38 |
+
assert len(documents[2]["clean_content"].split()) >= 8
|