wchen22 commited on
Commit
7e2d8b7
·
verified ·
1 Parent(s): 63799d5

Update managed compression API

Browse files
Files changed (2) hide show
  1. .app.py.swp +0 -0
  2. app.py +226 -23
.app.py.swp ADDED
Binary file (16.4 kB). View file
 
app.py CHANGED
@@ -7,10 +7,235 @@ from typing import Any
7
  from fastapi import FastAPI, HTTPException
8
 
9
  CLASSIFIER_MODEL = "microsoft/deberta-v3-small"
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  app = FastAPI(title="Touchdown Compression Classifier", version="0.1.0")
12
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def _tokens(text: str) -> list[dict[str, Any]]:
15
  started = time.perf_counter()
16
  try:
@@ -76,26 +301,4 @@ def classify(payload: dict[str, Any]) -> dict[str, Any]:
76
 
77
  @app.post("/v1/compress")
78
  def compress(payload: dict[str, Any]) -> dict[str, Any]:
79
- # The Space can be called immediately, but managed compression logic lives
80
- # in the package service. This endpoint is deliberately conservative until
81
- # the package is vendored into the Space image.
82
- text = payload.get("input")
83
- if not isinstance(text, str):
84
- raise HTTPException(status_code=400, detail="input must be a string")
85
- started = time.perf_counter()
86
- return {
87
- "output": text,
88
- "original_input_tokens": max(1, round(len(text) / 4.0)),
89
- "output_tokens": max(1, round(len(text) / 4.0)),
90
- "tokens_saved": 0,
91
- "compression_percentage": 0.0,
92
- "receipt": {
93
- "protected_spans_checked": len(payload.get("protected_spans") or []),
94
- "protected_spans_missing": 0,
95
- "code_blocks_preserved": True,
96
- "decision": "no_op_classifier_scaffold",
97
- "compressor_latency_ms": round((time.perf_counter() - started) * 1000.0, 3),
98
- "classifier_model": CLASSIFIER_MODEL,
99
- "classifier_status": "tokenizer_loaded_no_trained_keep_drop_head",
100
- },
101
- }
 
7
  from fastapi import FastAPI, HTTPException
8
 
9
  CLASSIFIER_MODEL = "microsoft/deberta-v3-small"
10
+ RULES_VERSION = "hf-space-rules-v0.1.0"
11
+ LOW_SIGNAL_PATTERNS = [
12
+ re.compile(pattern, re.IGNORECASE)
13
+ for pattern in [
14
+ r"\blet me know if you (need|want|have)\b",
15
+ r"\bi hope this helps\b",
16
+ r"\bas an ai language model\b",
17
+ r"\bof course[,!]?\s*$",
18
+ r"\bcertainly[,!]?\s*$",
19
+ r"\bsure[,!]?\s*$",
20
+ ]
21
+ ]
22
 
23
  app = FastAPI(title="Touchdown Compression Classifier", version="0.1.0")
24
 
25
 
26
+ def _find_spans(text: str, needle: str) -> list[tuple[int, int]]:
27
+ spans = []
28
+ cursor = 0
29
+ while needle:
30
+ index = text.find(needle, cursor)
31
+ if index < 0:
32
+ return spans
33
+ spans.append((index, index + len(needle)))
34
+ cursor = index + len(needle)
35
+ return spans
36
+
37
+
38
+ def _regex_spans(text: str, pattern: str, flags: int) -> list[tuple[int, int]]:
39
+ return [(match.start(), match.end()) for match in re.finditer(pattern, text, flags)]
40
+
41
+
42
+ def _json_line_spans(text: str) -> list[tuple[int, int]]:
43
+ spans = []
44
+ cursor = 0
45
+ for line in text.splitlines(keepends=True):
46
+ stripped = line.strip()
47
+ if stripped and stripped[0] in "[{":
48
+ try:
49
+ import json
50
+
51
+ json.loads(stripped)
52
+ except Exception:
53
+ pass
54
+ else:
55
+ offset = line.index(stripped[0])
56
+ spans.append((cursor + offset, cursor + offset + len(stripped)))
57
+ cursor += len(line)
58
+ return spans
59
+
60
+
61
+ def _merge(spans: list[tuple[int, int]]) -> list[tuple[int, int]]:
62
+ if not spans:
63
+ return []
64
+ ordered = sorted(spans)
65
+ merged = [ordered[0]]
66
+ for start, end in ordered[1:]:
67
+ prev_start, prev_end = merged[-1]
68
+ if start <= prev_end:
69
+ merged[-1] = (prev_start, max(prev_end, end))
70
+ else:
71
+ merged.append((start, end))
72
+ return merged
73
+
74
+
75
+ def _overlaps(spans: list[tuple[int, int]], start: int, end: int) -> bool:
76
+ return any(start < span_end and end > span_start for span_start, span_end in spans)
77
+
78
+
79
+ def _is_subsequence(candidate: str, original: str) -> bool:
80
+ cursor = 0
81
+ for char in candidate:
82
+ cursor = original.find(char, cursor)
83
+ if cursor < 0:
84
+ return False
85
+ cursor += 1
86
+ return True
87
+
88
+
89
+ def _protected_spans(
90
+ text: str,
91
+ protected_values: list[str],
92
+ *,
93
+ preserve_code: bool,
94
+ preserve_json: bool,
95
+ ) -> tuple[
96
+ list[tuple[int, int]],
97
+ list[tuple[int, int]],
98
+ list[tuple[int, int]],
99
+ list[tuple[int, int]],
100
+ ]:
101
+ spans = []
102
+ for value in protected_values:
103
+ spans.extend(_find_spans(text, value))
104
+ code_spans = (
105
+ _regex_spans(text, r"```.*?```", re.MULTILINE | re.DOTALL)
106
+ if preserve_code
107
+ else []
108
+ )
109
+ json_spans = (
110
+ _regex_spans(text, r"```(?:json|JSON)\s*\n.*?```", re.MULTILINE | re.DOTALL)
111
+ + _json_line_spans(text)
112
+ if preserve_json
113
+ else []
114
+ )
115
+ system_spans = (
116
+ _regex_spans(text, r"<system\b[^>]*>.*?</system>", re.MULTILINE | re.DOTALL)
117
+ + _regex_spans(text, r"^system\s*:\s*.*$", re.MULTILINE | re.IGNORECASE)
118
+ )
119
+ spans.extend(code_spans)
120
+ spans.extend(json_spans)
121
+ spans.extend(system_spans)
122
+ return _merge(spans), code_spans, json_spans, system_spans
123
+
124
+
125
+ def _compress_text(payload: dict[str, Any]) -> dict[str, Any]:
126
+ text = payload.get("input")
127
+ if not isinstance(text, str):
128
+ raise HTTPException(status_code=400, detail="input must be a string")
129
+ settings = payload.get("compression_settings") or {}
130
+ if not isinstance(settings, dict):
131
+ raise HTTPException(status_code=400, detail="compression_settings must be an object")
132
+ protected_values = payload.get("protected_spans") or []
133
+ if not isinstance(protected_values, list) or not all(
134
+ isinstance(value, str) for value in protected_values
135
+ ):
136
+ raise HTTPException(status_code=400, detail="protected_spans must be strings")
137
+ try:
138
+ aggressiveness = float(settings.get("aggressiveness", 0.35))
139
+ except Exception as exc:
140
+ raise HTTPException(status_code=400, detail="aggressiveness must be numeric") from exc
141
+ if not 0.0 <= aggressiveness <= 1.0:
142
+ raise HTTPException(status_code=400, detail="aggressiveness must be 0..1")
143
+
144
+ started = time.perf_counter()
145
+ preserve_code = bool(settings.get("preserve_code", True))
146
+ preserve_json = bool(settings.get("preserve_json", True))
147
+ protected, code_spans, json_spans, system_spans = _protected_spans(
148
+ text,
149
+ protected_values,
150
+ preserve_code=preserve_code,
151
+ preserve_json=preserve_json,
152
+ )
153
+ seen: set[str] = set()
154
+ drops: list[tuple[int, int, str, str]] = []
155
+ cursor = 0
156
+ previous_blank_kept = False
157
+ for line in text.splitlines(keepends=True):
158
+ start = cursor
159
+ end = cursor + len(line)
160
+ cursor = end
161
+ stripped = line.strip()
162
+ normalized = re.sub(r"\s+", " ", stripped).lower()
163
+ if _overlaps(protected, start, end):
164
+ if normalized:
165
+ seen.add(normalized)
166
+ previous_blank_kept = False
167
+ continue
168
+ reason = None
169
+ if not stripped and previous_blank_kept:
170
+ reason = "extra_blank"
171
+ elif len(normalized) > 30 and normalized in seen and aggressiveness >= 0.10:
172
+ reason = "duplicate_line"
173
+ elif aggressiveness >= 0.20 and any(
174
+ pattern.search(stripped) for pattern in LOW_SIGNAL_PATTERNS
175
+ ):
176
+ reason = "low_signal_phrase"
177
+ if reason:
178
+ drops.append((start, end, reason, stripped[:120]))
179
+ continue
180
+ previous_blank_kept = not stripped
181
+ if normalized:
182
+ seen.add(normalized)
183
+
184
+ chunks = []
185
+ drop_ranges = _merge([(start, end) for start, end, _, _ in drops])
186
+ cursor = 0
187
+ for start, end in drop_ranges:
188
+ chunks.append(text[cursor:start])
189
+ cursor = end
190
+ chunks.append(text[cursor:])
191
+ output = "".join(chunks)
192
+ before = max(1, round(len(text) / 4.0))
193
+ after = max(1, round(len(output) / 4.0))
194
+ saved = max(0, before - after)
195
+ missing = [value for value in protected_values if value and value not in output]
196
+ code_preserved = all(text[start:end] in output for start, end in code_spans)
197
+ json_preserved = all(text[start:end] in output for start, end in json_spans)
198
+ system_preserved = all(text[start:end] in output for start, end in system_spans)
199
+ decision = "reject" if (
200
+ missing or not code_preserved or not json_preserved or not system_preserved
201
+ ) else (
202
+ "high_confidence" if saved > 0 and aggressiveness <= 0.65 else "no_op"
203
+ )
204
+ return {
205
+ "output": output,
206
+ "original_input_tokens": before,
207
+ "output_tokens": after,
208
+ "tokens_saved": saved,
209
+ "compression_percentage": round(100.0 * saved / before, 1),
210
+ "receipt": {
211
+ "protected_spans_checked": len(protected_values),
212
+ "protected_spans_missing": len(missing),
213
+ "code_blocks_detected": len(code_spans),
214
+ "code_blocks_preserved": code_preserved,
215
+ "json_blocks_detected": len(json_spans),
216
+ "json_blocks_preserved": json_preserved,
217
+ "system_prompt_spans_detected": len(system_spans),
218
+ "system_prompts_preserved": system_preserved,
219
+ "decision": decision,
220
+ "compressor_latency_ms": round((time.perf_counter() - started) * 1000.0, 3),
221
+ "deletion_only": _is_subsequence(output, text),
222
+ "deterministic": True,
223
+ "rules_version": RULES_VERSION,
224
+ "classifier": {
225
+ "model": CLASSIFIER_MODEL,
226
+ "status": "tokenizer_loaded_no_trained_keep_drop_head",
227
+ "labels_received": 0,
228
+ "drop_spans_applied": 0,
229
+ },
230
+ "dropped_segments_count": len(drops),
231
+ "dropped_segments": [
232
+ {"reason": reason, "preview": preview}
233
+ for _, _, reason, preview in drops[:20]
234
+ ],
235
+ },
236
+ }
237
+
238
+
239
  def _tokens(text: str) -> list[dict[str, Any]]:
240
  started = time.perf_counter()
241
  try:
 
301
 
302
  @app.post("/v1/compress")
303
  def compress(payload: dict[str, Any]) -> dict[str, Any]:
304
+ return _compress_text(payload)