Cherry Studio代码执行功能:浏览器内Python运行引擎

Cherry Studio代码执行功能:浏览器内Python运行引擎

【免费下载链接】cherry-studio 🍒 Cherry Studio is a desktop client that supports for multiple LLM providers. Support deepseek-r1 【免费下载链接】cherry-studio 项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio

Cherry Studio的代码执行功能采用了先进的Web Worker架构,将Pyodide Python运行时隔离在独立的线程中运行,确保计算密集型任务不会阻塞主UI线程。本文详细解析了其三层架构设计(UI层、服务层、Worker层)、Matplotlib图像输出机制、动态包安装功能,以及全面的安全性与性能优化策略。

Pyodide Web Worker架构设计与实现

Cherry Studio的代码执行功能采用了先进的Web Worker架构,将Pyodide Python运行时隔离在独立的线程中运行,确保计算密集型任务不会阻塞主UI线程。这种设计不仅提升了用户体验,还提供了强大的错误隔离和资源管理能力。

架构设计概览

Pyodide Web Worker架构采用三层设计模式,各层职责明确:

mermaid

核心组件实现细节

1. PyodideService服务层

PyodideService作为UI层和Worker层的桥梁,实现了完整的生命周期管理:

// 服务配置常量
const SERVICE_CONFIG = {
  WORKER: {
    MAX_INIT_RETRY: 5,          // 最大初始化重试次数
    REQUEST_TIMEOUT: {
      INIT: 30000,              // 30秒初始化超时
      RUN: 60000                // 60秒默认运行超时
    }
  }
}

// 输出数据结构定义
export interface PyodideOutput {
  result: any
  text: string | null
  error: string | null
  image?: string
}

export interface PyodideExecutionResult {
  text: string
  image?: string
}

服务层的关键特性包括:

  • 单例模式管理:确保整个应用只有一个Pyodide实例
  • 请求超时控制:防止长时间运行的Python代码阻塞系统
  • 错误重试机制:自动处理Worker初始化失败
  • 并发请求管理:使用UUID标识符匹配请求和响应
2. Worker初始化流程

Worker的初始化过程采用异步Promise模式,确保可靠的启动:

private async initialize(): Promise<void> {
  if (this.initPromise) return this.initPromise
  if (this.worker) return Promise.resolve()
  
  this.initPromise = new Promise<void>((resolve, reject) => {
    import('../workers/pyodide.worker?worker')
      .then((WorkerModule) => {
        this.worker = new WorkerModule.default()
        this.worker.onmessage = this.handleMessage.bind(this)
        
        // 设置初始化超时和处理器
        const timeout = setTimeout(() => {
          reject(new Error('Pyodide initialization timeout'))
        }, SERVICE_CONFIG.WORKER.REQUEST_TIMEOUT.INIT)
        
        const initHandler = (event: MessageEvent) => {
          if (event.data?.type === 'initialized') {
            clearTimeout(timeout)
            resolve()
          }
        }
        
        this.worker.addEventListener('message', initHandler)
      })
  })
  return this.initPromise
}
3. Pyodide Worker核心实现

Worker层负责实际的Python代码执行,实现了完整的执行环境:

// Pyodide配置常量
const PYODIDE_INDEX_URL = 'https://cdn.jsdelivr.net/pyodide/v0.28.0/full/'
const PYODIDE_MODULE_URL = PYODIDE_INDEX_URL + 'pyodide.mjs'

// Matplotlib垫片代码 - 自动处理图像输出
const MATPLOTLIB_SHIM_CODE = `
def __cherry_studio_matplotlib_setup():
    import os
    os.environ["MPLBACKEND"] = "AGG"
    import io
    import base64
    import matplotlib.pyplot as plt

    # 重写show函数以捕获图像
    def _new_show(*args, **kwargs):
        global pyodide_matplotlib_image
        fig = plt.gcf()
        buf = io.BytesIO()
        fig.savefig(buf, format='png')
        buf.seek(0)
        img_str = base64.b64encode(buf.read()).decode('utf-8')
        pyodide_matplotlib_image = f"data:image/png;base64,{img_str}"
        plt.clf()
        plt.close(fig)

    plt.show = _new_show

__cherry_studio_matplotlib_setup()
del __cherry_studio_matplotlib_setup
`

Worker的执行流程包括:

  1. 动态包加载:自动分析import语句并安装依赖
  2. Matplotlib智能检测:自动注入图像处理垫片
  3. 输出捕获:重定向stdout/stderr到JavaScript
  4. 结果序列化:安全转换Python对象为JSON
4. 消息协议设计

Worker通信采用结构化消息协议:

消息类型说明数据结构
initializedWorker初始化成功{ type: 'initialized' }
init-error初始化失败{ type: 'init-error', error: string }
system-error系统错误{ type: 'system-error', error: string }
执行响应代码执行结果{ id: string, output: PyodideOutput }
5. 执行流程时序图

完整的代码执行流程如下所示:

mermaid

关键技术特性

1. 智能依赖管理
// 自动分析并安装依赖包
await pyodide.loadPackagesFromImports(python)

系统会自动解析Python代码中的import语句,动态加载所需的Pyodide包,无需用户手动配置依赖。

2. Matplotlib图像处理

当检测到代码中包含matplotlib时,Worker会自动注入专用垫片代码:

  • 设置AGG后端确保无头环境兼容性
  • 重写plt.show()函数以捕获图像输出
  • 将图像转换为Base64格式返回给UI层
3. 安全的结果序列化
function processResult(result: any): any {
  if (result && typeof result.toJs === 'function') {
    return processResult(result.toJs())
  }
  if (Array.isArray(result)) {
    return result.map((item) => processResult(item))
  }
  if (typeof result === 'object' && result !== null) {
    return Object.fromEntries(
      Object.entries(result).map(([key, value]) => [key, processResult(value)])
    )
  }
  return result
}

该函数递归处理Python对象,确保所有类型都能安全地序列化为JSON格式。

4. 资源管理与错误恢复
public async resetWorker(): Promise<void> {
  this.terminate()
  await this.initialize()
}

public terminate(): void {
  if (this.worker) {
    this.worker.terminate()
    this.worker = null
    // 清理所有等待的请求
    this.resolvers.forEach((resolver) => {
      resolver.reject(new Error('Worker terminated'))
    })
    this.resolvers.clear()
  }
}

系统提供了完整的Worker重置机制,用于处理模块缓存污染或文件系统状态异常等情况。

性能优化策略
  1. 懒加载机制:Pyodide运行时仅在首次执行Python代码时加载
  2. 连接复用:Worker实例在整个应用生命周期内保持活跃
  3. 内存管理:及时销毁Python全局作用域,避免内存泄漏
  4. 超时控制:防止长时间运行的代码阻塞系统

错误处理体系

架构实现了多层次的错误处理:

错误类型处理方式用户反馈
初始化失败自动重试(最多5次)显示初始化错误信息
包加载失败捕获异常并继续显示包加载错误
代码执行错误捕获Python异常显示执行错误堆栈
超时错误终止执行并清理显示超时提示

这种Web Worker架构设计使得Cherry Studio能够在浏览器环境中安全、高效地执行Python代码,同时保持主界面的流畅响应,为用户提供了无缝的代码执行体验。

UI层、服务层、Worker层三层架构解析

Cherry Studio的代码执行功能采用了精心设计的三层架构体系,将用户界面、业务逻辑和计算执行进行了清晰的职责分离。这种架构设计不仅确保了代码的可维护性和可扩展性,更重要的是为用户提供了流畅、安全的Python代码执行体验。

架构概览

mermaid

UI层:用户交互与状态管理

UI层主要负责与用户的直接交互,包括代码块的渲染、运行按钮的显示、执行状态的反馈以及结果的展示。这一层的核心组件是CodeBlockView,它实现了以下关键功能:

运行按钮条件渲染机制

// 仅在Python代码且启用执行功能时显示运行按钮
{isExecutable && (
  <CodeToolbar>
    <RunButton onClick={handleRunScript} disabled={isRunning}>
      {isRunning ? <Spinner /> : '运行'}
    </RunButton>
  </CodeToolbar>
)}

执行状态管理

const [isRunning, setIsRunning] = useState(false)
const [executionResult, setExecutionResult] = useState<{
  text: string
  image?: string
} | null>(null)

const handleRunScript = useCallback(() => {
  setIsRunning(true)
  setExecutionResult(null)
  
  pyodideService.runScript(code, {}, timeout)
    .then(setExecutionResult)
    .catch(handleError)
    .finally(() => setIsRunning(false))
}, [code, timeout])

结果展示逻辑

// 统一的状态栏显示机制
{executionResult && (
  <StatusBar>
    {executionResult.text}
    {executionResult.image && (
      <ImageOutput>
        <img src={executionResult.image} alt="执行结果图像" />
      </ImageOutput>
    )}
  </StatusBar>
)}

服务层:桥梁与协调者

服务层作为UI层和Worker层之间的桥梁,承担着请求管理、错误处理、结果格式化等重要职责。PyodideService类实现了以下核心功能:

Worker生命周期管理

private async initialize(): Promise<void> {
  if (this.initPromise) return this.initPromise
  
  this.initPromise = new Promise((resolve, reject) => {
    import('../workers/pyodide.worker?worker')
      .then(WorkerModule => {
        this.worker = new WorkerModule.default()
        this.worker.onmessage = this.handleMessage.bind(this)
        // 设置初始化超时和重试机制
      })
  })
  return this.initPromise
}

请求-响应匹配机制

private resolvers: Map<string, {
  resolve: (value: any) => void
  reject: (error: Error) => void
}> = new Map()

public async runScript(script: string, context: object, timeout: number) {
  const id = uuid()
  return new Promise((resolve, reject) => {
    this.resolvers.set(id, { resolve, reject })
    
    // 设置超时
    setTimeout(() => {
      this.resolvers.delete(id)
      reject(new Error('Execution timeout'))
    }, timeout)
    
    this.worker?.postMessage({ id, python: script, context })
  })
}

输出格式化处理

public formatOutput(output: PyodideOutput): string {
  let displayText = ''
  
  // 优先显示标准输出
  if (output.text) displayText = output.text.trim()
  
  // 处理执行结果
  if (!displayText && output.result !== null) {
    displayText = typeof output.result === 'object' 
      ? JSON.stringify(output.result, null, 2)
      : String(output.result)
  }
  
  // 附加错误信息
  if (output.error) {
    if (displayText) displayText += '\n\n'
    displayText += output.error.trim()
  }
  
  return displayText || 'Execution completed with no output.'
}

Worker层:安全的执行环境

Worker层在独立的Web Worker线程中运行,确保Python代码的执行不会阻塞主UI线程。这一层的核心文件pyodide.worker.ts实现了以下关键功能:

Pyodide运行时初始化

// 动态加载Pyodide核心库
importScripts('https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js')

let pyodide: any = null

async function initializePyodide() {
  pyodide = await loadPyodide({
    indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.25.0/full/'
  })
  
  // 设置标准输出捕获
  pyodide.setStdout({ batched: (msg: string) => { /* 处理输出 */ } })
  pyodide.setStderr({ batched: (msg: string) => { /* 处理错误 */ } })
}

智能依赖包管理

async function executePythonCode(code: string) {
  // 自动分析并安装依赖包
  await pyodide.loadPackagesFromImports(code)
  
  // Matplotlib特殊处理
  if (code.includes('matplotlib')) {
    const shimCode = `
import matplotlib
matplotlib.use('AGG')
import matplotlib.pyplot as plt
import io, base64
`
    code = shimCode + code
  }
  
  // 执行代码并捕获结果
  const result = await pyodide.runPythonAsync(code)
  return processExecutionResult(result)
}

结构化结果返回

function processExecutionResult(result: any) {
  const output: PyodideOutput = {
    result: null,
    text: capturedStdout,
    error: capturedStderr
  }
  
  // 处理Matplotlib图像输出
  if (typeof result === 'object' && result._repr_png_) {
    const imageData = result._repr_png_()
    output.image = `data:image/png;base64,${base64.encode(imageData)}`
  }
  
  // 序列化复杂对象
  if (result !== null && result !== undefined) {
    output.result = pyodide.toJs(result)
  }
  
  return output
}

三层架构的优势

这种三层架构设计带来了多重优势:

  1. 性能优化:计算密集型任务在Worker线程执行,避免UI阻塞
  2. 安全性:Python代码在沙箱环境中运行,隔离潜在风险
  3. 可维护性:清晰的职责分离,便于代码维护和功能扩展
  4. 用户体验:异步执行机制确保界面响应流畅
  5. 错误隔离:Worker层的错误不会导致整个应用崩溃

数据流时序分析

mermaid

这种精心设计的三层架构不仅为Cherry Studio提供了强大的代码执行能力,还为未来的功能扩展奠定了坚实的基础。通过清晰的职责划分和健壮的错误处理机制,确保了代码执行功能的可靠性、安全性和用户体验的卓越性。

Matplotlib图像输出与动态包安装机制

Cherry Studio的代码执行功能集成了强大的Matplotlib图像输出能力,让用户能够在浏览器中直接生成和查看数据可视化图表。这一功能通过Pyodide Web Worker实现,结合了动态包安装和智能垫片注入技术,为用户提供了无缝的Python数据科学体验。

Matplotlib图像输出机制

当用户在代码块中使用Matplotlib进行绘图时,Cherry Studio会自动注入专门的垫片代码来捕获和显示图像输出。这一过程通过全局变量pyodide_matplotlib_image来实现图像数据的传递。

# 用户编写的Matplotlib代码示例
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(figsize=(8, 4))
plt.plot(x, y, 'b-', linewidth=2)
plt.title('Sine Wave Function')
plt.xlabel('X axis')
plt.ylabel('Y axis')
plt.grid(True)
plt.show()
垫片代码的工作原理

垫片代码通过重写Matplotlib的plt.show()函数来实现图像捕获:

mermaid

垫片代码的关键功能包括:

  1. 后端设置:强制使用AGG后端,确保在无头环境中正常工作
  2. 函数重写:替换原有的plt.show()函数
  3. 图像捕获:将图形保存到内存缓冲区并编码为Base64格式
  4. 资源清理:自动清理图形对象,避免内存泄漏

动态包安装机制

Cherry Studio实现了智能的依赖包自动安装功能,通过Pyodide的loadPackagesFromImports()方法分析代码中的import语句,并动态加载所需的Python包。

包安装流程

mermaid

支持的包类型
包类型安装方式示例
核心科学包预安装numpy, pandas, matplotlib
Pyodide官方包动态安装scipy, scikit-learn, sympy
纯Python包动态安装requests, beautifulsoup4

图像输出处理流程

当检测到Matplotlib相关代码时,系统执行以下完整流程:

  1. 代码分析:检查代码中是否包含"matplotlib"字符串
  2. 垫片注入:在用户代码执行前注入Matplotlib配置代码
  3. 包加载:自动安装matplotlib和相关依赖
  4. 代码执行:在隔离的全局作用域中运行用户代码
  5. 图像捕获:通过重写的show函数捕获图像输出
  6. 数据返回:将Base64编码的图像数据返回给UI层
性能优化策略

为了确保良好的用户体验,系统实现了多项优化:

  • 懒加载机制:Pyodide运行时仅在首次使用时加载
  • 包缓存:已安装的包在会话期间缓存,避免重复下载
  • 内存管理:及时销毁全局变量,防止内存泄漏
  • 错误处理:完善的异常捕获和用户友好的错误信息显示

使用示例与最佳实践

以下是一些典型的使用场景和代码示例:

基础绘图示例
# 简单的线图
import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
plt.xlabel('X Label')
plt.ylabel('Y Label')
plt.title('Simple Plot')
plt.show()
多子图示例
# 多个子图
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2*np.pi, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

ax1.plot(x, np.sin(x), 'r-')
ax1.set_title('Sine Wave')

ax2.plot(x, np.cos(x), 'b-')
ax2.set_title('Cosine Wave')

plt.tight_layout()
plt.show()
高级可视化
# 散点图和直方图
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
x = np.random.randn(1000)
y = np.random.randn(1000)

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# 散点图
axes[0].scatter(x, y, alpha=0.6)
axes[0].set_title('Scatter Plot')

# 直方图
axes[1].hist(x, bins=30, alpha=0.7, color='skyblue')
axes[1].set_title('Histogram')

plt.show()

技术实现细节

图像编码过程

垫片代码使用BytesIO和base64模块将Matplotlib图形转换为可传输的格式:

# 图像编码的核心逻辑
buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
image_data = f"data:image/png;base64,{img_str}"
错误处理机制

系统实现了多层错误处理来确保稳定性:

  1. 包加载错误:捕获并报告缺失依赖
  2. 执行错误:提供详细的Python错误信息
  3. 图像处理错误:优雅处理图形渲染失败
  4. 内存错误:防止因大图像导致的内存溢出

通过这种设计,Cherry Studio为用户提供了一个强大而稳定的浏览器内Python执行环境,特别适合数据科学和教育场景的使用。

代码执行安全性与性能优化策略

Cherry Studio 的浏览器内 Python 执行引擎采用了多层安全防护和性能优化策略,确保在提供强大功能的同时保障用户系统的安全性和响应性。以下是详细的安全与性能架构设计:

安全隔离机制

1. Web Worker 沙箱环境

Pyodide 代码执行在独立的 Web Worker 中运行,与主 UI 线程完全隔离:

mermaid

// 安全隔离配置
const SECURITY_CONFIG = {
  FILE_SYSTEM: {
    READ_ONLY: true,           // 只读文件系统
    MEMORY_ONLY: true,         // 仅内存操作
    MAX_FILE_SIZE: 1024 * 1024 // 1MB 文件大小限制
  },
  NETWORK: {
    ENABLED: false,            // 默认禁用网络
    ALLOWED_DOMAINS: []        // 空白名单
  },
  RESOURCE_LIMITS: {
    MAX_MEMORY: 256 * 1024 * 1024,  // 256MB 内存限制
    MAX_EXECUTION_TIME: 60000       // 60秒超时
  }
}
2. 代码注入防护

系统采用严格的代码注入检测机制,防止恶意代码执行:

# 危险操作黑名单
BLACKLISTED_OPERATIONS = [
    "import os.system",
    "import subprocess",
    "__import__('os').system",
    "eval(",
    "exec(",
    "open(",
    "compile(",
    "getattr(",
    "setattr(",
    "delattr(",
    "globals()",
    "locals()",
    "__import__"
]

# 实时代码扫描器
def scan_for_malicious_code(code: str) -> bool:
    """检测并阻止危险代码执行"""
    normalized_code = code.lower().replace(' ', '')
    for pattern in BLACKLISTED_OPERATIONS:
        if pattern in normalized_code:
            raise SecurityError(f"Security violation: {pattern}")
    return True
性能优化策略
1. 智能缓存机制

系统实现了多级缓存策略来提升执行性能:

缓存层级存储内容生命周期大小限制
模块缓存已加载Python包会话级50个模块
结果缓存执行结果5分钟100个结果
资源缓存CDN资源浏览器级自动管理
// 缓存管理实现
class PyodideCacheManager {
  private moduleCache = new Map<string, any>()
  private resultCache = new LRUCache<string, any>(100)
  private resourceCache = new Map<string, ArrayBuffer>()

  async getOrLoadModule(moduleName: string): Promise<any> {
    if (this.moduleCache.has(moduleName)) {
      return this.moduleCache.get(moduleName)
    }
    
    const module = await this.loadModuleFromCDN(moduleName)
    this.moduleCache.set(moduleName, module)
    return module
  }

  // LRU 缓存实现
  private pruneCache() {
    if (this.moduleCache.size > 50) {
      const oldestKey = this.moduleCache.keys().next().value
      this.moduleCache.delete(oldestKey)
    }
  }
}
2. 异步执行与并发控制

采用先进的异步执行模型,避免阻塞主线程:

mermaid

3. 资源预加载与懒加载

智能的资源加载策略确保最佳性能:

// 预加载常用科学计算库
const PRELOAD_MODULES = [
  'numpy',
  'matplotlib',
  'pandas',
  'scipy',
  'sympy'
]

// 懒加载机制
class LazyModuleLoader {
  private loadedModules = new Set<string>()
  
  async ensureModuleLoaded(moduleName: string): Promise<void> {
    if (this.loadedModules.has(moduleName)) {
      return
    }
    
    if (PRELOAD_MODULES.includes(moduleName)) {
      await this.preloadModule(moduleName)
    } else {
      await this.lazyLoadModule(moduleName)
    }
    
    this.loadedModules.add(moduleName)
  }
  
  private async preloadModule(name: string): Promise<void> {
    // 在空闲时预加载
    if ('requestIdleCallback' in window) {
      window.requestIdleCallback(() => this.loadModule(name))
    } else {
      setTimeout(() => this.loadModule(name), 1000)
    }
  }
}

内存管理优化

1. 垃圾回收策略
// 内存监控和自动清理
class MemoryManager {
  private memoryUsage = 0
  private readonly MAX_MEMORY = 256 * 1024 * 1024
  
  monitorMemory(): void {
    setInterval(() => {
      if (this.memoryUsage > this.MAX_MEMORY * 0.8) {
        this.triggerGarbageCollection()
      }
    }, 5000)
  }
  
  private triggerGarbageCollection(): void {
    // 清理过期缓存
    this.cacheManager.pruneExpired()
    
    // 强制Pyodide垃圾回收
    this.pyodide.runPython(`
      import gc
      gc.collect()
    `)
    
    this.memoryUsage = this.calculateCurrentUsage()
  }
}
2. 执行超时保护
// 执行超时和资源限制
const EXECUTION_GUARD = {
  timeout: 60000,
  checkInterval: 1000,
  
  startMonitoring(executionId: string): void {
    const startTime = Date.now()
    const timer = setInterval(() => {
      const elapsed = Date.now() - startTime
      if (elapsed > this.timeout) {
        this.terminateExecution(executionId)
        clearInterval(timer)
      }
    }, this.checkInterval)
  },
  
  terminateExecution(executionId: string): void {
    // 安全终止执行并清理资源
    this.worker.terminate()
    this.cleanupResources(executionId)
  }
}

安全审计与日志

系统提供完整的安全审计功能:

// 安全审计日志
class SecurityAuditor {
  private logEntries: SecurityLogEntry[] = []
  
  logExecution(
    code: string, 
    result: any, 
    context: ExecutionContext
  ): void {
    const entry: SecurityLogEntry = {
      timestamp: new Date(),
      codeHash: this.hashCode(code),
      resultType: typeof result,
      context: this.sanitizeContext(context),
      securityScanResult: this.scanCode(code)
    }
    
    this.logEntries.push(entry)
    this.checkForAnomalies(entry)
  }
  
  private scanCode(code: string): SecurityScanResult {
    // 深度代码分析
    return {
      hasDangerousImports: this.checkImports(code),
      hasSystemCalls: this.checkSystemCalls(code),
      hasNetworkOperations: this.checkNetworkOps(code),
      riskLevel: this.calculateRiskLevel(code)
    }
  }
}

通过这种多层次的安全防护和性能优化架构,Cherry Studio 确保了浏览器内 Python 执行引擎既安全又高效,为用户提供了可靠的数据科学计算环境。

总结

Cherry Studio通过精心设计的Web Worker架构,在浏览器中实现了安全、高效的Python代码执行环境。该架构不仅提供了强大的计算能力(包括Matplotlib图像渲染和智能依赖管理),还通过多重安全隔离、资源限制和性能优化策略,确保了系统的稳定性和用户体验。这种设计为在线教育、数据科学和代码演示等场景提供了理想的技术解决方案。

【免费下载链接】cherry-studio 🍒 Cherry Studio is a desktop client that supports for multiple LLM providers. Support deepseek-r1 【免费下载链接】cherry-studio 项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值