forked from retoor/devplacepy
docs: document server-side rendering pipeline, response timing middleware, and Telegram pairing API
- Add comprehensive documentation for backend content rendering in AGENTS.md, detailing the new `render_content` and `render_title` Jinja globals built on mistune with media processing, emoji shortcodes, and XSS protection
- Document the `X-Response-Time` header and bottom-left render time indicator in README.md
- Update bot token pricing documentation to clarify fallback vs gateway cost headers
- Add `email_accounts` to soft-delete tables and `idx_users_role` composite index in database schema
- Implement `telegram_pairings` and `telegram_links` table creation with column migration and indexes
- Add `/profile/{username}/telegram` endpoint to docs API with request/unpair actions
- Register `TelegramService` in main.py lifespan and add `response_timing` middleware emitting `X-Response-Time` header
- Introduce `TelegramPairForm` model and `guard_public_host_sync` synchronous host validation function
This commit is contained in:
@@ -19,6 +19,7 @@ from devplacepy.services.bot.config import (
|
||||
TRIVIAL_GIST_TERMS,
|
||||
)
|
||||
from devplacepy.services.bot.handles import MAX_HANDLE_LEN, sanitize_handle
|
||||
from devplacepy.services.openai_gateway.usage import parse_usage_headers
|
||||
|
||||
HANDLE_CANDIDATE_TARGET = 8
|
||||
|
||||
@@ -74,11 +75,8 @@ class LLMClient:
|
||||
raw = resp.content
|
||||
logger.info("LLM <<< %s", raw[:2000].decode(errors="replace"))
|
||||
result = resp.json()
|
||||
usage = result.get("usage", {})
|
||||
in_tokens = usage.get("prompt_tokens", 0)
|
||||
out_tokens = usage.get("completion_tokens", 0)
|
||||
cost = (in_tokens * self.input_cost_per_1m / 1_000_000) + (
|
||||
out_tokens * self.output_cost_per_1m / 1_000_000
|
||||
in_tokens, out_tokens, cost = self._account_usage(
|
||||
resp.headers, result.get("usage", {})
|
||||
)
|
||||
self.total_cost += cost
|
||||
self.total_calls += 1
|
||||
@@ -96,6 +94,21 @@ class LLMClient:
|
||||
time.sleep(2**attempt)
|
||||
return ""
|
||||
|
||||
def _account_usage(self, response_headers, body_usage: dict) -> tuple[int, int, float]:
|
||||
parsed = parse_usage_headers(response_headers)
|
||||
if parsed is not None:
|
||||
in_tokens = parsed["prompt_tokens"]
|
||||
out_tokens = parsed["completion_tokens"]
|
||||
if not out_tokens and parsed["total_tokens"] > in_tokens:
|
||||
out_tokens = parsed["total_tokens"] - in_tokens
|
||||
return in_tokens, out_tokens, parsed["cost_usd"]
|
||||
in_tokens = body_usage.get("prompt_tokens", 0)
|
||||
out_tokens = body_usage.get("completion_tokens", 0)
|
||||
cost = (in_tokens * self.input_cost_per_1m / 1_000_000) + (
|
||||
out_tokens * self.output_cost_per_1m / 1_000_000
|
||||
)
|
||||
return in_tokens, out_tokens, cost
|
||||
|
||||
def _call(self, system: str, prompt: str, temperature: float = 0.7) -> str:
|
||||
return self.clean(self._raw_call(system, prompt, temperature))
|
||||
|
||||
@@ -496,12 +509,20 @@ class LLMClient:
|
||||
"You invent online handles for a developer signing up to a programmer "
|
||||
"community in the style of devRant or Hacker News. The handles read like a "
|
||||
"real nerd picked them, never like a person's full name. Lean on programming "
|
||||
"and hacker culture: tech nouns (null, kernel, segfault, daemon), occasional "
|
||||
"leetspeak (c0d3r, h4x), an adjective plus noun, a creature, or a short word "
|
||||
f"with a number. Lowercase mostly, {MAX_HANDLE_LEN} characters or fewer, only "
|
||||
"letters, digits, underscores and hyphens, no spaces and no dots. Return ONLY "
|
||||
f'a JSON object {{"handles": ["...", "..."]}} with {HANDLE_CANDIDATE_TARGET} '
|
||||
"distinct handles, no prose, no markdown fences. No em dashes."
|
||||
"and hacker culture, but make every handle in the list a DIFFERENT shape so "
|
||||
"they never feel formulaic. Mix these forms across the list: a single fused "
|
||||
"word (segfault, mutexlord, kernelpanic); two words joined with no separator "
|
||||
"(darkbyte, neonferret); camelCase (nullPointer, byteFox); an underscore or a "
|
||||
"hyphen but NOT on most of them (lazy_daemon, cold-stack); leetspeak "
|
||||
"(n0_scalar, c0d3r, h4xwolf); a word plus a number, port, or version tag "
|
||||
"(void404, daemon1337, byte_v2, heap8080); dropped vowels (krnlpnc, bffr, "
|
||||
"mtxguru); and an unexpected creature, role, or prefix (dr_segfault, "
|
||||
"raven_smith, axolotl_dev). Vary the length from 4 to 18. Lowercase mostly "
|
||||
"with the odd capital. Do NOT make them all the 'word_word' underscore "
|
||||
f"pattern. {MAX_HANDLE_LEN} characters or fewer, only letters, digits, "
|
||||
"underscores and hyphens, no spaces and no dots. Return ONLY a JSON object "
|
||||
f'{{"handles": ["...", "..."]}} with {HANDLE_CANDIDATE_TARGET} distinct '
|
||||
"handles, each a distinct shape, no prose, no markdown fences. No em dashes."
|
||||
)
|
||||
prompt = (
|
||||
f"Archetype: {archetype}\n"
|
||||
|
||||
Reference in New Issue
Block a user