AI 资讯
AVIF vs WebP vs JPEG: Real Benchmarks (2026)
I compressed 100 photos through 3 formats. Here's the actual data. A 2MB JPEG photo. Convert it to WebP — now it's 480KB. Convert it to AVIF — now it's 310KB. Same visual quality. Three different file sizes. I've spent the last 2 weeks building an image compression tool, so I've seen thousands of these comparisons. Here's what the numbers actually say, and what it means for your website. The Setup I took 50 real-world photos and 50 screenshots/design assets — not synthetic test images, but actual files people would upload: Photos : vacation shots (JPEG, 2-8MB), product photos, portrait selfies Graphics : PNG screenshots (1-4MB), logos, UI mockups, illustrations Source sizes : 500KB to 12MB, average ~3.2MB Each image was compressed through JPEG (quality 85%), WebP (quality 80%), and AVIF (quality 65%) — settings that produce visually identical results on a 2x retina display. The Numbers Format Avg Compressed Size Reduction vs Original Reduction vs JPEG Browser Support Original 3.2 MB — — 100% JPEG (q85) 820 KB 74.4% — 100% WebP (q80) 480 KB 85.0% 41.5% smaller than JPEG 96.8% AVIF (q65) 310 KB 90.3% 62.2% smaller than JPEG 93.1% The headline : WebP halves your JPEG size. AVIF halves WebP again. Photo Results (JPEG source, 50 images) For photographs — the most common use case — here's what happened: Format Avg Size Best Case Worst Case JPEG q85 820 KB 180 KB 3.1 MB WebP q80 480 KB 95 KB 1.8 MB AVIF q65 310 KB 60 KB 1.2 MB What this means : On an average product page with 6 photos: JPEG: 6 × 820KB = 4.9 MB WebP: 6 × 480KB = 2.9 MB (saves 2 MB) AVIF: 6 × 310KB = 1.9 MB (saves 3 MB) On a 4G connection (10 Mbps), that's the difference between 4 seconds and 1.5 seconds to load all images. On a product page, that's the difference between a bounce and a sale. Screenshot/Graphics Results (PNG source, 50 images) PNGs are a different story. Lossy WebP and AVIF can crush PNGs — but only if you're OK losing pixel-perfect accuracy. Format Avg Size Notes Original PNG 1.4 MB Lossles
AI 资讯
Stop writing CSS gradients by hand — free generator with Tailwind and SCSS export
Writing linear-gradient(135deg, #667eea 0%, #764ba2 100%) from scratch every time is tedious. Remembering the syntax for radial and conic gradients is even worse. I added a free CSS gradient generator to PaletteCSS that handles all three gradient types with a live visual preview. What it supports linear-gradient — any angle, drag the dial or type degrees radial-gradient — circular and elliptical conic-gradient — pie-chart style, great for progress rings and color wheels Up to 5 color stops with draggable positions Instant copy in 3 formats CSS background : linear-gradient ( 135 deg , #667 eea 0 %, #764 ba2 100 %); SCSS $gradient-primary : linear-gradient ( 135deg , #667eea 0% , #764ba2 100% ); Tailwind style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)" Try it free 👉 https://palettecss.com/css-gradient-generator No signup. The site also has a browsable gradient library if you want inspiration rather than building from scratch. Any gradient types or export formats you'd want added? Drop a comment.
AI 资讯
600 Filters and a 414: The New QUERY Method in .NET 10
A product search, a filter list that kept growing, and a status code I hadn't seen in years. Filters went in the query string, the way they always do. That held up fine until someone saved a "filter set" with a few hundred SKUs in it and the endpoint started answering with 414. I rebuilt a small version of it to find the exact wall. Same search, filters as repeated ?sku= values, count going up in steps of a hundred: 1) GET with filters in the URL 100 filters | request line 1534 bytes | 200 OK 200 filters | request line 3034 bytes | 200 OK 300 filters | request line 4534 bytes | 200 OK 400 filters | request line 6034 bytes | 200 OK 500 filters | request line 7534 bytes | 200 OK 600 filters | request line 9034 bytes | 414 RequestUriTooLong Kestrel's default max request line is 8 KB, and the request line is the method plus the URL plus the HTTP version. Somewhere between 500 and 600 filters, my URL stopped being a URL. Every fix I knew was a compromise. A body on GET is undefined by spec and some proxies quietly drop it. POST works, but POST announces "this might change something", so caches skip it, gateways won't auto-retry it, and anyone reading your API docs has to guess whether POST /search is actually a search. Cramming the filters into a header is the kind of idea that sounds clever for about a day. The method that was missing RFC 10008 defines QUERY , and it's exactly the thing that spot in the matrix was waiting for. The body carries the query. The method is safe and idempotent, so it can be retried after a dropped connection without anyone panicking. Responses are cacheable, and the spec is explicit that the cache key has to be built from "the request content and related metadata". There's also a nice touch on the response side: Content-Location can point at a URL where those exact results can be fetched with a plain GET. The one-line version I keep giving people: it's a GET with a body, and that's the entire point. Wiring it up in ASP.NET Core 10 .NET 10 shi
AI 资讯
The Loneliness Protocol of a Solo Tech Founder
The Loneliness Protocol of a Solo Tech Founder Loneliness in entrepreneurship is as predictable as a server crash during peak traffic. For a solo founder, it’s a relentless companion, one that doesn't care if you’re in bustling Davao or isolated at your desk. Here’s the brutal truth: isolation can break you if you let it. You’re not just navigating tech challenges, but also the uncharted waters of solo existence, where human connection feels like a distant luxury. The Core Problem & Why This Matters Let me be clear, as a solo tech founder, loneliness isn’t a sidebar issue—it’s central to your survival. You might be a genius with API integrations or a master of patent applications , but if you’re fighting the darkness of isolation, your innovations suffer. The mental load of building something from scratch is immense. Add to that the silence of not having a co-founder or team to bounce ideas off, and you’re skating on thin ice. Why does this matter? Confidence wanes, decision-making suffers, and burnout creeps in. When productivity is tied to connection, and all your colleagues are digital avatars miles away, your business can quickly spiral downwards. This isn’t just about feeling good. It’s about maintaining a sustainable creative energy . If your innovation pipeline clogs with self-doubt, you lose ground, fast. The Systems Engineering Approach The solution isn't a one-size-fits-all. It starts with engineering systems designed to bring people into your virtual workspace. Think beyond the Zoom calls. We’re talking curated, meaningful interactions. Start with regular, structured virtual check-ins with other industry experts. Set these in stone, like a production deployment—a fixed calendar, strict agenda. Engage in remote communities with shared goals. Platforms like Slack and Discord have niche channels dedicated to tech founders. These aren’t just chat rooms; they’re virtual war rooms for brainstorming, networking, and problem-solving. The key here is participation
AI 资讯
Hunter-Base-Intelligence: Building a Local On-Chain Scanner & Paper-Trading Engine for Base EVM 🚀
Hello DEV Community! 👋 I wanted to share my latest open-source project: Hunter-Base-Intelligence (v17 Plus). It is a fully local-only cryptocurrency intelligence dashboard that scans DEX tokens on the Base blockchain, scores them using a multi-factor logic, and simulates a paper-trading shadow portfolio. 🛡️ Why Local-Only? Most on-chain analytics tools require sensitive private keys, leak user data, or rely heavily on slow, paid external infrastructure. I engineered this tool to be fully local —it requires no wallets, no seed phrases, and sends your data nowhere. Pure local analysis using Python , Flask , and SQLite . ⚙️ How It Works (Core Architecture) The ecosystem runs on a continuous ~60-second scan cycle: scanner.py : Discovers active and newly created tokens using DexScreener, BaseScan, and direct EVM RPC factory logs. scorer.py : Every token is evaluated across 6 independent dimensions (Momentum, Manual Trade Feasibility, Execution Reality, Money Flow, Multi-Timeframe Pulse, and Composite Rank). hunter_court.py : A proprietary "Court" analytics engine that runs a risk-free paper-trading shadow portfolio with realistic gas, fee, and slippage simulation. It evaluates its own past decisions to continuously calibrate scoring thresholds! 📊 System Features Adaptive Exit Parameters: Automated position sizing and execution simulation ( exit_engine.py ). System Guardian: Keeps the system running 24/7 with auto-restart on crashes and automatic local database backups ( system_guardian.py ). Beautiful Dashboard: Clean, real-time local web interface for tracking active simulated trades and market analytics. 📂 Explore and Contribute The project is licensed under the MIT License and is open for contributions. Whether you want to optimize the scoring algorithms, expand the web API endpoints, or improve the dashboard frontend, feel free to dive in! 👉 Check out the Repository here: https://github.com/shbadrconsulting-source/Hunter-Base-Intelligence I would love to hear your fe
AI 资讯
The Multiple Browser Tab Token Trap: Synchronizing JWT Refresh Across Browser Tabs
How multiple open browser tabs can accidentally DDOS your auth server, and how to fix it with the Web Locks API. Picture this: You’ve just shipped a state-of-the-art Axios response interceptor. You implemented a mutex lock ( isRefreshing ) and a promise queue ( failedQueue ) to handle concurrent 401 errors. You tested it within a single tab, and it worked like a charm. You gave yourself a high-five and closed your laptop. Then, a power user logs in. Like most humans on the internet, they don't use just one browser tab. They open Tab 1 for User Management, Tab 2 for Analytics, Tab 3 for Settings, and Tab 4 for Support Tickets. Fifteen minutes pass. Their short-lived JWT access token expires. The user switches back to Tab 1. In the background, all 4 open tabs wake up, detect the expired token, and fire off four independent POST /auth/refresh-token/ requests at the exact same millisecond. Tab 1 refreshes the token first, but Tab 2's request arrives a millisecond later, invalidates Tab 1's new token, and Tab 3 nukes the session entirely. Suddenly, all 4 tabs dump the user back to the login screen. Welcome to the Cross-Tab Token Trap . 1. The Problem: The Multi-Tab Stampede In modern single-page applications (SPAs), each browser tab operates in its own isolated JavaScript runtime environment. Memory is not shared. When an access token expires: isRefreshing = true in Tab A only stops requests inside Tab A . Tab B has no idea Tab A is currently refreshing a token. Tab C lives in complete ignorance of Tabs A and B. Tab A (Memory Space 1) ---> isRefreshing = true ---> POST /auth/refresh-token/ (Token Set 1) Tab B (Memory Space 2) ---> isRefreshing = true ---> POST /auth/refresh-token/ (Token Set 2 -> Revokes Set 1!) Tab C (Memory Space 3) ---> isRefreshing = true ---> POST /auth/refresh-token/ (Token Set 3 -> Revokes Set 2!) If your backend enforces Single-Use Refresh Token Rotation (where using a refresh token revokes all previous ones), multi-tab usage causes immediate ses
AI 资讯
We Built a Signal Protocol Messenger. Then We Checked If It Was Legal in 5 Jurisdictions.
TL;DR: We checked Halonyx — our self-hosted E2EE messenger implementing X3DH + Double Ratchet — against the EU's Chat Control, US EARN IT Act, India's IT Rules 2021, the UK's Online Safety Act + Investigatory Powers Act, and the UN Cybercrime Convention. Here's the honest answer for each. When you implement end-to-end encryption from scratch, you spend a lot of time thinking about cryptographic threat models. Key substitution attacks. OPK exhaustion. WebRTC IP leakage. The adversaries you model are largely technical. At some point, you have to model a different kind of adversary: the legal one. We built Halonyx — a self-hostable E2EE messenger implementing the Signal Protocol (X3DH key exchange, Double Ratchet, Safety Numbers, WebTorrent P2P file transfer). The server architecturally cannot read your messages — not by policy, but because it holds no decryption keys and no plaintext. We wrote a STRIDE threat model across 17 attack surfaces. We did not write a legal threat model. So we did. This is what we found across five jurisdictions. None of this is legal advice. All of it is current as of July 2026, in a policy landscape that is actively moving. Quick Architecture Recap Before the jurisdiction breakdown, a one-paragraph recap of what Halonyx actually does, because the architecture is what determines the legal exposure. The relay server stores and forwards only AES-256-GCM ciphertext. It holds no private keys, performs no cryptographic operations on behalf of users, and has no mechanism to identify message content or originators. User identity is a pseudonymous 256-bit USID — the server stores only SHA-256(USID) . Files transfer peer-to-peer via WebTorrent; the server receives only a magnet URI. This architecture — which we call Federated Relay Architecture (FRA) — is what creates the legal situation described below. 1. European Union — Chat Control / CSAR Current status: No conflict with anything currently in force. The EU's Child Sexual Abuse Regulation (CSAR),
AI 资讯
No Backend, No Build Step: A Spaced-Repetition Chrome Extension That Runs on chrome.storage.sync Alone
Most "save this for later" tools I've used eventually want a server: an account system, a database for your notes, a sync service with its own outage history. I wanted something narrower — capture text or a whole page while browsing, turn it into a spaced-repetition flashcard, and have it show up on my other machine — without running any infrastructure at all. MindStack is a Manifest V3 Chrome extension that does exactly that: capture, spaced-repetition scheduling, a full dashboard, and cross-device sync, built entirely on chrome.storage.sync and chrome.identity . No backend, no bundler, no npm install before you can load it unpacked. Here's what that constraint forces you to get right. Decision 1: The scheduler is SM-2-shaped, not SM-2 Spaced repetition apps usually reach for a full SuperMemo SM-2 implementation — ease factors computed from response quality on a 0–5 scale, per-review interval history. MindStack's actual scheduler is a compressed version that captures the two properties that matter for a lightweight capture tool and drops the rest: const scoreReview = async ( score ) => { const memory = state . memories . find (( item ) => item . id === activeReviewId ); const interval = { forgot : 1 , hard : Math . max ( 1 , Math . round (( memory . reviewCount || 1 ) * 1.5 )), good : Math . max ( 2 , Math . round (( memory . reviewCount || 1 ) * ( memory . ease || 2.5 ))), easy : Math . max ( 4 , Math . round (( memory . reviewCount || 1 ) * (( memory . ease || 2.5 ) + 1 ))) }[ score ]; const updated = { ... memory , reviewCount : ( memory . reviewCount || 0 ) + 1 , successCount : ( memory . successCount || 0 ) + ( score === " forgot " ? 0 : 1 ), ease : Math . min ( 3.4 , Math . max ( 1.3 , ( memory . ease || 2.5 ) + ({ forgot : - 0.35 , hard : - 0.12 , good : 0.05 , easy : 0.16 }[ score ]) )), nextReviewAt : addDays ( interval ), }; Two properties, deliberately preserved from SM-2: intervals grow multiplicatively with review count (so a card you keep getting righ
AI 资讯
12 things to check before you ship your vibe-coded app
Getting an app to work has stopped being the hard part. You describe what you want, Lovable or Bolt or v0 builds it, and forty minutes later there's something on a real URL that real people can click. The hard part moved. It's now everything between "it works" and "it survives contact with the internet." That gap isn't a vibe. It's measurable. Symbiotic Security crawled 65,643 URLs and fully scanned 1,072 Supabase-backed vibe-coded apps in June 2026: 98% had at least one security issue, 16% had something critical. A separate academic study by Deng et al. found that vibe-coded apps show recurring vulnerability patterns that differ from the ones traditional codebases produce — meaning these aren't random mistakes, they're structural. And an Xint.io analysis reported by SecurityWeek turned up 434 exploitable flaws concentrated in secrets exposure, broken authorization and denial of service. Same handful of failure modes, over and over. Which is good news, because it means you can check for them in about fifteen minutes. Below is the list I actually walk through. Everything here you can run against your own domain with curl and browser devtools. No tooling required. 1. Is your .env reachable over HTTP? The single most common catastrophic finding. It happens when the build output directory and the project root end up being the same thing. curl -sI https://yourapp.com/.env | head -1 curl -sI https://yourapp.com/.env.local | head -1 curl -sI https://yourapp.com/.env.production | head -1 Anything other than 404 is an emergency. Rotate every key in that file before you do anything else — assume it's already been scraped, because bots hit these paths constantly. 2. Is your .git directory exposed? Worse than .env , because it hands over your entire history including keys you thought you'd removed. curl -sI https://yourapp.com/.git/HEAD | head -1 curl -s https://yourapp.com/.git/config If HEAD returns 200, the whole repository is reconstructable by a stranger. 3. Which keys are
AI 资讯
How I compile React-shaped TSX without React or hydration
I started building Kudzu while making static websites with AI. AI coding tools have become very good at producing React-shaped TSX, and I have become used to reviewing code in that form. Function components, props, JSX, and event handlers are often easier for me to understand and verify than scattered DOM queries and imperative JavaScript mutations. But I was still building static pages. I wanted to keep TSX as the authoring and code-review format without automatically shipping React, a virtual DOM, hydration, or a browser-side component tree. Kudzu grew from that idea: Write familiar TSX, execute components during the build, and ship ordinary HTML with only the JavaScript each route actually needs. Kudzu is an experimental, HTML-first TSX framework. Website: kudzujs.cloud GitHub: github.com/kudzujs/kudzu The problem I wanted to solve Consider a blog, documentation site, newsletter, or product landing page. Most of the page is already known during the build: headings; navigation; articles; images; metadata; product descriptions; documentation content. TSX is a convenient way to author and review that structure. function PostCard ({ title , description , href }: { title : string description : string href : string }) { return ( < article > < h2 >< a href = { href } > { title } </ a ></ h2 > < p > { description } </ p > </ article > ) } The component model is useful for authoring, but that does not necessarily mean the browser needs a component runtime. For a static page, I wanted the output to remain ordinary HTML. <article> <h2><a href= "/posts/hello" > Hello </a></h2> <p> My first article. </p> </article> I also wanted interactive pages to receive only the JavaScript required for their actual behavior. Kudzu's model Kudzu treats components as build-time authoring units. React-shaped TSX ↓ Kudzu compiler ↓ Static HTML + CSS + capability-specific ESM Function components execute during the build. The browser does not receive: the component functions; React; a virtual D
AI 资讯
5 of the biggest mistakes i made in my first project.
Building my first website was exciting, but it taught me that creating something people actually enjoy using is much harder than just writing code. Here are the biggest mistakes I made and what I learned from them. Trying to Make Everything Perfect I kept changing tiny details instead of launching. Lesson: Ship first, improve later. ⸻ Adding Too Many Features I focused on building more instead of making the existing features better. Lesson: A simple website that solves one problem well is far more valuable. ⸻ Ignoring User Experience A good-looking website isn’t enough if it’s confusing or slow. Lesson: Make every click simple and intuitive. ⸻ Not Testing Enough I only tested on my own device, which led to bugs and layout issues on others. Lesson: Test on different browsers and screen sizes before publishing. ⸻ Being Afraid of Feedback Not every suggestion was easy to hear, but every piece of feedback helped improve the website. Lesson: Listen to your users—they’ll help you build something better. ⸻ Final Thoughts Building my first website taught me much more than coding. Every mistake helped me improve, and every update made the project a little better. If you’re building your first website, don’t be afraid to make mistakes—they’re one of the fastest ways to grow as a developer. 💬 What’s the biggest lesson you’ve learned while building a project?
AI 资讯
Subscription Goldmine: SaaS Models and Startup Cash Flow
Subscription Goldmine: SaaS Models and Startup Cash Flow Here's the brutal truth: nothing brings a tech solopreneur closer to existential dread than staring down a dried-up cash runway in the office at midnight. This concern is universal for founders, whether you're nestled in a cozy Davao home office or grinding away in a bustling city. The rise of subscription-based Software as a Service (SaaS) models is shifting this narrative, offering both solutions and new challenges. The stakes are high, but so are the potential rewards. The Core Problem & Why This Matters Startups live and die by their cash flow. Managing liquidity is crucial for keeping the lights on and securing future growth. Traditional software sales were typically characterized by large, one-time purchases. This model, while sometimes lucrative, posed significant challenges for startups that needed a steady influx of cash. The subscription model flips this on its head by transforming how revenue is recognized, providing a more predictable income stream. The consistent monthly inflows from subscriptions give startups the cushion they need to weather the ups and downs of growth periods. But here's the catch: converting users into paying subscribers isn’t a cakewalk. It requires upfront investments in product development, marketing, and customer support. Yet, this model becomes a vital lifeline, especially when venture capital isn't an option. Subscription models necessitate long-term engagement strategies, but they offer a recurring revenue stream that can stabilize an otherwise volatile cash flow. The Systems Engineering Approach Developing a subscription-based SaaS model requires a meticulous systems approach. The first step involves designing a seamless user experience . Every touchpoint must be optimized to retain users and convert trial customers into paid subscribers. From initial sign-up to daily usage, every feature should scream value. Next, focus on robust backend systems. These systems are the
开发者
Why I built Sanctuary: A local-first, zero-tracking reflection app
Most journaling and mental wellness apps require syncing sensitive personal thoughts to cloud servers where they risk being mined or exposed. I wanted a space where user data never leaves the browser. So I built Sanctuary — a lightweight, local-first reflection vault. 🛠️ Technical Highlights 100% Local-First: All entries and app states stay strictly inside browser local storage. Zero tracking scripts or analytics. Resonance Diagnostics: Dynamic, client-side SVG visualizations mapping baseline mood trends over time. Therapy PDF Export: Uses native CSS print styling ( @media print ) to generate clean offline summary reports for check-ins without sharing app access. Zero Overhead: Blazing fast load times with no database or cloud sync latency. Check out the live app: sanctuaryb.lovable.app I'd love feedback from the dev community on the local storage architecture, baseline algorithms, or visual UI!
开发者
How to Build an Interactive Sales Analytics Dashboard in Python using Streamlit
Streamlit makes it remarkably fast to transform raw Python scripts into interactive, web-based data applications without needing any frontend knowledge in HTML, CSS, or JavaScript. In this tutorial, we will build a full-featured **Sales Analytics Dashboard** complete with real-time sidebar filtering, custom KPI metric cards, dynamic line/bar charts, and expandable data preview tables. --- ## Prerequisites To follow along, make sure you have Python 3.9+ installed along with the required libraries: bash pip install streamlit pandas numpy --- ## Step 1: Setting Up the Page & Mock Data with Caching First, we import the necessary libraries, set up the layout, and create a function to generate mock sales records. We use Streamlit’s `@st.cache_data` decorator so the data is only generated once per session, keeping the app snappy during user interactions. python import streamlit as st import pandas as pd import numpy as np Set layout configuration st.set_page_config(page_title="Sales Dashboard", layout="wide") Cache data loading for performance optimization @st .cache_data def load_data(): dates = pd.date_range("2025-01-01", periods=180) regions = ["North", "South", "East", "West"] df = pd.DataFrame({ "date": np.random.choice(dates, 500), "region": np.random.choice(regions, 500), "product": np.random.choice(["A", "B", "C"], 500), "sales": np.random.randint(100, 5000, 500), "units": np.random.randint(1, 50, 500), }) return df.sort_values("date") df = load_data() --- ## Step 2: Adding Interactive Sidebar Filters Next, we add controls inside the sidebar to let users filter the dataset by region, product type, and date range. A boolean mask applies those selections dynamically. python --- Sidebar filters --- st.sidebar.header("Filters") region_filter = st.sidebar.multiselect("Region", df["region"].unique(), default=df["region"].unique()) product_filter = st.sidebar.multiselect("Product", df["product"].unique(), default=df["product"].unique()) date_range = st.sidebar.date_input(
AI 资讯
Why most "PDF dark mode" Chrome extensions do nothing on a web PDF
Chrome still ships no dark mode for its built-in PDF viewer. Open a white paper at 1am and you get a flashbang. So you go to the Web Store, install the extension with the most installs, click it, and… nothing happens. The page stays white. I went and read the manifests of the top results to find out why. Two reasons, and both are boring. Reason 1: the popular ones only handle file:// The extension named "PDF Dark Mode" (about 10,000 users, rated 2.5) declares exactly this: "permissions" : [ "scripting" , "declarativeContent" ] , "host_permissions" : [ "file:///*.pdf" ] The runner-up, "PDF Dark Theme" (about 9,000 users, rated 2.9), does the same thing with a content script: "content_scripts" : [{ "matches" : [ "file://*.pdf" ], "js" : [ "content-script.js" ] }] file:///*.pdf matches a PDF you dragged in from your own disk. It does not match https://arxiv.org/pdf/1706.03762 , or the invoice your bank linked, or the syllabus on a course site. That is where almost everyone actually meets a PDF. So the extension is installed, enabled, and structurally incapable of touching the document in front of you. This is also why the reviews are full of people being told to flip "Allow access to file URLs" and reporting back that it changed nothing. It was never the missing piece. You can check any extension for this in ten seconds: chrome://extensions → Details → look at "Site access". If it says nothing beyond file URLs, that is your answer. Reason 2: the CSS target moved The other approach is a CSS filter on the viewer element: embed [ type = "application/x-google-chrome-pdf" ] { filter : invert ( 90% ) hue-rotate ( 180deg ); } That used to be right. When you navigate straight to a PDF today, the document you are styling has no <embed> in it. The viewer lives in an out-of-process child frame that your CSS cannot reach. Your selector matches zero elements and fails silently, which is the worst way for CSS to fail. What does reach it is a filter on the root element of the PDF doc
AI 资讯
How We Built Precise Translation and Language Identification for AI Book Translation
How we tackled 精准翻译与语言识别 (precise translation and language identification) for AI-powered book translation. The Problem: Garbage In, Garbage Out When we first launched LectuLibre, our AI book translation service, we thought the hardest part would be fine-tuning LLM prompts for literary quality. But we quickly discovered a more fundamental hurdle: if the source language of an uploaded book is misidentified, no amount of prompt engineering can salvage the translation. Users upload EPUBs and PDFs from all over the world. Some contain metadata specifying the language, but many don't. Others are multilingual books, or have prefaces in a different language. Our initial language detection using Python's langdetect library was correct only about 85% of the time on real-world uploads. That 15% error rate meant entirely garbled translations, frustrated users, and wasted LLM API credits. We needed something far more robust—what we internally call 精准翻译与语言识别 (precise translation and language identification). Here’s how we built it. The Language Detection Pipeline: From 85% to 98% Accuracy Our first instinct was to try heavier models like fastText's pre-trained language identification model, which is known for high accuracy. But when we tested it on book excerpts, we hit a new problem: short paragraphs or dialogues in one language embedded in a book of another language (e.g., French phrases in an English novel) would throw off chunk-level detection. We realized that we needed a two-tier approach: book-level language detection with confidence scoring, and per-chunk verification before translation. Combining Multiple Detectors with Voting We created a LanguageDetector class that runs several detectors and picks the majority vote, with a fallback to user-specified language when available. The detectors we use are: fastText with the official lid.176.bin model (loaded once, not per request) langdetect , which is lightweight and good for long texts cld3 (Compact Language Detector 3) fr
AI 资讯
Integrating AI and WordPress: From Idea to Execution, Real-World Challenges, and Practical Workflows
Integrating AI and WordPress: From Idea to Execution, Real-World Challenges, and Practical Workflows The rise of artificial intelligence has fundamentally transformed our definition of an effective website. The era of static websites that merely served as digital placeholders is over. Today, Content Management Systems like WordPress—backed by custom AI capabilities—are evolving into intelligent, automated, and interactive assistants. Below is a detailed overview of our practical experience, architecture, completed implementations, and the technical hurdles we overcame while building custom AI tools for WordPress. 1. Why Integrate AI with WordPress? (Beyond Simple Plugins) Many people view AI in WordPress as limited to off-the-shelf content generation plugins or generic chatbots. However, real value is unlocked when custom AI tools are tailored specifically to a business's unique workflow and ecosystem. Our focus when implementing AI tools relies on three core principles: Complex Process Automation: Reducing human intervention in repetitive tasks, such as automatic categorization, SEO optimization, and metadata generation. Personalized User Experience: Delivering smart, exclusive responses to users based on real-time behavior and stored data. Direct and Secure Connectivity: Seamlessly bridging Large Language Models (LLMs) with the WordPress database and native hooks via APIs. 2. Featured Projects and Case Studies Throughout our development journey, we have brought several practical AI use cases from concept to live production environments: A) Intelligent Content Engine A custom tool integrated into the WordPress admin panel that analyzes article topics to: Generate an optimized SEO structure (Headings and target keywords). Draft initial content alongside image metadata (Alt text and Descriptions). Automatically suggest internal links based on existing posts inside the wp_posts database table. B) Context-Aware AI Support Agents Upgrading basic chatbots into smart agen
开发者
I Audited 12 Open Source JWT Implementations and Found the Same 6 Mistakes
I spent last month reviewing JWT implementations across 12 open-source Node.js projects on GitHub — ranging from starter templates with 2k stars to production boilerplates used by teams at real companies. I found the same 6 mistakes in almost every one. None of these projects are bad. The developers are skilled. The mistakes are subtle, copy-paste errors from tutorials that nobody questioned. Here they are. Mistake 1 — The Secret Is Literally "secret" I found this in three separate projects: const token = jwt . sign ({ userId : user . id }, " secret " , { expiresIn : " 1h " }); This secret is in every JWT tutorial on the internet. It is in the jwt.io documentation. It is in the jsonwebtoken README. Developers copy it and forget to replace it. A 6-character ASCII secret has approximately 42 bits of entropy. A GPU cluster cracks it from a dictionary in milliseconds. Generate a real secret here — it takes 3 seconds and produces a 256-bit cryptographically random key. Mistake 2 — jwt.decode() Used in Auth Middleware // DANGEROUS — this is in a production auth middleware const decoded = jwt . decode ( req . headers . authorization . split ( " " )[ 1 ]); if ( ! decoded . userId ) return res . status ( 401 ). send ( " Unauthorized " ); jwt.decode() does not verify the signature. It reads the payload regardless of whether the token is valid, expired, or forged. An attacker can craft any payload they want and it will pass this check. The fix is two characters: jwt.verify() . const decoded = jwt . verify ( token , process . env . JWT_SECRET , { algorithms : [ " HS256 " ] }); Mistake 3 — Algorithm Not Specified in verify() // Missing algorithms option jwt . verify ( token , secret ); Without { algorithms: ['HS256'] } , the library trusts whatever algorithm is in the token's header. An attacker can create a token with alg: none and an empty signature — and jwt.verify() will accept it. Always specify the expected algorithm explicitly. Mistake 4 — Secret Committed to Version Cont
AI 资讯
I gave open claw and codex the whole internet without any api keys using this tool and it was never performed better
AI agents can reason about the web. But giving an agent unrestricted browser or network access creates a serious authority problem. The obvious solution is to restrict the tools available to the agent. Then I kept running into the opposite problem: Once the tool became sufficiently restricted, it lost many of the capabilities required to complete real work. I wanted both sides: Enough power to crawl, render, navigate, extract, capture, and investigate the web Explicit operator control over origins, credentials, budgets, browser hooks, profiles, and evidence So I built Cockroach Crawler . It is an open-source Node.js and TypeScript toolkit for AI agents, RAG pipelines, documentation indexing, research, QA, and web-data workflows. I connected it to OpenClaw and Codex , and the difference was honestly wild. Instead of giving the agents one narrow search tool, I gave them a bounded web-research layer that could crawl websites, inspect JavaScript applications, extract structured data, process PDFs, take screenshots, generate PDFs, inspect public sources, and return evidence with provenance. And for many public workflows, I did not need to configure a separate API key for every source. GitHub: https://github.com/AjnasNB/cockroach-crawler Documentation: https://cockroachcrawler.com/docs/ npm: https://www.npmjs.com/package/cockroach-crawler What changed after I connected it to OpenClaw and Codex? Before this, the agents could reason well, but their web access was limited. They could answer questions, write code, and work with the context I gave them. But once a task required deeper live-web investigation, I still had to manually combine several tools. After connecting Cockroach Crawler, they could: Crawl public websites Render JavaScript-heavy pages Follow sitemaps Search and map documentation sites Extract readable Markdown Extract structured fields with CSS, XPath, or restricted regular expressions Read local and remote PDFs Generate PDFs Take screenshots Handle bounded c
AI 资讯
llms.txt: What It Actually Does, and Why It Rots
When ChatGPT, Claude or Perplexity answers a question about your product, it is not consulting a decade of PageRank. It fetches a handful of pages and tries to work out what your site is. That is a very different retrieval problem from classic search, and most sites are accidentally hostile to it. Why sitemaps are the wrong mental model A sitemap optimises for coverage — every URL, every paginated archive, every tag page. That is correct for a crawler with a huge budget and a ranking model to sort the noise afterwards. An LLM landing on your site has neither. It has a limited context window and one shot. If the first thing it ingests is 400 URLs of ?page=17 and /tag/misc , your three genuinely useful guides are buried. llms.txt inverts this. It is a small markdown file at your root that optimises for priority : # Your Product > One-line description of what this actually does. ## Docs - [ Quickstart ]( https://example.com/docs/quickstart ) : Install and first request in 5 minutes - [ API Reference ]( https://example.com/docs/api ) : Every endpoint with request/response examples Two rules make or break it: Every link carries a description. The colon-suffix annotation is what lets a model decide whether to fetch a page. A bare link list is barely better than a sitemap. Omit aggressively. If a page does not answer a question someone would ask, it does not belong. llms-full.txt and the context tradeoff llms-full.txt inlines expanded content rather than linking out, so a model can ingest everything in one request. This is genuinely useful for compact docs — and actively harmful for large sites, where you will blow the context window and get truncated mid-document. Rough heuristic: if your docs exceed roughly 50k tokens, ship llms.txt alone and let models fetch selectively. The part nobody mentions: it rots This is where most implementations quietly fail. You write the file, ship it, and three months later half the descriptions describe features you renamed and two links 4