edgenote 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edgenote/__init__.py +113 -0
- edgenote/__main__.py +144 -0
- edgenote/chunker.py +565 -0
- edgenote/compressor.py +220 -0
- edgenote/downloader.py +278 -0
- edgenote/integrations.py +240 -0
- edgenote/reranker.py +516 -0
- edgenote/session.py +402 -0
- edgenote/style.py +45 -0
- edgenote/tokenizers.py +350 -0
- edgenote/tokens.py +17 -0
- edgenote-0.1.0.dist-info/METADATA +275 -0
- edgenote-0.1.0.dist-info/RECORD +16 -0
- edgenote-0.1.0.dist-info/WHEEL +4 -0
- edgenote-0.1.0.dist-info/entry_points.txt +2 -0
- edgenote-0.1.0.dist-info/licenses/LICENSE +18 -0
edgenote/__init__.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""edgenote — place important notes at the edges of your LLM prompts.
|
|
2
|
+
|
|
3
|
+
Addresses the "lost in the middle" attention problem (Liu et al., 2023) by
|
|
4
|
+
pinning key information at the *head* and *tail* of the assembled prompt while
|
|
5
|
+
keeping bulk context in the middle. No LLM calls, no disk persistence.
|
|
6
|
+
|
|
7
|
+
**100% zero-dependency core** — sentence-transformers, tiktoken, transformers,
|
|
8
|
+
and other heavy libraries are imported *dynamically* only when you explicitly
|
|
9
|
+
use a backend that requires them.
|
|
10
|
+
|
|
11
|
+
Basic usage::
|
|
12
|
+
|
|
13
|
+
from edgenote import Session
|
|
14
|
+
|
|
15
|
+
s = Session()
|
|
16
|
+
s.pin("Budget is $500")
|
|
17
|
+
s.add("Doc A: project overview …", relevance=0.9)
|
|
18
|
+
s.add("Doc B: cost breakdown …", relevance=0.4)
|
|
19
|
+
|
|
20
|
+
result = s.render("Which option fits the budget?")
|
|
21
|
+
print(result.text)
|
|
22
|
+
|
|
23
|
+
# Or turn it into an API-ready message list:
|
|
24
|
+
messages = result.to_messages()
|
|
25
|
+
|
|
26
|
+
Advanced — zero-dep backends (always available)::
|
|
27
|
+
|
|
28
|
+
from edgenote import Session
|
|
29
|
+
from edgenote.reranker import BM25Reranker, TFIDFReranker
|
|
30
|
+
from edgenote.chunker import StructuralChunker
|
|
31
|
+
from edgenote.tokenizers import RegexTokenizer
|
|
32
|
+
|
|
33
|
+
s = Session(reranker=BM25Reranker()) # pure Python BM25
|
|
34
|
+
s = Session(reranker=TFIDFReranker()) # pure Python TF-IDF cosine
|
|
35
|
+
s = Session(token_counter=RegexTokenizer()) # BPE-approximate counter
|
|
36
|
+
|
|
37
|
+
chunker = StructuralChunker(max_tokens=256) # Markdown-aware, zero-dep
|
|
38
|
+
chunks = chunker.chunk(long_markdown_doc)
|
|
39
|
+
|
|
40
|
+
Advanced — optional heavy backends (dynamically loaded)::
|
|
41
|
+
|
|
42
|
+
from edgenote import Session
|
|
43
|
+
from edgenote.tokenizers import auto_tokenizer
|
|
44
|
+
from edgenote.integrations import from_langchain, from_llamaindex, from_dicts
|
|
45
|
+
|
|
46
|
+
# Real token counting (always available, tiktoken & transformers auto-installed)
|
|
47
|
+
s = Session(token_counter="gpt-4o")
|
|
48
|
+
|
|
49
|
+
# Semantic reranking — requires: pip install edgenote[rerank]
|
|
50
|
+
s = Session(reranker="cross-encoder") # CrossEncoderReranker
|
|
51
|
+
s = Session(reranker="embedding") # EmbeddingReranker
|
|
52
|
+
|
|
53
|
+
# Semantic chunking — requires: pip install edgenote[chunker]
|
|
54
|
+
s = Session(chunker="semantic")
|
|
55
|
+
|
|
56
|
+
# LLM-based context compression
|
|
57
|
+
s = Session(compressor=my_summarize_fn)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
from .session import Rendered, Session
|
|
61
|
+
from .style import Style
|
|
62
|
+
from .tokens import estimate_tokens
|
|
63
|
+
from .tokenizers import auto_tokenizer, CharEstimator, RegexTokenizer, TokenCounter
|
|
64
|
+
from .reranker import (
|
|
65
|
+
Reranker,
|
|
66
|
+
NoopReranker,
|
|
67
|
+
BM25Reranker,
|
|
68
|
+
TFIDFReranker,
|
|
69
|
+
CrossEncoderReranker,
|
|
70
|
+
EmbeddingReranker,
|
|
71
|
+
)
|
|
72
|
+
from .compressor import Compressor, DropCompressor, LLMSummarizer
|
|
73
|
+
from .chunker import Chunker, FixedChunker, StructuralChunker, SemanticChunker
|
|
74
|
+
from .downloader import set_auto_install
|
|
75
|
+
from . import integrations
|
|
76
|
+
|
|
77
|
+
__all__ = [
|
|
78
|
+
# Core
|
|
79
|
+
"Session",
|
|
80
|
+
"Rendered",
|
|
81
|
+
"Style",
|
|
82
|
+
# Tokenizers
|
|
83
|
+
"auto_tokenizer",
|
|
84
|
+
"CharEstimator",
|
|
85
|
+
"RegexTokenizer",
|
|
86
|
+
"TokenCounter",
|
|
87
|
+
"estimate_tokens",
|
|
88
|
+
# Rerankers (zero-dep)
|
|
89
|
+
"Reranker",
|
|
90
|
+
"NoopReranker",
|
|
91
|
+
"BM25Reranker",
|
|
92
|
+
"TFIDFReranker",
|
|
93
|
+
# Rerankers (optional heavy, dynamically loaded)
|
|
94
|
+
"CrossEncoderReranker",
|
|
95
|
+
"EmbeddingReranker",
|
|
96
|
+
# Compressors
|
|
97
|
+
"Compressor",
|
|
98
|
+
"DropCompressor",
|
|
99
|
+
"LLMSummarizer",
|
|
100
|
+
# Chunkers (zero-dep)
|
|
101
|
+
"Chunker",
|
|
102
|
+
"FixedChunker",
|
|
103
|
+
"StructuralChunker",
|
|
104
|
+
# Chunkers (optional heavy, dynamically loaded)
|
|
105
|
+
"SemanticChunker",
|
|
106
|
+
# Auto-installer
|
|
107
|
+
"set_auto_install",
|
|
108
|
+
# Integrations
|
|
109
|
+
"integrations",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
__version__ = "0.1.0"
|
|
113
|
+
__author__ = "Md Tareq Shah Alam"
|
edgenote/__main__.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
edgenote CLI entry point.
|
|
3
|
+
Run with:
|
|
4
|
+
edgenote
|
|
5
|
+
python -m edgenote
|
|
6
|
+
python -m edgenote --demo
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from edgenote import Session, Style, __version__
|
|
11
|
+
|
|
12
|
+
# ANSI escape codes for stylish terminal styling
|
|
13
|
+
CYAN = "\033[96m"
|
|
14
|
+
MAGENTA = "\033[95m"
|
|
15
|
+
GREEN = "\033[92m"
|
|
16
|
+
YELLOW = "\033[93m"
|
|
17
|
+
BOLD = "\033[1m"
|
|
18
|
+
DIM = "\033[2m"
|
|
19
|
+
RESET = "\033[0m"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
BANNER = f"""{CYAN}{BOLD}
|
|
23
|
+
____ _ _
|
|
24
|
+
/ __ \\ | | | |
|
|
25
|
+
| | | || | __ _ ___ _ __ | |_ ___
|
|
26
|
+
| | | || | / _` | / _ \\| '_ \\ | __/ _ \\
|
|
27
|
+
| |__| || | | (_| || __/| | | | | || __/
|
|
28
|
+
\\____/ |_| \\__, | \\___||_| |_| \\__\\___|
|
|
29
|
+
__/ |
|
|
30
|
+
|___/
|
|
31
|
+
{MAGENTA} * Prompt Edge-Pinning Framework for LLMs *{RESET}
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
LINKEDIN_URL = "https://www.linkedin.com/in/md-tareq-shah-alam/"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def make_hyperlink(url: str, text: str) -> str:
|
|
39
|
+
"""Wrap text in an OSC 8 terminal hyperlink escape sequence."""
|
|
40
|
+
return f"\033]8;;{url}\033\\{text}\033]8;;\033\\"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def print_banner() -> None:
|
|
44
|
+
print(BANNER)
|
|
45
|
+
author_text = f"{YELLOW}{BOLD}Md Tareq Shah Alam{RESET}"
|
|
46
|
+
author_linked = make_hyperlink(LINKEDIN_URL, author_text)
|
|
47
|
+
linkedin_text = f"{CYAN}{LINKEDIN_URL}{RESET}"
|
|
48
|
+
linkedin_linked = make_hyperlink(LINKEDIN_URL, linkedin_text)
|
|
49
|
+
|
|
50
|
+
print(f" {BOLD}Package :{RESET} {CYAN}edgenote{RESET}")
|
|
51
|
+
print(f" {BOLD}Version :{RESET} {GREEN}v{__version__}{RESET}")
|
|
52
|
+
print(f" {BOLD}Author :{RESET} {author_linked}")
|
|
53
|
+
print(f" {BOLD}LinkedIn :{RESET} {linkedin_linked}")
|
|
54
|
+
print(f" {BOLD}License :{RESET} Proprietary (All Rights Reserved)")
|
|
55
|
+
print(f" {BOLD}Purpose :{RESET} Fight 'Lost in the Middle' attention degradation")
|
|
56
|
+
print()
|
|
57
|
+
print(f" {DIM}-------------------------------------------------------------{RESET}")
|
|
58
|
+
print()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def run_demo() -> None:
|
|
62
|
+
print(f" {BOLD}{MAGENTA}[ Live Demonstration ]{RESET}\n")
|
|
63
|
+
|
|
64
|
+
s = Session(style=Style(
|
|
65
|
+
head_title="Key Constraints (Read First)",
|
|
66
|
+
tail_title="Key Constraints (Reminder)",
|
|
67
|
+
body_title="Retrieved Knowledge",
|
|
68
|
+
question_label="Query",
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
# 1. Edge-pinned note
|
|
72
|
+
s.pin("The total hardware budget is strictly capped at $185,000.", label="Budget Cap")
|
|
73
|
+
|
|
74
|
+
# 2. Context chunks
|
|
75
|
+
s.add("Server Hall cooling upgrade proposal: Tier-3 standard liquid loop.", relevance=0.7)
|
|
76
|
+
s.add("Vendor A quotation: 64-chip acceleration cluster at $240,000.", relevance=0.9)
|
|
77
|
+
s.add("Vendor B quotation: 48-chip acceleration cluster at $180,000.", relevance=0.85)
|
|
78
|
+
|
|
79
|
+
result = s.render("Which vendor quotation qualifies under our budget?")
|
|
80
|
+
|
|
81
|
+
print(f"{YELLOW}{BOLD}Prompt Rendered by edgenote:{RESET}\n")
|
|
82
|
+
print(f"{DIM}{'-' * 60}{RESET}")
|
|
83
|
+
print(result.user_text)
|
|
84
|
+
print(f"{DIM}{'-' * 60}{RESET}\n")
|
|
85
|
+
print(f" {GREEN}[+] Token estimate :{RESET} ~{result.tokens} tokens")
|
|
86
|
+
print(f" {GREEN}[+] Pin overhead :{RESET} +{result.pin_overhead} tokens")
|
|
87
|
+
print(f" {GREEN}[+] Status :{RESET} Both head & tail edges fortified against attention loss.\n")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def main() -> None:
|
|
91
|
+
args = sys.argv[1:]
|
|
92
|
+
|
|
93
|
+
if args and args[0] == "install":
|
|
94
|
+
from edgenote.downloader import EXTRAS, install
|
|
95
|
+
venv_path, positional, i = None, [], 1
|
|
96
|
+
while i < len(args):
|
|
97
|
+
a = args[i]
|
|
98
|
+
if a == "--venv":
|
|
99
|
+
if i + 1 >= len(args):
|
|
100
|
+
print("--venv requires a path"); sys.exit(1)
|
|
101
|
+
venv_path = args[i + 1]; i += 2; continue
|
|
102
|
+
if a.startswith("--venv="):
|
|
103
|
+
venv_path = a.split("=", 1)[1]
|
|
104
|
+
elif not a.startswith("-"):
|
|
105
|
+
positional.append(a)
|
|
106
|
+
i += 1
|
|
107
|
+
extra = positional[0] if positional else "all"
|
|
108
|
+
if extra not in EXTRAS:
|
|
109
|
+
print(f"Unknown extra. Choose from: {', '.join(EXTRAS)}"); sys.exit(1)
|
|
110
|
+
confirm = "--yes" not in args
|
|
111
|
+
break_sys = "--break-system-packages" in args
|
|
112
|
+
sys.exit(0 if install(extra, confirm=confirm, break_system_packages=break_sys, venv_path=venv_path) else 1)
|
|
113
|
+
|
|
114
|
+
if "--version" in args or "-v" in args:
|
|
115
|
+
author_linked = make_hyperlink(LINKEDIN_URL, "Md Tareq Shah Alam")
|
|
116
|
+
print(f"edgenote v{__version__} by {author_linked} ({LINKEDIN_URL})")
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
if "--help" in args or "-h" in args:
|
|
120
|
+
print_banner()
|
|
121
|
+
print("Usage:")
|
|
122
|
+
print(" edgenote Show credits and quick usage")
|
|
123
|
+
print(" edgenote install [extra] [--venv PATH] [--yes] Install optional extras (rerank, chunker, regex, all)")
|
|
124
|
+
print(" edgenote --demo Run an interactive edge-pinning prompt demo")
|
|
125
|
+
print(" edgenote --version Show version and author info")
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
print_banner()
|
|
129
|
+
|
|
130
|
+
if "--demo" in args:
|
|
131
|
+
run_demo()
|
|
132
|
+
else:
|
|
133
|
+
print(f" {BOLD}Quick Start:{RESET}")
|
|
134
|
+
print(f" {CYAN}from edgenote import Session{RESET}")
|
|
135
|
+
print(f" {CYAN}s = Session(){RESET}")
|
|
136
|
+
print(f" {CYAN}s.pin('Budget is strictly $185,000', label='Constraint'){RESET}")
|
|
137
|
+
print(f" {CYAN}s.add('Doc 1: details ...', relevance=0.9){RESET}")
|
|
138
|
+
print(f" {CYAN}res = s.render('Which option fits?'){RESET}")
|
|
139
|
+
print()
|
|
140
|
+
print(f" {DIM}Run {RESET}{GREEN}python -m edgenote --demo{RESET}{DIM} to see prompt assembly in action.{RESET}\n")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
main()
|