Compare commits

...

9 Commits

Author SHA1 Message Date
Simon 62519416bb chore(version): bump version to 0.0.24 2026-01-14 18:34:55 +08:00
Simon a1e70e663d feat(PageController): exclude aria-hidden elements 2026-01-14 18:04:31 +08:00
Simon 338e317be1 chore(website): fix homepage overflow 2026-01-14 17:45:49 +08:00
Simon 9a66d5205f feat(website): display version in header and load from page-agent package 2026-01-14 17:42:18 +08:00
Simon 7d45bf6598 feat(website): update CDN links and usage 2026-01-14 17:27:35 +08:00
Simon 78ee72eea4 chore(version): bump version to 0.0.23 2026-01-14 15:46:10 +08:00
Simon 3b71c535b1 fix: clean up debug code 2026-01-14 15:23:02 +08:00
Simon 6615f7b300 Merge pull request #110 from alibaba/fix/panel-text-uncompleted
feat: add HTML escaping to Panel
2026-01-14 15:17:43 +08:00
Simon 38caae5e23 feat: add HTML escaping to Panel 2026-01-14 15:15:51 +08:00
21 changed files with 290 additions and 185 deletions
+35 -23
View File
@@ -28,7 +28,22 @@
## 🚀 快速开始 ## 🚀 快速开始
### NPM 安装 ### 快速体验 (Demo CDN)
最快的体验方式:
```html
<script src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js" crossorigin="true"></script>
```
> ⚠️ **仅用于技术评估。** Demo 模型有速率限制和使用限制,生产环境请使用 NPM 方式。
| 位置 | URL |
| ------ | --------------------------------------------------------------------------------------- |
| 全球 | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
| 中国 | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
### NPM 安装(推荐)
```bash ```bash
npm install page-agent npm install page-agent
@@ -37,40 +52,37 @@ npm install page-agent
```javascript ```javascript
import { PageAgent } from 'page-agent' import { PageAgent } from 'page-agent'
// 测试接口
// @note: 限流,限制 prompt 内容,限制来源,随时变更,请替换成你自己的
// @note: 使用 DeepSeek-chat(3.2) 官方版本,使用协议和隐私策略见 DeepSeek 网站
const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy'
const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const agent = new PageAgent({ const agent = new PageAgent({
model: DEMO_MODEL, model: 'deepseek-chat',
baseURL: DEMO_BASE_URL, baseURL: 'https://api.deepseek.com',
apiKey: DEMO_API_KEY, apiKey: 'YOUR_API_KEY',
language: 'zh-CN', language: 'zh-CN',
}) })
await agent.execute('点击登录按钮') await agent.execute('点击登录按钮')
``` ```
### CDN 集成 ### CDN 引入
Fastest way to try PageAgent is to include it via CDN. Demo model will be used by default. 适用于无法使用 NPM 的环境,用法与 NPM 一致:
| Location | URL |
| -------- | ----------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js |
| China | https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js |
```html ```html
<script <script src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js" crossorigin="true"></script>
src="https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js" <script>
crossorigin="true" const agent = new PageAgent({
type="text/javascript" model: 'deepseek-chat',
></script> baseURL: 'https://api.deepseek.com',
apiKey: 'YOUR_API_KEY',
})
await agent.execute('点击登录按钮')
</script>
``` ```
| 位置 | URL |
| ------ | ----------------------------------------------------------------------------------- |
| 全球 | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js |
| 中国 | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js |
## 🏗️ 架构设计 ## 🏗️ 架构设计
PageAgent adopts a simplified monorepo structure: PageAgent adopts a simplified monorepo structure:
+35 -23
View File
@@ -28,7 +28,22 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
## 🚀 Quick Start ## 🚀 Quick Start
### NPM Installation ### Quick Try (Demo CDN)
Fastest way to try PageAgent:
```html
<script src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js" crossorigin="true"></script>
```
> ⚠️ **For technical evaluation only.** Demo model has rate limits and usage restrictions. Use NPM for production.
| Location | URL |
| -------- | --------------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js |
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js |
### NPM Installation (Recommended)
```bash ```bash
npm install page-agent npm install page-agent
@@ -37,40 +52,37 @@ npm install page-agent
```javascript ```javascript
import { PageAgent } from 'page-agent' import { PageAgent } from 'page-agent'
// test server
// @note: rate limit. prompt limit. Origin limit. May change anytime. Use your own llm!
// @note Using official DeepSeek-chat(3.2). Go to DeepSeek website for privacy policy.
const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy'
const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const agent = new PageAgent({ const agent = new PageAgent({
model: DEMO_MODEL, model: 'deepseek-chat',
baseURL: DEMO_BASE_URL, baseURL: 'https://api.deepseek.com',
apiKey: DEMO_API_KEY, apiKey: 'YOUR_API_KEY',
language: 'en-US', language: 'en-US',
}) })
await agent.execute('Click the login button') await agent.execute('Click the login button')
``` ```
### CDN Integration ### CDN Build
Fastest way to try PageAgent is to include it via CDN. Demo model will be used by default. For environments where NPM is not available. Usage is identical to NPM:
| Location | URL |
| -------- | ----------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js |
| China | https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js |
```html ```html
<script <script src="https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js" crossorigin="true"></script>
src="https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js" <script>
crossorigin="true" const agent = new PageAgent({
type="text/javascript" model: 'deepseek-chat',
></script> baseURL: 'https://api.deepseek.com',
apiKey: 'YOUR_API_KEY',
})
await agent.execute('Click the login button')
</script>
``` ```
| Location | URL |
| -------- | ----------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js |
| China | https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js |
## 🏗️ Structure ## 🏗️ Structure
PageAgent adopts a simplified monorepo structure: PageAgent adopts a simplified monorepo structure:
+12 -12
View File
@@ -1,12 +1,12 @@
{ {
"name": "root", "name": "root",
"version": "0.0.22", "version": "0.0.24",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "root", "name": "root",
"version": "0.0.22", "version": "0.0.24",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
@@ -8147,15 +8147,15 @@
}, },
"packages/cdn": { "packages/cdn": {
"name": "@page-agent/cdn", "name": "@page-agent/cdn",
"version": "0.0.22", "version": "0.0.24",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"page-agent": "0.0.22" "page-agent": "0.0.24"
} }
}, },
"packages/llms": { "packages/llms": {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "0.0.22", "version": "0.0.24",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
@@ -8163,19 +8163,19 @@
} }
}, },
"packages/page-agent": { "packages/page-agent": {
"version": "0.0.22", "version": "0.0.24",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@page-agent/llms": "0.0.22", "@page-agent/llms": "0.0.24",
"@page-agent/page-controller": "0.0.22", "@page-agent/page-controller": "0.0.24",
"@page-agent/ui": "0.0.22", "@page-agent/ui": "0.0.24",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5" "zod": "^4.3.5"
} }
}, },
"packages/page-controller": { "packages/page-controller": {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.0.22", "version": "0.0.24",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ai-motion": "^0.4.8" "ai-motion": "^0.4.8"
@@ -8183,12 +8183,12 @@
}, },
"packages/ui": { "packages/ui": {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.0.22", "version": "0.0.24",
"license": "MIT" "license": "MIT"
}, },
"packages/website": { "packages/website": {
"name": "@page-agent/website", "name": "@page-agent/website",
"version": "0.0.22", "version": "0.0.24",
"dependencies": { "dependencies": {
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-separator": "^1.1.8",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "root", "name": "root",
"private": true, "private": true,
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/page-controller", "packages/page-controller",
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"name": "@page-agent/cdn", "name": "@page-agent/cdn",
"private": false, "private": false,
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"files": [ "files": [
"dist/" "dist/"
@@ -18,6 +18,6 @@
"build": "vite build && vite build --mode demo" "build": "vite build && vite build --mode demo"
}, },
"dependencies": { "dependencies": {
"page-agent": "0.0.22" "page-agent": "0.0.24"
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/llms", "name": "@page-agent/llms",
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"main": "./dist/lib/page-agent-llms.js", "main": "./dist/lib/page-agent-llms.js",
"module": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js",
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"name": "page-agent", "name": "page-agent",
"private": false, "private": false,
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"main": "./dist/esm/page-agent.js", "main": "./dist/esm/page-agent.js",
"module": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js",
@@ -46,8 +46,8 @@
"dependencies": { "dependencies": {
"chalk": "^5.6.2", "chalk": "^5.6.2",
"zod": "^4.3.5", "zod": "^4.3.5",
"@page-agent/llms": "0.0.22", "@page-agent/llms": "0.0.24",
"@page-agent/page-controller": "0.0.22", "@page-agent/page-controller": "0.0.24",
"@page-agent/ui": "0.0.22" "@page-agent/ui": "0.0.24"
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/page-controller", "name": "@page-agent/page-controller",
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"main": "./dist/lib/page-controller.js", "main": "./dist/lib/page-controller.js",
"module": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js",
@@ -16,6 +16,7 @@
* @edit scrollable element detection * @edit scrollable element detection
* @edit add `data-browser-use-ignore` attribute * @edit add `data-browser-use-ignore` attribute
* @edit improve `sampleRect`, filter out rects with 0 area * @edit improve `sampleRect`, filter out rects with 0 area
* @edit exclude aria-hidden elements
*/ */
export default ( export default (
@@ -1446,7 +1447,14 @@ export default (
* @edit add `data-browser-use-ignore` attribute * @edit add `data-browser-use-ignore` attribute
*/ */
if (node.dataset?.browserUseIgnore === 'true') { if (node.dataset?.browserUseIgnore === 'true') {
return true // Skip this node and its children return null // Skip this node and its children
}
/**
* @edit exclude aria-hidden elements
*/
if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {
return null // Skip this node and its children
} }
// Special handling for root node (body) // Special handling for root node (body)
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@page-agent/ui", "name": "@page-agent/ui",
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"main": "./dist/lib/page-agent-ui.js", "main": "./dist/lib/page-agent-ui.js",
"module": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js",
+2 -5
View File
@@ -1,6 +1,6 @@
import { type Step, UIState } from './UIState' import { type Step, UIState } from './UIState'
import { I18n, type SupportedLanguage } from './i18n' import { I18n, type SupportedLanguage } from './i18n'
import { truncate } from './utils' import { escapeHtml, truncate } from './utils'
import styles from './Panel.module.css' import styles from './Panel.module.css'
@@ -590,10 +590,7 @@ export class Panel {
#updateHistory(): void { #updateHistory(): void {
const steps = this.#state.getAllSteps() const steps = this.#state.getAllSteps()
this.#historySection.innerHTML = steps.map((step) => this.#createHistoryItem(step)).join('') this.#historySection.innerHTML = steps.map((step) => this.#createHistoryItem(step)).join('')
// Scroll to bottom to show latest records
this.#scrollToBottom() this.#scrollToBottom()
} }
@@ -660,7 +657,7 @@ export class Panel {
<div class="${styles.historyItem} ${typeClass}"> <div class="${styles.historyItem} ${typeClass}">
<div class="${styles.historyContent}"> <div class="${styles.historyContent}">
<span class="${styles.statusIcon}">${statusIcon}</span> <span class="${styles.statusIcon}">${statusIcon}</span>
<span>${step.displayText}</span> <span>${escapeHtml(step.displayText)}</span>
</div> </div>
<div class="${styles.historyMeta}"> <div class="${styles.historyMeta}">
${stepLabel} ${stepLabel}
+12
View File
@@ -4,3 +4,15 @@ export function truncate(text: string, maxLength: number): string {
} }
return text return text
} }
/**
* Escape HTML special characters to prevent XSS and rendering issues
*/
export function escapeHtml(text: string): string {
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
}
+2 -2
View File
@@ -1,10 +1,10 @@
{ {
"name": "@page-agent/website", "name": "@page-agent/website",
"private": true, "private": true,
"version": "0.0.22", "version": "0.0.24",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite --host 0.0.0.0",
"build:website": "vite build", "build:website": "vite build",
"preview": "vite preview", "preview": "vite preview",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
@@ -41,6 +41,7 @@ export default function Header() {
className="hidden sm:block text-xs text-gray-600 dark:text-gray-300 py-0 font-normal overflow-visible" className="hidden sm:block text-xs text-gray-600 dark:text-gray-300 py-0 font-normal overflow-visible"
duration={600} duration={600}
animateOnHover={true} animateOnHover={true}
aria-hidden="true"
> >
{t('header.slogan')} {t('header.slogan')}
</HyperText> </HyperText>
@@ -84,6 +85,9 @@ export default function Header() {
role="navigation" role="navigation"
aria-label={t('header.nav_docs')} aria-label={t('header.nav_docs')}
> >
<span className="text-xs font-mono text-gray-400 dark:text-gray-500 tabular-nums before:content-['v']">
{import.meta.env.VERSION}
</span>
<Link <Link
href="/docs/introduction/overview" href="/docs/introduction/overview"
className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200" className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200"
+9 -3
View File
@@ -1,3 +1,9 @@
export const CDN_URL = 'https://cdn.jsdelivr.net/npm/page-agent@latest/dist/umd/page-agent.js' // Demo build (auto-init with demo LLM, for quick testing)
export const CDN_CN_URL = export const CDN_DEMO_URL = 'https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.demo.js'
'https://registry.npmmirror.com/page-agent/latest/files/dist/umd/page-agent.js' export const CDN_DEMO_CN_URL =
'https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js'
// Full build (exports PageAgent class, usage identical to npm)
export const CDN_FULL_URL = 'https://cdn.jsdelivr.net/npm/@page-agent/cdn/dist/page-agent.js'
export const CDN_FULL_CN_URL =
'https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.js'
+4
View File
@@ -1,5 +1,9 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VERSION: string
}
declare module '*.module.css' { declare module '*.module.css' {
const classes: Record<string, string> const classes: Record<string, string>
export default classes export default classes
+6 -3
View File
@@ -12,10 +12,10 @@ import { Highlighter } from '../components/ui/highlighter'
import { NeonGradientCard } from '../components/ui/neon-gradient-card' import { NeonGradientCard } from '../components/ui/neon-gradient-card'
import { Particles } from '../components/ui/particles' import { Particles } from '../components/ui/particles'
import { SparklesText } from '../components/ui/sparkles-text' import { SparklesText } from '../components/ui/sparkles-text'
import { CDN_CN_URL, CDN_URL } from '../constants' import { CDN_DEMO_CN_URL, CDN_DEMO_URL } from '../constants'
function getInjection(useCN?: boolean) { function getInjection(useCN?: boolean) {
const cdn = useCN ? CDN_CN_URL : CDN_URL const cdn = useCN ? CDN_DEMO_CN_URL : CDN_DEMO_URL
const injection = encodeURI( const injection = encodeURI(
`javascript:(function(){var s=document.createElement('script');s.src=\`${cdn}?t=\${Math.random()}\`;s.setAttribute('crossorigin', true);s.type="text/javascript";s.onload=()=>console.log('PageAgent script loaded!');document.body.appendChild(s);})();` `javascript:(function(){var s=document.createElement('script');s.src=\`${cdn}?t=\${Math.random()}\`;s.setAttribute('crossorigin', true);s.type="text/javascript";s.onload=()=>console.log('PageAgent script loaded!');document.body.appendChild(s);})();`
@@ -95,7 +95,10 @@ export default function HomePage() {
{/* Hero Section */} {/* Hero Section */}
<main id="main-content"> <main id="main-content">
<section className="relative px-6 py-22 lg:py-28" aria-labelledby="hero-heading"> <section
className="relative px-6 py-22 lg:py-28 overflow-hidden"
aria-labelledby="hero-heading"
>
<div className="max-w-7xl mx-auto text-center"> <div className="max-w-7xl mx-auto text-center">
{/* Background Pattern + Particles */} {/* Background Pattern + Particles */}
<div className="absolute inset-0 opacity-30" aria-hidden="true"> <div className="absolute inset-0 opacity-30" aria-hidden="true">
+1 -1
View File
@@ -43,7 +43,7 @@ export default function DocsLayout({ children }: DocsLayoutProps) {
items: [ items: [
{ title: t('nav.configuration'), path: '/docs/integration/configuration' }, { title: t('nav.configuration'), path: '/docs/integration/configuration' },
{ title: t('nav.third_party_agent'), path: '/docs/integration/third-party-agent' }, { title: t('nav.third_party_agent'), path: '/docs/integration/third-party-agent' },
{ title: '🚧 ' + t('nav.cdn_setup'), path: '/docs/integration/cdn-setup' }, { title: t('nav.cdn_setup'), path: '/docs/integration/cdn-setup' },
{ {
title: '🚧 ' + t('nav.security_permissions'), title: '🚧 ' + t('nav.security_permissions'),
path: '/docs/integration/security-permissions', path: '/docs/integration/security-permissions',
@@ -1,81 +1,124 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import BetaNotice from '@/components/BetaNotice'
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import { CDN_CN_URL, CDN_URL } from '@/constants' import { CDN_DEMO_CN_URL, CDN_DEMO_URL, CDN_FULL_CN_URL, CDN_FULL_URL } from '@/constants'
export default function CdnSetup() { export default function CdnSetup() {
const { i18n } = useTranslation() const { i18n } = useTranslation()
const isZh = i18n.language === 'zh-CN' const isZh = i18n.language === 'zh-CN'
return ( return (
<div> <div className="space-y-10">
<BetaNotice /> <header>
<h1 className="text-4xl font-bold mb-4">{isZh ? 'CDN 引入' : 'CDN Setup'}</h1>
<p className="text-lg text-gray-600 dark:text-gray-300 leading-relaxed">
{isZh
? 'CDN 提供两种构建版本:Demo 版用于快速体验,标准版用法与 NPM 一致。'
: 'CDN provides two builds: Demo for quick testing, standard build with usage identical to NPM.'}
</p>
</header>
<h1 className="text-4xl font-bold mb-6">{isZh ? 'CDN 引入' : 'CDN Setup'}</h1> {/* Demo Build Section */}
<section>
<h2 className="text-2xl font-bold mb-3">{isZh ? '🚀 快速体验' : '🚀 Quick Try'}</h2>
<p className="text-xl text-gray-600 dark:text-gray-300 mb-8 leading-relaxed"> <p className="text-gray-600 dark:text-gray-300 mb-3">
{isZh {isZh
? '通过 CDN 快速集成 page-agent,无需复杂的构建配置。默认使用演示模型。' ? '自动初始化并使用内置 Demo LLM,无需任何配置:'
: 'Fastest way to integrate page-agent via CDN. No complex build setup needed. Demo model will be used by default.'} : 'Auto-initializes with built-in demo LLM, no configuration needed:'}
</p> </p>
<section className="mb-8">
<h2 className="text-2xl font-bold mb-4">{isZh ? 'CDN 地址' : 'CDN URLs'}</h2>
<div className="overflow-x-auto mb-6">
<table className="w-full border-collapse text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-3 px-4 font-semibold">{isZh ? '位置' : 'Location'}</th>
<th className="text-left py-3 px-4 font-semibold">URL</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-gray-100 dark:border-gray-800">
<td className="py-3 px-4">{isZh ? '全球' : 'Global'}</td>
<td className="py-3 px-4 font-mono text-xs break-all">{CDN_URL}</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-800">
<td className="py-3 px-4">{isZh ? '中国镜像' : 'China Mirror'}</td>
<td className="py-3 px-4 font-mono text-xs break-all">{CDN_CN_URL}</td>
</tr>
</tbody>
</table>
</div>
</section>
<section className="mb-8">
<h2 className="text-2xl font-bold mb-4">{isZh ? '快速开始' : 'Quick Start'}</h2>
<CodeEditor <CodeEditor
className="mb-6" className="mb-3"
code={`<script code={`<script src="${CDN_DEMO_URL}" crossorigin="true"></script>`}
src="${CDN_URL}"
crossorigin="true"
type="text/javascript"
></script>`}
/> />
<div className="bg-yellow-50 dark:bg-yellow-900/20 px-4 py-3 rounded-lg mb-4 text-sm">
<span className="text-yellow-800 dark:text-yellow-200">
{' '}
{isZh
? '仅用于技术评估,Demo 模型有速率限制。'
: 'For evaluation only. Demo model has rate limits.'}
</span>
</div>
<table className="w-full border-collapse text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-2 px-3 font-semibold w-28">
{isZh ? '位置' : 'Location'}
</th>
<th className="text-left py-2 px-3 font-semibold">URL</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-gray-100 dark:border-gray-800">
<td className="py-2 px-3">{isZh ? '全球' : 'Global'}</td>
<td className="py-2 px-3 font-mono text-xs break-all">{CDN_DEMO_URL}</td>
</tr>
<tr>
<td className="py-2 px-3">{isZh ? '中国' : 'China'}</td>
<td className="py-2 px-3 font-mono text-xs break-all">{CDN_DEMO_CN_URL}</td>
</tr>
</tbody>
</table>
</section> </section>
<section className="mb-8"> {/* CDN Build Section */}
<div className="bg-yellow-50 dark:bg-yellow-900/20 p-4 rounded-lg"> <section>
<h3 className="text-lg font-semibold mb-2 text-yellow-900 dark:text-yellow-300"> <h2 className="text-2xl font-bold mb-3">{isZh ? '📦 标准版' : '📦 Standard Build'}</h2>
{isZh ? '注意事项' : 'Notes'}
</h3> <p className="text-gray-600 dark:text-gray-300 mb-3">
<ul className="text-gray-600 dark:text-gray-300 space-y-1"> {isZh
<li> ? '将 PageAgent 类暴露到 globalThis,用法与 NPM 一致:'
{isZh ? '生产环境建议使用固定版本号' : 'Use fixed version number in production'} : 'Exposes PageAgent class to globalThis, usage identical to NPM:'}
</li> </p>
<li> {isZh ? '确保 HTTPS 环境下使用' : 'Ensure HTTPS environment'}</li>
<li> <CodeEditor
{' '} className="mb-4"
{isZh code={`<script src="${CDN_FULL_URL}" crossorigin="true"></script>
? '配置 CSP 策略允许脚本执行' <script>
: 'Configure CSP policy to allow script execution'} const agent = new PageAgent({
</li> model: 'deepseek-chat',
</ul> baseURL: 'https://api.deepseek.com',
</div> apiKey: 'YOUR_API_KEY',
})
await agent.execute('Click the submit button')
</script>`}
/>
<table className="w-full border-collapse text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-2 px-3 font-semibold w-28">
{isZh ? '位置' : 'Location'}
</th>
<th className="text-left py-2 px-3 font-semibold">URL</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-gray-100 dark:border-gray-800">
<td className="py-2 px-3">{isZh ? '全球' : 'Global'}</td>
<td className="py-2 px-3 font-mono text-xs break-all">{CDN_FULL_URL}</td>
</tr>
<tr>
<td className="py-2 px-3">{isZh ? '中国' : 'China'}</td>
<td className="py-2 px-3 font-mono text-xs break-all">{CDN_FULL_CN_URL}</td>
</tr>
</tbody>
</table>
</section>
{/* Tips */}
<section className="bg-blue-50 dark:bg-blue-900/20 p-4 rounded-lg">
<h3 className="text-base font-semibold mb-2 text-blue-900 dark:text-blue-300">
💡 {isZh ? '提示' : 'Tips'}
</h3>
<ul className="text-gray-600 dark:text-gray-300 text-sm space-y-1">
<li> {isZh ? '生产环境推荐使用 NPM' : 'NPM is recommended for production'}</li>
<li> {isZh ? '生产环境建议锁定版本号' : 'Lock version number in production'}</li>
<li> {isZh ? '确保 HTTPS 环境' : 'Ensure HTTPS environment'}</li>
</ul>
</section> </section>
</div> </div>
) )
@@ -2,10 +2,11 @@ import { useTranslation } from 'react-i18next'
import BetaNotice from '@/components/BetaNotice' import BetaNotice from '@/components/BetaNotice'
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import { CDN_CN_URL, CDN_URL } from '@/constants' import { CDN_DEMO_CN_URL, CDN_DEMO_URL } from '@/constants'
export default function QuickStart() { export default function QuickStart() {
const { t } = useTranslation('docs') const { t, i18n } = useTranslation('docs')
const isZh = i18n.language === 'zh-CN'
return ( return (
<div> <div>
@@ -16,64 +17,62 @@ export default function QuickStart() {
<h2 className="text-2xl font-bold mb-3">{t('quick_start.installation')}</h2> <h2 className="text-2xl font-bold mb-3">{t('quick_start.installation')}</h2>
<div className="space-y-4 mb-6"> <div className="space-y-4 mb-6">
{/* Demo CDN - One Line */}
<div className="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg"> <div className="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
<h3 className="text-lg font-semibold mb-2 text-blue-900 dark:text-blue-300"> <h3 className="text-lg font-semibold mb-2 text-blue-900 dark:text-blue-300">
{t('quick_start.step1_title')} {isZh ? '🚀 快速体验(Demo CDN' : '🚀 Quick Try (Demo CDN)'}
</h3> </h3>
<div className="space-y-3"> <div className="bg-yellow-50 dark:bg-yellow-900/20 p-2 rounded mb-3 text-sm">
<div> <span className="text-yellow-800 dark:text-yellow-200">
<p className="text-sm font-medium mb-2">{t('quick_start.step1_cdn')}</p> {isZh ? '仅用于技术评估' : 'For evaluation only'}
<CodeEditor </span>
code={`// CDN: \t${CDN_URL}
// Mirror: \t${CDN_CN_URL}
<script src="${CDN_URL}" crossorigin="true" type="text/javascript"></script>`}
language="html"
/>
</div>
<div>
<p className="text-sm font-medium mb-2">{t('quick_start.step1_npm')}</p>
<CodeEditor
code={`// npm install page-agent
import PageAgent from 'page-agent'`}
language="bash"
/>
</div>
</div> </div>
<CodeEditor
code={`// Global: ${CDN_DEMO_URL}
// China: ${CDN_DEMO_CN_URL}
<script src="${isZh ? CDN_DEMO_CN_URL : CDN_DEMO_URL}" crossorigin="true"></script>`}
language="html"
/>
</div> </div>
{/* NPM - Recommended */}
<div className="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg"> <div className="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg">
<h3 className="text-lg font-semibold mb-2 text-green-900 dark:text-green-300"> <h3 className="text-lg font-semibold mb-2 text-green-900 dark:text-green-300">
{t('quick_start.step2_title')} {isZh ? '📦 NPM 安装(推荐)' : '📦 NPM Install (Recommended)'}
</h3> </h3>
<CodeEditor <CodeEditor
code={`// 仅供测试使用,生产环境需要配置 LLM 接入点,本工具不提供 LLM 服务 code={`npm install page-agent
// 测试接口
// @note: 限流,限制 prompt 内容,限制来源,随时变更,请替换成你自己的
// @note: 使用 DeepSeek-chat(3.2) 官方版本,使用协议和隐私策略见 DeepSeek 网站
const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const DEMO_BASE_URL = 'https://hwcxiuzfylggtcktqgij.supabase.co/functions/v1/llm-testing-proxy'
const DEMO_API_KEY = 'PAGE-AGENT-FREE-TESTING-RANDOM'
const agent = new PageAgent({ import { PageAgent } from 'page-agent'`}
model: DEMO_MODEL, language="bash"
baseURL: DEMO_BASE_URL,
apiKey: DEMO_API_KEY,
language: 'zh-CN'
})`}
language="javascript"
/> />
</div> </div>
<div className="p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg"> <div className="p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
<h3 className="text-lg font-semibold mb-2 text-purple-900 dark:text-purple-300"> <h3 className="text-lg font-semibold mb-2 text-purple-900 dark:text-purple-300">
{t('quick_start.step2_title')}
</h3>
<CodeEditor
code={`const agent = new PageAgent({
model: 'deepseek-chat',
baseURL: 'https://api.deepseek.com',
apiKey: 'YOUR_API_KEY',
language: '${isZh ? 'zh-CN' : 'en-US'}'
})`}
language="javascript"
/>
</div>
<div className="p-4 bg-orange-50 dark:bg-orange-900/20 rounded-lg">
<h3 className="text-lg font-semibold mb-2 text-orange-900 dark:text-orange-300">
{t('quick_start.step3_title')} {t('quick_start.step3_title')}
</h3> </h3>
<CodeEditor <CodeEditor
code={`// 程序化执行自然语言指令 code={`// ${isZh ? '程序化执行自然语言指令' : 'Execute natural language instructions programmatically'}
await pageAgent.execute('点击提交按钮,然后填写用户名为张三'); await agent.execute('${isZh ? '点击提交按钮,然后填写用户名为张三' : 'Click submit button, then fill username as John'}');
// 或者显示对话框让用户输入指令 // ${isZh ? '或者显示对话框让用户输入指令' : 'Or show panel for user to input instructions'}
pageAgent.panel.show() agent.panel.show()
`} `}
language="javascript" language="javascript"
/> />
+5
View File
@@ -1,12 +1,16 @@
import tailwindcss from '@tailwindcss/vite' import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react-swc' import react from '@vitejs/plugin-react-swc'
import { config as dotenvConfig } from 'dotenv' import { config as dotenvConfig } from 'dotenv'
import { readFileSync } from 'node:fs'
import process from 'node:process' import process from 'node:process'
import { dirname, resolve } from 'path' import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
const __dirname = dirname(fileURLToPath(import.meta.url)) const __dirname = dirname(fileURLToPath(import.meta.url))
const pageAgentPkg = JSON.parse(
readFileSync(resolve(__dirname, '../page-agent/package.json'), 'utf-8')
)
// Load .env from repo root // Load .env from repo root
dotenvConfig({ path: resolve(__dirname, '../../.env') }) dotenvConfig({ path: resolve(__dirname, '../../.env') })
@@ -32,5 +36,6 @@ export default defineConfig({
'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME), 'import.meta.env.LLM_MODEL_NAME': JSON.stringify(process.env.LLM_MODEL_NAME),
'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY), 'import.meta.env.LLM_API_KEY': JSON.stringify(process.env.LLM_API_KEY),
'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL), 'import.meta.env.LLM_BASE_URL': JSON.stringify(process.env.LLM_BASE_URL),
'import.meta.env.VERSION': JSON.stringify(pageAgentPkg.version),
}, },
}) })