a16z-backed Base Power is offering cheaper electricity to the power grid that needs it most
Base Power is skipping the PJM's troubled interconnection queue by placing its batteries at people's homes, offering backup services in exchange.
找到 1182 篇相关文章
Base Power is skipping the PJM's troubled interconnection queue by placing its batteries at people's homes, offering backup services in exchange.
Code generation tools are powerful and can significantly accelerate development work. Their main limitation is not capability, but context. Without access to organizational knowledge, internal conventions, and system-specific patterns, generated output often requires careful verification. This is why generation tools work best when paired with AI code search, as the latter provides immediate visibility into the existing codebase, making it easier to align AI-generated changes with the realities of the system. In regulated environments, the adoption model may look different. Security or compliance constraints can restrict the use of cloud-based code generation. AI code search still improves developer efficiency across implementation, review, and documentation workflows by enabling fast navigation and comprehension of large multi-repository codebases. What is AI code intelligence, and how does it help in practice? Code intelligence tools help developers find and understand existing code. If a search returns a poor result, the developer simply searches again. Nothing changes in your codebase. Code search also integrates without friction. No new review processes, no changes to CI/CD, no new permissions. Generation tools require policies for AI-written code that stall many pilots before they produce data. Clear metrics for measuring AI code intelligence An AI code search assistant only reads your code, which makes it much easier to measure its impact. You can track simple things like: • how long it takes to find the right piece of code • how quickly new developers get up to speed • how many hours the team spends searching each week If your team of 20 developers each spends 5 hours weekly understanding code, that equals 100 hours of engineering time. At $75 per hour, that’s $360,000 per year. Assume 10% reduction recovers $36,000, a realistic input for an AI ROI framework for tech teams. Faster path to Phase 3 expansion Code generation tools face tough questions from secu
A follow-up to Part 1 ( EN on LinkedIn · RU on Habr ), where we stood up a two-tier PKI: a Root CA and three intermediate CAs — Person, Server and Code. At the end of Part 1 I promised we'd learn to revoke certificates and run OCSP. That's what we'll do here. Like Part 1, this article is meant as a hands-on manual : for every command and extension we touch, there's an extended reference of the parameters you can actually use — with syntax, allowed values, defaults and gotchas. If you don't need a given option right now, just skim past the table; it's there so you don't have to dig through man later. Each section has the same shape: first the working commands for the common case, then the full parameter reference. Tested on versions. Flag names, defaults and extension syntax were verified against the official documentation of OpenSSL master , plus nginx and Apache mod_ssl. OpenSSL evolves per branch: anything marked "OpenSSL 4.0 / master" (for example the nonss qualifier on authorityKeyIdentifier ) is not yet available in the stable 3.x line. If you're on OpenSSL 3.0–3.6, double-check the disputed options with openssl <cmd> --help or your version's man before copy-pasting config. The numeric openssl verify error codes above 40 also shifted between branches — confirm them against your version's header. In this part: How a revoked certificate differs from an expired one, and why we need two mechanisms — CRL and OCSP. Adding the distribution points (CDP) and AIA to the config so issued certificates "tell" verifiers where to check them. Revoking a certificate and working with the CA database. Generating a CRL and inspecting it with openssl crl . Checking revocation with openssl verify . Running an OCSP responder: issuing its certificate, starting the daemon, querying status. Publishing the CRL and OCSP over HTTP (nginx), configuring OCSP stapling and revocation checking on the web server. All paths, file names and config sections are the same as in Part 1. Where you name
Most TypeScript projects treat environment variables like second-class citizens. They're string | undefined everywhere, asserted with ! and parsed with parseInt() . TypeScript can't help because process.env is typed as Record<string, string | undefined> . Schema-based validation fixes this. But most solutions bring zod, which adds 50 KB to your bundle. CtroEnv does it with zero dependencies and 6.5 KB gzipped. How Inference Works The type system reads each validator's configuration at compile time: type InferredValue < V > = V extends Validator < infer T > ? V [ " metadata " ] extends { hasDefault : true } ? T // .default() → non-nullable : V [ " metadata " ] extends { optional : true } ? T | undefined // .optional() → nullable : T // required → guaranteed present : never This means the schema defines the type: const env = defineEnv ({ PORT : number (). port (). default ( 3000 ), // ^? number — default makes it always present DB_URL : string (). url (), // ^? string — required DEBUG : boolean (). optional (), // ^? boolean | undefined — optional NODE_ENV : pick ([ " dev " , " prod " , " staging " ] as const ), // ^? "dev" | "prod" | "staging" — exact union }) No interface Env { ... } . No z.infer<typeof Schema> . Add a new validator, and the type updates automatically. Default vs Optional vs Required The three states and their types: Declaration Type Runtime behavior string() string Required — throws if missing string().optional() `string \ undefined` string().default("x") string Falls back to "x" string().optional().default("x") string Default overrides optional TypeScript reflects this exactly. Optional gives you | undefined . Default removes it. The as const Requirement pick() needs as const to preserve literal types: pick ([ " dev " , " prod " ]) // type: string — widened pick ([ " dev " , " prod " ] as const ) // type: "dev" | "prod" — exact union Without as const , TypeScript widens the array to string[] and you lose the union. Exhaustive Checking With exact l
As UK police embrace the AI revolution, a WIRED investigation reveals the messy inside story of one region’s experiment with predictive analytics.
Dai metadati in una lingua a 20 localizzazioni senza impazzire tra click e schermate: un flusso pratico per indie e piccoli team. Localizzare un’app non significa solo tradurre le stringhe dell’interfaccia. Una buona parte dell’acquisizione organica passa dai metadati su App Store Connect : titolo, sottotitolo, descrizione e keyword. Il problema è che, quando provi a farlo “a mano” dal pannello web, diventa subito un lavoro di pura resistenza: apri la scheda, cambi lingua, compili i campi, salvi, ripeti. Ora moltiplica per 10–20 lingue. Per molti indie (e in generale per chi ha poco tempo e zero voglia di click ripetitivi) il punto di svolta è usare ASC CLI per rendere questa attività automatizzabile, ripetibile e verificabile . Perché la localizzazione dei metadati è un caso d’uso perfetto per una CLI Dal punto di vista del flusso di lavoro, i metadati App Store hanno tre caratteristiche che li rendono ideali per l’automazione: Sono campi strutturati (title, subtitle, description, keywords): non stai “inventando” contenuti ogni volta, stai trasformando contenuti. Sono ripetitivi per lingua : la sequenza di operazioni è identica, cambia solo la locale. Sono tanti : più lingue aggiungi, più l’approccio manuale scala male (tempo, errori, incoerenze). Con una CLI, invece, il lavoro si sposta dal “fare cose” al definire un processo : prendi i metadati di partenza, generi le varianti linguistiche, applichi l’update in batch. Cosa conviene localizzare (e cosa no) In genere ha senso includere in un passaggio di localizzazione “massiva”: App name / title (attenzione ai limiti e ai trademark) Subtitle (spesso è la parte più ASO-oriented) Description (qui conta più la leggibilità che la traduzione letterale) Keywords (campo delicato: va adattato, non tradotto alla cieca) Al contrario, è meglio trattare con più cautela: Claim e frasi marketing molto creative : in alcune lingue risultano innaturali se tradotte letteralmente Keyword strategy : la ricerca utenti cambia per mercat
You added a useLayoutEffect to measure a tooltip, shipped it, and the next time your Next.js (or Remix, or Gatsby) dev server rendered a page on the server, the console lit up: Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. The warning is correct, the suggested fix ("only use it on the client") is unhelpful, and the obvious workaround — just switch to useEffect — quietly reintroduces the visual bug you used useLayoutEffect to kill in the first place. useIsomorphicLayoutEffect is the small hook that resolves the standoff. This post explains exactly why the warning happens, why the two naive fixes are both wrong, and what the one-line hook actually does. Why useLayoutEffect Exists At All React gives you two effect hooks that look nearly identical: useEffect runs after the browser has painted. Its callback is queued and fires asynchronously once the frame is on screen. useLayoutEffect runs before the browser paints, synchronously, right after React has mutated the DOM but before the user sees anything. That timing difference is the whole point. If you need to read layout — getBoundingClientRect , scrollHeight , the measured width of a node — and then write a style based on it, you have to do it before paint. Otherwise the user sees one frame of the wrong layout, then a flicker as your useEffect corrects it. The canonical example is a tooltip that has to position itself relative to its own measured size: function Tooltip ({ targetRect , children }) { const ref = useRef < HTMLDivElement > ( null ); const [ pos , setPos ] = useState ({ top : 0 , left : 0 }); useLayoutEffect (() => { const { height , width } = ref . current ! . getBoundingClientRect (); // place the tooltip above the target, centered s
Apache Iceberg looked like the answer to everything when we first adopted it. Open format, ACID transactions, time travel, schema evolution. We migrated our Hive tables, ran a few queries, and felt good about life. Three months later, our S3 costs doubled. Queries that used to take 10 seconds were taking 4 minutes. Metadata operations were timing out. Nobody on the team could explain why. That was the beginning of a real education in how Iceberg actually behaves in production. This post covers what I wish someone had told us before we went all-in. The Small Files Problem Is Not Optional Iceberg is append-friendly by design. Every micro-batch write, every streaming insert, every incremental load creates new Parquet files. Each file also gets its own metadata entry. After a week of hourly loads, you might have 10,000 files in a single partition where you wanted 20. The result: Iceberg's metadata layer has to plan queries across thousands of file manifests. Planning takes longer than execution. Your 10-second query becomes a 4-minute query, and your users start filing tickets. Fix: automate compaction from day one. In Spark, compaction is called rewrite_data_files . The basic call looks like this: -- Run this on a schedule, not on-demand CALL iceberg_catalog . system . rewrite_data_files ( table => 'analytics.events' , strategy => 'binpack' , options => map ( 'target-file-size-bytes' , '134217728' , -- 128MB target per file 'min-input-files' , '5' -- only compact if 5+ small files exist ) ) Target file size of 128MB to 512MB is the practical sweet spot. Smaller than that, you still have too many files. Larger, and your query engines cannot parallelize reads efficiently. If you are not using Spark, PyIceberg exposes compaction through the table maintenance API (as of 0.7.x). For Flink or Trino-only shops, schedule compaction as a separate Spark job. Yes, it is annoying, but it is the right call. Hidden Partitioning Is the Feature You Are Probably Ignoring Old Hive parti
"Contract values for these efforts ballooned from nearly $2.8 billion to $5.9 billion."
Hey dev community! 👋 As developers, our inboxes often turn into a graveyard of job alerts (LinkedIn, Indeed, ZipRecruiter) and tech newsletters we subscribe to with the intention of "reading later" but never actually open. The result? Important emails get lost, and we get the dreaded "Account storage is almost full" notification. Recently, I hit that wall. I had thousands of accumulated emails. While Gmail allows you to create filters for incoming mail, it doesn't have a native feature to say: "Delete this email automatically after 7 days" . So, I decided to solve it the way we solve everything: by writing some code. 🛠️ The Solution: Google Apps Script + JavaScript Since the Google Workspace ecosystem runs on a JavaScript-based environment, I put together a custom script. Fun fact: a simple loop originally failed due to Google's strict 6-minute execution limit. To fix this, I optimized the code to process emails in batches of 100 , preventing the server from timing out. Here is the final production-ready script: function cleanSpamTsunami() { // 1. Loop to delete ALL Job Board emails in batches of 100 var continueJobSearch = true; while (continueJobSearch) { var jobThreads = GmailApp.search('computrabajo OR indeed OR linkedin OR OCC OR neuvoo OR talent.com OR jooble', 0, 100); if (jobThreads.length > 0) { Logger.log('Deleting a batch of ' + jobThreads.length + ' job alert emails...'); GmailApp.moveThreadsToTrash(jobThreads); } else { Logger.log('No more job alerts found!'); continueJobSearch = false; // Break the loop } } // 2. Loop to delete old Newsletters (older than 7 days) in batches of 100 var continueNewsletters = true; while (continueNewsletters) { var newsletterThreads = GmailApp.search('unsubscribe OR "cancelar suscripción" older_than:7d', 0, 100); if (newsletterThreads.length > 0) { Logger.log('Deleting a batch of ' + newsletterThreads.length + ' old newsletters...'); GmailApp.moveThreadsToTrash(newsletterThreads); } else { Logger.log('No more old newslett
There's a specific kind of bad documentation that I think we've all suffered through. You search for "what is a goroutine" or "how do database transactions work" and you get one of two things: either a six-page academic paper that assumes you already know the answer, or a tutorial so watered-down it covers nothing real. What you actually want is someone like that senior engineer at your company the one who, when you finally work up the nerve to ask a dumb question, sits down and actually explains the thing. Not just the what, but the why. Not just the happy path, but the part where you'll get confused at 2am and what to do about it. I've been building that resource. It's called The Missing Manual. Here's the pitch in one sentence: it's a free, growing library of developer guides written like advice from a battle-hardened friend who genuinely wants you to understand the thing, not just copy the code. Some examples of what's in there right now: Reading a Stack Trace at 2am — starts with "that wall of text is not an attack, it's a map," then teaches you the four-step method that works in Python, JavaScript, Java, or whatever you're using. Includes the site-packages/ vs your-own-code trick that turns 40-line traces into 2-line ones. Go From Zero - covers the basics, but also the deep stuff that most Go tutorials skip: what the GMP scheduler actually does, how escape analysis decides what lives on the heap, why goroutines are cheap in a way OS threads aren't. Mental-model-first, the whole way through. Docker Without the Magic - doesn't just show you docker run. Explains what a namespace and a cgroup actually are, so when Docker does something weird, you have somewhere to start. Why Is My Query Slow? - the real answer, including EXPLAIN, index cardinality, the N+1 problem, and what "using index" in a query plan actually means vs what you want it to mean. There are 160+ guides across debugging, databases, infrastructure, networking, APIs, AI/ML, performance, and programmin
UK-based staff at the Wikimedia Foundation (WMF), the nonprofit that supports Wikipedia, are pushing forward with their unionization drive. On Wednesday, the staff sent a letter to WMF management requesting the organization voluntarily recognize the union. "The WMF has undergone a period of significant change in recent months, escalating workers' concerns over transparency, trust, and […]
Figma has revealed some new design and coding product updates at its annual Config conference that aim to help creatives "push their ideas further" and automate tedious tasks with AI. Part of this is a reimagined canvas that's now optimized for full-stack development, according to Figma, bringing teams, AI agents, tools, and materials "together in […]
Semana passada eu passei três horas debugando um bug que deveria levar 20 minutos. O problema? Um módulo de validação escrito em 2019 que ninguém mexe "porque funciona". Spoiler: não funcionava mais, e quando finalmente abri o arquivo, encontrei um // TODO: refactor this datado de 2020. Por que legacy vira bola de neve A indústria trata código legado como se fosse dívida técnica opcional — algo que você paga "quando tiver tempo". Mas código legado se comporta mais como mofo: se espalha, contamina áreas adjacentes, e quanto mais você ignora, mais cara fica a limpeza. O ciclo é previsível: você herda um projeto ou feature antiga, vê que está "meio bagunçado mas roda", adiciona sua feature com um if a mais, e segue em frente. Seis meses depois, outra pessoa faz o mesmo. Um ano depois, aquele arquivo tem 800 linhas, cinco níveis de if aninhados, e zero testes. Ninguém mais entende o fluxo completo, então cada mudança vira uma sessão de especulação: "se eu mexer aqui, quebra ali?" O custo real de esperar Esse código "que funciona" tem um custo oculto que aparece em três formas: Velocidade de desenvolvimento despenca. Features que deveriam levar dois dias levam uma semana porque você passa mais tempo entendendo o contexto do que escrevendo código novo. Bugs aumentam exponencialmente. Código sem testes e com lógica embolada é um gerador de regressões. Você corrige um edge case e quebra outro que nem sabia que existava. Onboarding vira tortura. Novo dev no time? Boa sorte explicando por que aquele service tem três formas diferentes de fazer autenticação, ou por que a mesma validação está copiada em sete lugares. Sinais de que você está sentado em cima de uma bomba Nem todo código antigo é legacy tóxico. Aqui estão os red flags que indicam que você precisa agir agora: // Red flag #1: comentários mentirosos ou inúteis function processPayment ( order ) { // Process the payment const user = order . user ; // TODO: fix this later // HACK: don't touch this, breaks prod if ( user
If you've ever tried to pull live options data into a Python script, you've probably hit the same wall I did: the cheapest real-time providers start at $99/mo. Here's how to do it for $20/mo — or free if you stay within 1,000 credits/day. What You'll Need Python 3.8+ requests library ( pip install requests ) An API key from market-option.com (free tier available, no card required) Fetching a Full Options Chain import os import requests API_KEY = os . environ [ " MARKET_OPTIONS_KEY " ] BASE_URL = " https://market-option.com/api/v1 " def get_chain ( ticker : str ) -> list [ dict ]: res = requests . get ( f " { BASE_URL } /options/chain/ { ticker } " , params = { " apiKey " : API_KEY }, ) res . raise_for_status () return res . json ()[ " results " ] contracts = get_chain ( " SPY " ) print ( f " { len ( contracts ) } contracts returned " ) print ( contracts [ 0 ]) Each contract in results looks like this: { "details" : { "contract_type" : "call" , "strike_price" : 530 , "expiration_date" : "2026-01-17" , "ticker" : "O:SPY260117C00530000" }, "last_quote" : { "bid" : 3.45 , "ask" : 3.50 , "midpoint" : 3.475 }, "greeks" : { "delta" : 0.42 , "gamma" : 0.031 , "theta" : -0.18 , "vega" : 0.29 }, "implied_volatility" : 0.182 , "open_interest" : 12418 } Filtering by Expiration and Strike def get_near_the_money ( ticker : str , expiration : str , spot : float , width : float = 0.05 ): """ Return contracts within ±width% of spot price. """ contracts = get_chain ( ticker ) low = spot * ( 1 - width ) high = spot * ( 1 + width ) return [ c for c in contracts if c [ " details " ][ " expiration_date " ] == expiration and low <= c [ " details " ][ " strike_price " ] <= high ] atm = get_near_the_money ( " SPY " , " 2026-01-17 " , spot = 530 ) for c in atm : print ( c [ " details " ][ " strike_price " ], c [ " details " ][ " contract_type " ], c [ " last_quote " ][ " bid " ], c [ " greeks " ][ " delta " ], ) Scanning for High IV Contracts def high_iv_scan ( ticker : str , iv_threshold :
Named Jalapeño, the new processor was designed specifically for the unique needs of OpenAI's inference systems.
On April 29, 2026, Nathan Sobo published the Zed 1.0 announcement post on Zed's blog. The post landed on Hacker News at 2,047 points and 663 comments — the highest-engagement HN story in the present cache by a substantial margin. The launch announcement is a milestone marker after five years of development, roughly a million lines of Rust, and a custom GPU-accelerated UI framework called GPUI that the Zed team built from scratch rather than building atop Electron, Chromium, or any other browser engine. The structural argument Zed has been making for the last several years is condensed in one sentence from Sobo's post: "Instead of building Zed like a web page, we built it like a video game, organizing the entire application around feeding data to shaders running on the GPU." The video-game framing is not metaphorical. Zed's editor surface is composited by feeding glyph atlases, syntax-tree-derived color spans, and pane-layout geometry into GPU shaders the way a video-game engine composites its frames. The reason this matters is the reason the Zed team gave for starting over from the Atom era: Atom was built as a fork of Chromium, and the same team that built Atom is the team that spawned Electron. The Atom-Electron-VSCode lineage is, in the historical-causal sense, Zed's own. Sobo's post is unusually direct about the inherited limitation: "Electron eventually became the foundation of VS Code (which today seems to be forked into a new AI code editor every other week). Web technology offered an easy path to shipping flexible software, but it also imposed a ceiling. No matter how hard we worked, we couldn't make Atom better than the platform it was built on." The 1.0 announcement is, in part, a statement that the rebuild from scratch has finally cleared that ceiling. Who built it Zed's three co-founders all worked on Atom at GitHub before founding Zed Industries in 2021. Nathan Sobo led the Atom team from 2011 to 2018; he also co-led Teletype for Atom, one of the first
Você já fez um commit no repositório do trabalho e percebeu que estava com o seu e-mail pessoal? Ou o contrário? Esse é um dos erros mais comuns de quem usa Git com múltiplas contas no mesmo computador. Neste tutorial você vai aprender a configurar tudo corretamente, de uma vez, usando chaves SSH separadas e .gitconfig condicional — sem gambiarras. O problema Por padrão o Git usa uma configuração global: git config --global user.name "Seu Nome" git config --global user.email "seu@email.com" Isso significa que todos os repositórios no seu computador usam o mesmo usuário. Quando você tem contas separadas (ex: joao@empresa.com no GitLab da empresa e joao@gmail.com no GitLab pessoal), os commits vão sair com o e-mail errado. A solução profissional envolve duas partes: Chaves SSH separadas para cada conta .gitconfig condicional que aplica o usuário certo — e a chave SSH certa — por pasta Passo 1 — Gerar as chaves SSH Abra o terminal e gere uma chave para cada conta. Use nomes diferentes para não sobrescrever: # Chave para a conta pessoal ssh-keygen -t ed25519 -C "joao@gmail.com" -f ~/.ssh/id_ed25519_pessoal # Chave para a conta do trabalho ssh-keygen -t ed25519 -C "joao@empresa.com" -f ~/.ssh/id_ed25519_trabalho 💡 Por que ed25519 ? É o algoritmo mais moderno, mais seguro e recomendado pelo GitHub, GitLab e Bitbucket. Evite RSA a menos que seu servidor seja muito antigo. Ao final você terá quatro arquivos em ~/.ssh/ : id_ed25519_pessoal ← chave privada (nunca compartilhe) id_ed25519_pessoal.pub ← chave pública (você registra no GitLab) id_ed25519_trabalho id_ed25519_trabalho.pub Passo 2 — Registrar as chaves no GitLab Para cada conta: Copie o conteúdo da chave pública: # Pessoal cat ~/.ssh/id_ed25519_pessoal.pub # Trabalho cat ~/.ssh/id_ed25519_trabalho.pub Acesse Settings → SSH and GPG keys → New SSH key na conta correspondente e cole o conteúdo. Faça isso nas duas contas , cada uma com a sua respectiva chave pública. Passo 3 — Configurar o Git por pasta (o pulo do gato)
Why I Stopped Picking AI Models by Hype and Started Picking by Speed Three months ago I almost lost a $14,000 retainer because my chatbot felt sluggish. The client didn't say "your TTFT is too high." They said "it feels dumb." That's freelancer code for "users are bouncing and I'm about to find someone else." I rebuilt that bot in a weekend using a model I'd never even heard of six weeks earlier, dropped average response time from 1.4 seconds to under 300ms, and the client renewed for another six months. That single pivot paid for my rent. So I went down a rabbit hole. I ran the same speed test on every model I could get my hands on through Global API's unified endpoint. Fifteen models. Same prompt. Same regions. Ten iterations each. I'm writing this up because if you're billing by the hour or running a side hustle on a shoestring, speed isn't a vanity metric — it's a profit metric. Let me show you what I found. The Setup (How I Actually Ran the Tests) I'm not a researcher with a rack of GPUs. I'm a guy with a M2 MacBook, a $19/mo Hetzner box, and a stopwatch in the form of Python's time.perf_counter() . Here's how I kept it honest. Date window: All tests run on May 20, 2026 Regions tested: US East (Ohio) and Asia (Singapore) Prompt used: "Explain recursion in 200 words" — boring on purpose, because boring prompts are where most apps actually live Output length: Roughly 150 tokens per run Iterations: 10 runs per model per region, average recorded Streaming: Yes, SSE throughout Endpoint: Global API at https://global-apis.com/v1 I measured two things: TTFT (time to first token — the lag before the user sees anything move) and sustained tokens per second (how fast the words actually arrive after that). Both matter. TTFT is the "is this thing broken?" feeling. Tokens per second is the "is this thing fast?" feeling. Here's the script I used, stripped down to the essentials: import time import requests from statistics import mean API_KEY = " your-global-api-key " BASE_URL
How to Use Chinese LLMs Without a Chinese Phone Number If you've tried signing up for any Chinese AI service, you've seen the same message: Please enter your phone number (+86) to receive a verification code. This single requirement blocks most overseas developers from accessing some of the best-performing and most cost-effective LLMs on the market. This guide covers every workaround I've found — from least to most practical. The Problem China's major AI labs produce world-class models: DeepSeek — DeepSeek V4-Pro matches GPT-4o within 3-5% on coding benchmarks Qwen (Alibaba) — Qwen 3.7-Max beats GPT-4o on long-context tasks (256K tokens) GLM (ZhipuAI) — GLM-4.5 is competitive with Claude for reasoning tasks Baichuan — Strong for Chinese-language generation But every single one requires: A +86 Chinese phone number for registration Alipay or WeChat Pay for billing Chinese-language documentation Method 1: Virtual Chinese Phone Numbers (Fragile) Services like SMS-activate and 5sim offer temporary Chinese phone numbers for ~$1-2. The problem: Chinese providers have gotten aggressive about flagging virtual numbers. Your account gets banned within days. You lose any balance you've added. ❌ Not recommended — too unreliable for production use. Method 2: Third-Party Gateway Services (Recommended) The most practical solution is a gateway that handles the China-side complexity for you. These services: Maintain their own Chinese accounts and infrastructure Register with real Chinese business entities Handle Alipay/WeChat billing on their end Expose everything through a standard OpenAI-compatible API What this means for you: Sign up with email (no phone number needed) Pay via Stripe or PayPal Get a standard API key Use the OpenAI Python/Node.js SDK as-is Migration example (Python): # Before — can't access Chinese models at all # client = OpenAI(api_key="...") # Only works for OpenAI # After — full access to Chinese models client = OpenAI ( base_url = " https://api.tokenmaster.com