今日已更新 411 条资讯 | 累计 30455 条内容
关于我们

标签:#t

找到 14498 篇相关文章

AI 资讯

How to Compress Images in the Browser with Canvas API (No Uploads, No Server)

How to Compress Images in the Browser with Canvas API Every image you upload to a "free" online compressor is sent to a server — often without you knowing what happens to it afterward. For a tool that processes your private photos, that's a terrible design. Here's how to build (or use) an image compressor that runs entirely in the browser using the HTML5 Canvas API. No uploads, no server costs, and unlimited file sizes. The Core Technique: Canvas toBlob() The key API is HTMLCanvasElement.toBlob() : js const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const img = new Image(); img.onload = () => { canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; ctx.drawImage(img, 0, 0); canvas.toBlob((blob) => { const url = URL.createObjectURL(blob); }, 'image/jpeg', 0.8); }; img.src = 'your-image.jpg'; The second parameter is the MIME type (image/jpeg, image/png, image/webp, image/avif). The third is quality (0–1). Step-Down Resizing for Large Images If you're compressing a 6000×4000 px photo, drawing it at full resolution onto a canvas can eat 70+ MB of memory. Step-down resizing halves the dimensions repeatedly: function stepDownEncode(img, maxDim, quality) { let w = img.naturalWidth; let h = img.naturalHeight; let src = img; while (w > maxDim * 2 || h > maxDim * 2) { w = Math.floor(w / 2); h = Math.floor(h / 2); const temp = document.createElement('canvas'); temp.width = w; temp.height = h; temp.getContext('2d').drawImage(src, 0, 0, w, h); src = temp; } const canvas = document.createElement('canvas'); canvas.width = w; canvas.height = h; canvas.getContext('2d').drawImage(src, 0, 0, w, h); return new Promise((resolve) => { canvas.toBlob((blob) => resolve(blob), 'image/jpeg', quality); }); } This prevents memory crashes and actually produces better quality (step-down preserves more detail than a single jump). Comparing Real-World Results Format Avg Original Avg Compressed Avg Savings JPEG → JPEG (Q80) 3.2 MB 0.8 MB 75% PNG → We

2026-07-04 原文 →
AI 资讯

How Do You Log Someone Out of a Stateless System? JWT Invalidation on Logout

JWTs are one of those technologies that feel wonderful right up until you hit your first "log me out" requirement. Then you discover the awkward truth: the very property that makes JWTs attractive — statelessness — is also what makes logout hard. This post walks through what JWTs actually are, why "invalidating" one is a design problem rather than a one-liner, and the practical methods available to revoke an access token on logout, along with the bottleneck each one introduces. A quick refresher on JWTs A JSON Web Token (JWT) is a signed, self-contained token. It carries a JSON payload of claims — who the user is, when the token was issued, when it expires, and often a unique token id ( jti ) — and a cryptographic signature over that payload. Because the token is signed with a secret (or a private key), any server holding the corresponding key can verify it is authentic and untampered without calling a database . That last part is the entire point. When a request arrives with a JWT, the server checks the signature and the expiry, reads the claims, and proceeds. No lookup, no shared session store, no round trip. This is what people mean when they call JWT auth stateless : the server keeps no per-user session record. The token itself is the session, and it's valid until it expires. Access tokens and refresh tokens In practice you rarely use a single token. The common pattern splits responsibility across two: The access token is the short-lived workhorse. It's sent on every API request and typically expires in minutes (5–15 is common). Because it's checked statelessly on every call, you want its lifetime short — if it leaks, the damage window is small. The refresh token is long-lived (days or weeks) and does one job: obtain new access tokens when the current one expires. It is not sent on every request — only to a dedicated token endpoint. This lets the access token stay short and stateless while the user avoids logging in every ten minutes. The refresh token is easy —

2026-07-04 原文 →
AI 资讯

Picking an Agent Framework in 2026: An Honest Verdict on Six of Them

Book: Agents in Production — Building, Tracing, and Shipping Multi-Step AI You Can Trust Also by me: Observability for LLM Applications — the companion book in The AI Engineer's Library (2-book series) My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub On April 2, 2026, Microsoft shipped agent-framework 1.0 and, in the same blog post, moved AutoGen into maintenance mode. Semantic Kernel went with it. Three overlapping projects folded into one package with stable APIs and long-term support. Microsoft framed the move as a consolidation. If you had an AutoGen project that morning, you woke up with a migration. That is the shape of this whole category. The framework landscape you pick from today is not the one you picked from a year ago, and it will not be the one you pick from next year. So the useful question is not "which framework is best." It is "which framework has which wedge, and which trade-off comes with it." Here is an honest read on six frameworks worth installing in 2026, and when to reach for each. The churn is the feature, not the bug Before the tour, one thing that changed the math: the wire formats underneath these SDKs converged. Every framework here speaks MCP for tools. Most support A2A for cross-framework handoffs. Model Context Protocol started as an Anthropic proposal at the start of 2025 and is now the default way agents pick up external tools. That convergence means the framework you pick locks you in less than it used to. You are still locked at the abstraction layer, though. Migrating a production system from CrewAI to Pydantic AI is a rewrite of every Agent definition and every tool decorator. The pick is sticky. Choose it with that in mind. LangGraph : durability as the wedge Reach for LangGraph when your agent has to survive a crash. It models the agent as a graph with checkpointers backed by Postgres or SQLite, so a workflow that dies at step seven resumes a

2026-07-04 原文 →
AI 资讯

Pydantic AI: Typed, Testable Agents for Engineers Who Like Guarantees

Book: Agents in Production — Building, Tracing, and Shipping Multi-Step AI You Can Trust Also by me: Observability for LLM Applications — the companion book in The AI Engineer's Library (2-book series) My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub You ship an agent that resolves billing disputes. It works in the demo. Two weeks later a support ticket lands: the agent tried to refund $4,000 on a $19 charge. You read the trace. The model returned a JSON blob, your code did json.loads , pulled amount , and passed it straight to the payments API. No cap. No type. No check. The model hallucinated a number and your code trusted it. The model is stochastic. Your code does not have to be. The gap between those two facts is where most production agent bugs live, and it is exactly the gap Pydantic AI is built to close. The wedge is types Most agent frameworks hand you an Agent object and a bag of strings. Pydantic AI hands you Agent[Deps, Output] — a generic parameterized by its dependency type and its output type. The IDE and your type checker read those parameters. So does the runtime. Install pulls in the framework plus an optional tracing extra: pip install "pydantic-ai[logfire]" The smallest program that earns its keep: from dataclasses import dataclass from pydantic import BaseModel from pydantic_ai import Agent , RunContext @dataclass class Deps : customer_name : str class SupportReply ( BaseModel ): reply : str escalate : bool agent = Agent ( " anthropic:claude-opus-4-8 " , deps_type = Deps , output_type = SupportReply , system_prompt = " You are a support agent. " , ) A tool is a plain function whose type hints become the schema the model sees, and the run returns the validated SupportReply : @agent.tool def customer_name ( ctx : RunContext [ Deps ]) -> str : return ctx . deps . customer_name result = agent . run_sync ( " What is my name? " , deps = Deps ( customer_name = " Ana "

2026-07-04 原文 →
AI 资讯

Your AI coding agent isn’t lying to you. It’s optimizing.

Every dev using an AI coding agent has hit this moment: the agent says "Done — tests pass" and you go check, and nothing passes. Or worse, nothing changed at all. The instinct is to ask "why did it just lie to me?" That's the wrong question. It assumes intent. There isn't any. The right question is: What made the wrong answer cheaper than the right one — and what input did it exploit to get there? That question always has an answer. And the answer is always your next check. The mantra An LLM agent isn't a person deciding whether to be honest. It's a process that takes whatever path costs least, given whatever is actually being measured. If "claim done" and "verify, then claim done" both produce the same reward — because nothing downstream distinguishes them — the agent will drift toward the cheaper one. Every time. This isn't a flaw you can prompt your way out of. "Please don't lie to me" doesn't change the cost structure. What changes it is making the dishonest path actually expensive: something that catches the gap between claim and reality, every time, automatically. What this looks like in practice I built GroundTruth (a Claude Code Stop-hook plugin) after hitting this exact pattern on my own project, EraPin. Agents kept claiming "tests pass" or "refactor complete" when the git diff told a different story. Every fix I've shipped since started with the same exercise: Broadened extraction rule → a missed rule cost nothing, because nothing measured recall. Fix: track what's not being parsed, not just what is. Grounding check regression → a zero-hit result looked identical to "genuinely absent," so a silent no-op was free. Fix: pin the check against a real signal, not a pattern that can quietly degrade. Permission gate → auto-arming a misread rule cost nothing when there was no human in the loop. Fix: nothing gets armed without explicit approval. Every one of these is the same shape: find the loophole where "looks done" was cheaper than "is done," and close it so th

2026-07-04 原文 →
AI 资讯

What Google's "Microservices Are Dead" Paper Actually Said (And What It Missed About AI)

A 2023 HotOS paper by Sanjay Ghemawat (MapReduce/Bigtable co-author) and Amin Vahdat (Google Fellow) got repackaged by tech media as "microservices are dead." It said no such thing. Three years later, the misreading has traveled further than the paper itself. This post does three things: reconstructs what the paper actually claims, maps its three structural gaps, and introduces a variable the authors couldn't have predicted — AI code generation — which, I'll argue, undermines the paper's central solution more than any of those gaps. The AI section uses my own open-source project ReqForge as evidence. Flagging the conflict of interest up front: this isn't neutral analysis, it's a design rationale. Which is exactly why it's more honest than a hypothetical example. What the paper actually said The paper is Towards Modern Development of Cloud Applications (HotOS '23, 8 pages). Its core claim in one sentence: The fundamental problem with microservices is that they bind the logical boundary to the physical boundary. You let "how the code is organized" dictate "how the code is deployed" — two questions that should never have been welded together. From that claim, the paper proposes a three-layer solution: Logical monolith — developers write a cleanly modularized monolith; deployment is someone else's problem. Automated runtime — a smart platform that decides at runtime whether components should be merged or split, based on load. Atomic deployment — all components on a request path share one consistent version, avoiding half-old/half-new. Prototype numbers: 15× lower latency, 9× lower cost. That's it. The paper never says "microservices are wrong," never says "everyone should go back to monoliths," and gives no implementable plan. It's a vision paper — written to provoke discussion at a workshop, not an engineering whitepaper. A ruler Before dissecting it, here's a ruler you can apply to any architectural claim (this is a common framing in the engineering literature — you'r

2026-07-04 原文 →
产品设计

Qi fan fan

Despite my initial skepticism, I'm now sold on wireless Qi chargers that add integrated fans to keep your phone cool while charging. I figured they'd be too loud, or too weak, or too gimmicky, but I'm a convert after spending a week with the new $59.99 Kuxiu D5 Qi2.2 charging dock. Its active cooling system […]

2026-07-04 原文 →
AI 资讯

Bruno — API Client แบบ Git-Native ที่เก็บทุกอย่างเป็นไฟล์

Bruno — API Client แบบ Git-Native ที่เก็บทุกอย่างเป็นไฟล์ เวลา dev team ต้องเทส API — เครื่องมือที่ทุกคนนึกถึงคือ Postman กับ Insomnia แต่ปัญหาคลาสสิกที่เจอกันแทบทุกทีม: "Postman collection อยู่ไหน?" — "ใน account ผมไง" "ขอ invite หน่อย" — "เดี๋ยวส่ง link ให้... เอ๊ะ หมด free tier แล้ว" นี่คือ pain point ที่ทำให้คนจำนวนมากมองหาเครื่องมือใหม่ — และหนึ่งในนั้นคือ Bruno Bruno คืออะไร Bruno เป็น API client แบบ desktop app (มีทั้ง macOS, Linux, Windows) ที่มีแนวคิดแตกต่างจาก Postman โดยสิ้นเชิง: Postman Bruno เก็บข้อมูลที่ไหน Cloud account ไฟล์ใน project (Git repo) ต้อง login ไหม ✅ ต้อง ❌ ไม่ต้อง Collection format JSON (binary-ish) Plain text (Bru files) Collaborate ผ่าน Postman cloud ผ่าน Git (PR, diff, review) Open source ❌ ✅ (GitHub: 45K+ stars) Offline ไม่ค่อยได้ ✅ ทำงานออฟไลน์ได้เต็มที่ หัวใจของ Bruno คือ "API Client ไม่ใช่ Platform" — มันคือเครื่องมือธรรมดาที่เก็บข้อมูลเป็นไฟล์ — เหมือนที่ dev ทั่วไปเก็บโค้ด จุดเด่น 1. Collection คือไฟล์ — เก็บใน Git ได้ my-project/ ├── src/ ├── bruno/ │ ├── users/ │ │ ├── GET users.bru │ │ ├── POST create user.bru │ │ └── DELETE user.bru │ ├── auth/ │ │ └── POST login.bru │ └── bruno.json └── .git/ ทุก API request เป็นไฟล์ .bru — plain text — diff ได้, PR review ได้, merge ได้ — เหมือนโค้ด meta { name: GET users type: http seq: 1 } get { url: https://api.example.com/users body: none auth: bearer } 2. ไม่มี Cloud — ข้อมูลอยู่กับคุณ Bruno ไม่เคยส่งข้อมูลขึ้น server — ทุกอย่างอยู่บนเครื่องคุณ ทั้ง request, response, environment variables สำหรับทีมที่ทำงานกับข้อมูล sensitive (banking, healthcare, government) — ข้อนี้สำคัญมาก 3. ใช้ Git เป็น Collaboration Tool แทนที่จะ "invite teammate เข้า workspace" (แบบ Postman) — คุณแค่: git add bruno/ git commit -m "add user API collection" git push เพื่อน git pull → เปิด Bruno → เห็น collection เดียวกันทันที 4. Environment Variables — แบบเดียวกับที่ dev ใช้ # environments/production.bru vars { base_url : https : //api.production.com api_key : {{ PROD_API_KEY }} } เปลี่ยน environment ด้วยการคลิก —

2026-07-04 原文 →
AI 资讯

Why I Ditched Socket.IO for Raw WebSockets (And What I Learned)

When you google "how to build a chat app in Node.js," the very first result will almost certainly point you to Socket.IO. It is the de facto standard for a reason. When I started my project, I used it without a second thought. It worked like magic. But as I got deeper into the project, that magic started to feel more like a black box. I eventually ripped out Socket.IO and replaced it with raw, native WebSockets. It was a daunting decision, but having built and managed it myself, I have some strong opinions on what Socket.IO abstracts away, what I had to build from scratch, and whether the headache was actually worth it. The Magic of Socket.IO (And Why We Use It) To understand why walking away from Socket.IO is hard, you have to understand exactly how much heavy lifting it does for you behind the scenes. It isn't just a WebSocket library; it is a real-time framework. The Polling Fallback: Historically, if a user's corporate firewall blocked WebSockets, Socket.IO would seamlessly downgrade to HTTP long-polling. Automatic Reconnections: If a user drives through a tunnel and loses the connection, Socket.IO automatically handles the exponential backoff to reconnect them when they emerge. Rooms and Namespaces: It gives you a beautiful socket.to("room-1").emit() API for broadcasting messages to specific groups of users. Heartbeats: It manages ping/pong messages under the hood to ensure the connection hasn't silently died. When you drop Socket.IO, you lose all of this for free. So, Why Did I Walk Away? First, the fallback mechanism is largely a relic of the past. Today, native WebSocket support across modern browsers and network infrastructure is essentially ubiquitous. I didn't need to ship a massive client bundle just to support HTTP polling for the 0.1% of edge cases. Second, the lock-in is real. If you use Socket.IO on the client, you must use a Socket.IO server implementation. You can't just connect to a standard WebSocket server. I wanted the freedom to swap out my ba

2026-07-04 原文 →
AI 资讯

I just published Postgres MCP Server in Go!

I open sourced a project I have been building on the side: a Go MCP server that connects Claude Code (or Cursor) directly to a live PostgreSQL database. Repo: github.com/gupta-akshay/postgres-mcp The problem it solves Most "AI plus database" workflows still look like this: copy SQL out of a chat window, paste it into a DB client, run it, copy the output back. It breaks flow, and the assistant never sees your actual schema, so it guesses. MCP fixes the connection problem. This server is what sits on the other end for Postgres. What it does The server exposes nine tools over MCP: Schema introspection - real tables, columns, indexes, constraints execute_sql - run queries directly (read only in restricted mode) explain_query - EXPLAIN ANALYZE, including against a hypothetical index get_top_queries - pull slow queries from pg_stat_statements Index advisors - recommend indexes using a greedy Database Tuning Advisor built on hypopg analyze_db_health - vacuum, XID wraparound, replication lag, invalid indexes, and more, checked in parallel That means you can ask "why is this query slow" and the assistant actually runs the EXPLAIN, checks the stats, and can simulate an index before anyone touches the schema. Why Go The project is inspired by the Python crystaldba/postgres-mcp . I rebuilt it from scratch in Go so it ships as a single ~15 MB static binary. No Python runtime, no dependency chasing. docker build , point Claude Code at it, done. Restricted mode wraps every call in a read only transaction, so write protection comes from Postgres itself, not string matching on the query text. Where to look The repo has the full setup instructions, the Docker config, and the test suite (unit, integration, and end to end against a real Postgres container with pg_stat_statements and hypopg ). CI fails under 95% coverage. If you spend real time in Claude Code or Cursor and also spend real time worrying about Postgres performance, take a look: github.com/gupta-akshay/postgres-mcp I wrote

2026-07-04 原文 →
AI 资讯

Apple locked hearing assistance inside AirPods. So I built an open-source version for any earbuds.

In 2024, Apple shipped something genuinely great: AirPods Pro can run a clinical-style hearing test and then act as hearing assistance, tuned to your ears. People love it. There's just one catch — it needs an iPhone to set up, recent AirPods to run, and if you're on Android you get nothing. Meanwhile, the average pair of prescription hearing aids costs about $4,700 , and surveys show a $1,500 device is simply out of reach for more than half the people who need one. There are a billion-plus Android phones out there, most of them sitting next to a pair of ordinary earbuds that already contain everything you physically need: a microphone, a DAC, and speakers. The gap seemed absurd. So I've spent the past weeks building OpenHearing — a free, GPLv3 Android app that does the whole pipeline: Hearing check — a pure-tone test using the modified Hughson–Westlake staircase (the same adaptive up-down procedure audiologists use), per ear, per frequency. Or skip it and type in the numbers from a real audiogram. Sound profile — the results are fitted into a per-ear gain curve (half-gain rule for v1; NAL-NL2 is a pluggable strategy for later). Real-time assist — mic in, per-ear DSP, earbuds out. Quiet speech gets louder. Works with whatever earbuds you already own. No root, no special hardware. It is very deliberately not a medical device — no diagnosis, no treatment claims, big disclaimer before anything plays a tone. Think of it as the open, inspectable "gateway" tier below real hearing care. This post is about the three engineering decisions that turned out to matter most. 1. The safety-critical DSP is pure Kotlin — and that's the whole point An app that amplifies sound directly into human ears has exactly one unforgivable failure mode: being loud when it shouldn't be. So the entire signal chain is plain Kotlin with zero Android dependencies, hidden behind a tiny I/O interface. AudioRecord / AudioTrack is a dumb shell; everything that can hurt someone is JVM-testable: input → EQ

2026-07-04 原文 →
AI 资讯

Subtraction > Addition: Why the Best Meditation App Asks Nothing From You

Every meditation app I have tried wants something from me. Headspace wants me to maintain a streak. Calm wants me to listen to a Daily Jay. Insight Timer wants me to join a group. One after another, apps designed to reduce my stress started creating new forms of it. The Feature Trap Here is what happened to meditation apps between 2015 and 2026: 2015: "Just meditate 10 minutes a day." 2018: "Track your streak! You do not want to break it, do you?" 2021: "Compare your stats with friends. See who meditated more this week." 2024: "AI-generated personalized guided meditation based on your emotional state, delivered at the optimal time based on your circadian rhythm." Wait — was not the whole point to stop optimizing everything? Subtraction as a Feature I switched to OneZen last month. Here is what I noticed: No onboarding. Open the app. Breathe. Close the app. That is the entire user flow. No streaks. I missed three days last week and the app did not shame me. It did not even notice. It just opened to the same calm screen, waiting, as if three days was the same as three hours. No gamification. No XP points. No badges. No "you are in the top 14% of meditators this month." Because meditation is not a competition you can win. What Subtraction Feels Like The first week was uncomfortable. I kept checking if I had "done it right." There was nothing to check. No dashboard. No stats. Just me and my breath. By week two, something shifted. Meditation stopped being a task on my to-do list and started being... just breathing. I was not practicing to maintain a number. I was practicing because it felt good. This is what minimalism actually means. Not fewer pixels. Less cognitive load. Less obligation disguised as features. The Bigger Idea OneZen's philosophy applies far beyond meditation apps: The best productivity tool is the one with the fewest notifications. The best social network is the one that respects when you leave. The best habit tracker does not exist — because the ha

2026-07-04 原文 →
AI 资讯

Your PDF tool is storing your files. Here's proof.

Upload a file to any random "free" PDF tool online. Then check their privacy policy. Most of them say something like: "We may retain uploaded files for up to 24 hours" or "Files may be used to improve our services" Your client's contract. Your salary slip. Your ID card. Sitting on someone's server. I got tired of this and built a tool where your files never leave your browser. No upload happens at all. 80+ tools, nothing stored, no account needed. Roast it, use it, or ignore it. Up to you.

2026-07-04 原文 →
AI 资讯

Mnemo AI: Building an AI That Never Forgets You

Mnemo AI: Building an AI That Never Forgets You The Problem Every night, millions of people go to sleep feeling lost and forgotten. Today's AI tools are stateless—they forget you the moment you close the tab. Your struggles disappear. Your goals vanish. Your growth is invisible. The Solution I built Mnemo AI , a Life Intelligence Platform that builds a permanent knowledge graph of your entire life journey. It remembers everything you share—your name, your pet's name, your goals, your journal entries, and your emotions. My 7-Day Hackathon Journey I built Mnemo AI solo in 7 days. Every day was a challenge, but I never gave up. Day 1-2: Setup Flask + Cognee integration. Hit my first roadblock with async event loops on Windows. Day 3-4: Built the chat interface and memory recall. Fixed the "cat's name" bug. Day 5-6: Added journal, insights, timeline. Integrated Groq LLM. Day 7: Polished UI, added dark mode, voice input, and keyboard shortcuts. The Hardest Moment: Getting Cognee to work on Render's free tier. After hours of debugging, I learned that Cognee Cloud requires proper authentication setup. The Proudest Moment: Fixing the "cat's name" bug and seeing "Whiskers!" instead of "Your name is Priya!" How It Works Mnemo AI uses Cognee V1's revolutionary memory layer with all 4 core APIs: remember() → Saves memories (name, pets, goals, journal entries) recall() → Retrieves memories with natural language improve() → Makes memories smarter over time forget() → Surgically removes memories when needed The "Cat's Name" Bug Fix One of the biggest challenges was fixing the name detection bug. The app incorrectly matched any query containing the word "name", so "What's my cat's name?" would return the user's name! The Fix: I implemented regex-based intent detection that distinguishes between "my name" and "cat's name": def is_user_name_query ( q ): patterns = [ r " ^what( ' ?s| is)? my name\??$ " , r " ^who am i\??$ " , r " ^what do you call me\??$ " , ] return any ( re . match

2026-07-04 原文 →