Type something to search...
提升你的开发效率:使用openai Canvas构建高效的react应用程序的5个技巧

提升你的开发效率:使用openai Canvas构建高效的react应用程序的5个技巧

开放AI几周前发布了他们的画布工具的重要更新。如果你不知道画布是什么,或者只模糊地听说过但从未使用过,画布是聊天生成预训练变换器中的一个界面,旨在增强写作和编码项目的协作。与您熟悉的传统基于聊天的交互不同,画布提供了一个并排的工作区,用户可以在接收聊天生成预训练变换器的实时帮助的同时直接编辑文本或代码。这种设置允许用户与模型响应之间进行动态交互,使其成为需要迭代编码、文本编辑和精炼的任务的有用工具。

画布的关键特性

用户可以直接修改画布中的文本或代码,从而获得更大的灵活性和对内容的控制。

您可以通过简单地突出显示文本或代码的关键部分并提出进一步的问题,让聊天生成预训练变换器提供针对性的反馈和建议。

专用的后退按钮允许轻松恢复先前版本,确保每次更改都是可逆的。

画布还提供了多种便捷的写作和编码快捷方式。

写作快捷方式

  • 从聊天生成预训练变换器那里获得清晰度和连贯性的改进。
  • 调整文本长度以满足不同需求。
  • 调整复杂性以匹配目标受众。
  • 精炼语法以获得精致的最终结果。
  • 使用表情符号来增加强调和视觉效果。

编码快捷方式

  • 获取内联建议以提升代码质量。
  • 插入打印语句以调试和跟踪代码流程。
  • 添加注释以提高可读性和可维护性。
  • 快速发现和修复错误。
  • 将代码翻译成流行的语言,如JavaScript、Python和Java。

最新更新

我们将集中讨论本文剩余部分的编码方面,从这个角度来看,有两个新的重要更新。

  • 能够在画布上使用开放AI的o1模型。从模型选择下拉框中选择o1模型,然后在聊天输入框中使用/canvas命令。对于更困难的任务,您可能只需要使用o1模型(例如,参见我下面的地图显示应用)。对于简单的任务,使用较弱的模型应该足够。
  • 反应和超文本标记语言代码的创建与开发。如果您的代码包含这些内容,画布现在可以渲染它,以便您可以在画布工具中查看输出。

让我们看看新变化的实际效果

我假设您已经可以访问桌面或基于浏览器的聊天生成预训练变换器应用程序。

图片来自开放AI网站

您首先需要做的是从聊天生成预训练变换器屏幕左上角的模型下拉列表中选择您想要的模型,如上所示。

之后,有三种方法可以访问画布。

  1. 您可以通过在消息框中输入指令 打开画布 来指示聊天生成预训练变换器显示画布。

  2. 您可以使用消息框正下方的小三点 “肉丸” 图标。点击此图标,画布选项将是可供您选择的选项之一。

  3. 您可以点击聊天输入框内并输入 /canvas 然后按 RETURN 键。您会看到 /canvas 文本将被替换为蓝色的 画布 一词,等待您进一步输入文本,如下所示。

请注意,目前并非所有模型都支持使用画布;例如,最近发布的 03-mini 模型都不支持。

图片来自开放AI网站

从这里开始,只需输入您希望画布为您编码的内容。

当画布准备好输出代码时,您的屏幕将分为两个部分。左侧将是您的聊天记录。右侧将是代码。请注意,代码部分的右上角有一个 预览 按钮。一旦模型完成编写代码,您可以使用此按钮查看渲染的应用程序。

示例

为了展示新功能,我将展示两个使用画布编写的反应/超文本标记语言应用的示例案例。第一个是一个相对简单的井字棋游戏应用。第二个是一个使用谷歌地图API的更复杂的互动应用。

项目 1 — 一个简单的井字游戏

对于这个任务,由于相对简单,我选择了 GTP-4o 作为我的模型,并在 画布 模式中输入了这个简单的提示。

使用 反应 和 超文本标记语言 创建一个简单的井字游戏

画布 在短时间内显示了这个内容。

Image 4

尽管游戏按预期工作,但我不喜欢它的外观,想将方块的背景颜色改为白色,将圈和叉改为黑色,所以我要求 画布 这样做。以下是最终结果。

Image 5

供参考,这里是生成的最终代码。

import { useState } from "react";
import { Button } from "@/components/ui/button";

export default function TicTacToe() {
  const [board, setBoard] = useState(Array(9).fill(null));
  const [isXNext, setIsXNext] = useState(true);

  const handleClick = (index) => {
    if (board[index] || calculateWinner(board)) return;
    const newBoard = board.slice();
    newBoard[index] = isXNext ? "X" : "O";
    setBoard(newBoard);
    setIsXNext(!isXNext);
  };

  const winner = calculateWinner(board);
  const status = winner ? `Winner: ${winner}` : `Next Player: ${isXNext ? "X" : "O"}`;

  return (
    <div className="flex flex-col items-center space-y-4">
      <h1 className="text-xl font-bold">Tic-Tac-Toe</h1>
      <div className="grid grid-cols-3 gap-2">
        {board.map((cell, index) => (
          <Button key={index} className="w-16 h-16 text-lg bg-white text-black" onClick={() => handleClick(index)}>
            {cell}
          </Button>
        ))}
      </div>
      <p className="text-lg font-semibold">{status}</p>
      <Button onClick={() => setBoard(Array(9).fill(null))} className="mt-2">Reset</Button>
    </div>
  );
}

function calculateWinner(board) {
  const lines = [
    [0, 1, 2], [3, 4, 5], [6, 7, 8],
    [0, 3, 6], [1, 4, 7], [2, 5, 8],
    [0, 4, 8], [2, 4, 6]
  ];
  for (let [a, b, c] of lines) {
    if (board[a] && board[a] === board[b] && board[a] === board[c]) {
      return board[a];
    }
  }
  return null;
}

所以,这个效果非常好,令人印象深刻。是时候进行一个更具挑战性的任务了。

编码项目 2 — 互动全球地图

在这个例子中,我想创建一个应用程序,使用谷歌地图API显示地球的全球地图。地图应该显示按人口排名的前20个城市,并添加功能,使得当点击城市位置时,会显示一个小的弹出信息框,提供该城市的信息。

这是一个更复杂的任务,因此我选择o1模型作为调用画布之前的模型。

这是我使用的初始提示。

为我创建一个使用反应/超文本标记语言和谷歌地图JavaScript API的互动全球地图。在地图上,显示按人口排名的前20个城市的位置。当我点击一个城市时,在屏幕中间显示一个弹出框,显示:- 城市名称、其人口排名,例如1/20、其人口以及所在国家。

一分钟后,画布开始生成所需的代码,当它完成时,显示了一个可工作的应用程序。第一次也有点工作,除了信息弹出框是模态的,并且使显示的地图失去焦点,因此我输入了这个额外的提示。

弹出框似乎是模态的。你能把它改为非模态的,这样在显示时地图就不会变得模糊吗?

这解决了问题,正如你从下面的截图中看到的那样。

作者提供的图片

作为参考,这里是画布创建的完整代码。我没有提供任何城市信息或其他内容。这些都是由聊天生成预训练变换器创建的。

import React, { useEffect, useRef, useState } from "react";

const cities = [
  { name: "Tokyo", country: "Japan", rank: 1, population: "37,339,804", lat: 35.6895, lng: 139.6917 },
  { name: "Delhi", country: "India", rank: 2, population: "31,181,376", lat: 28.7041, lng: 77.1025 },
  { name: "Shanghai", country: "China", rank: 3, population: "27,795,702", lat: 31.2304, lng: 121.4737 },
  { name: "Sao Paulo", country: "Brazil", rank: 4, population: "22,237,472", lat: -23.5505, lng: -46.6333 },
  { name: "Mexico City", country: "Mexico", rank: 5, population: "22,085,140", lat: 19.4326, lng: -99.1332 },
  { name: "Cairo", country: "Egypt", rank: 6, population: "20,900,604", lat: 30.0444, lng: 31.2357 },
  { name: "Mumbai", country: "India", rank: 7, population: "20,667,656", lat: 19.076, lng: 72.8777 },
  { name: "Beijing", country: "China", rank: 8, population: "20,463,985", lat: 39.9042, lng: 116.4074 },
  { name: "Dhaka", country: "Bangladesh", rank: 9, population: "20,283,552", lat: 23.8103, lng: 90.4125 },
  { name: "Osaka", country: "Japan", rank: 10, population: "19,059,856", lat: 34.6937, lng: 135.5023 },
  { name: "New York", country: "USA", rank: 11, population: "18,823,000", lat: 40.7128, lng: -74.006 },
  { name: "Karachi", country: "Pakistan", rank: 12, population: "16,459,472", lat: 24.8607, lng: 67.0011 },
  { name: "Buenos Aires", country: "Argentina", rank: 13, population: "15,154,000", lat: -34.6037, lng: -58.3816 },
  { name: "Chongqing", country: "China", rank: 14, population: "15,872,000", lat: 29.563, lng: 106.5516 },
  { name: "Istanbul", country: "Turkey", rank: 15, population: "15,190,000", lat: 41.0082, lng: 28.9784 },
  { name: "Kolkata", country: "India", rank: 16, population: "14,681,589", lat: 22.5726, lng: 88.3639 },
  { name: "Manila", country: "Philippines", rank: 17, population: "14,158,573", lat: 14.5995, lng: 120.9842 },
  { name: "Lagos", country: "Nigeria", rank: 18, population: "14,862,111", lat: 6.5244, lng: 3.3792 },
  { name: "Rio de Janeiro", country: "Brazil", rank: 19, population: "13,544,000", lat: -22.9068, lng: -43.1729 },
  { name: "Tianjin", country: "China", rank: 20, population: "13,396,402", lat: 39.3434, lng: 117.3616 },
];

export default function GlobalMapWithMarkers() {
  const mapRef = useRef(null);
  const [selectedCity, setSelectedCity] = useState(null);
  const [mapLoaded, setMapLoaded] = useState(false);

  useEffect(() => {
    const existingScript = document.getElementById("google-maps-script");

    if (!existingScript) {
      const script = document.createElement("script");
      script.id = "google-maps-script";
      script.src = `https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY`;
      script.async = true;
      script.defer = true;
      script.onload = () => {
        setMapLoaded(true);
      };
      document.body.appendChild(script);
    } else {
      setMapLoaded(true);
    }
  }, []);

  useEffect(() => {
    if (mapLoaded && window.google && mapRef.current) {
      const map = new window.google.maps.Map(mapRef.current, {
        center: { lat: 20, lng: 0 }, 
        zoom: 2,
      });

      cities.forEach((city) => {
        const marker = new window.google.maps.Marker({
          position: { lat: city.lat, lng: city.lng },
          map,
          title: city.name,
        });

        marker.addListener("click", () => {
          setSelectedCity(city);
        });
      });
    }
  }, [mapLoaded]);

  return (
    <div className="w-full h-screen relative">
      {/* 地图容器 */}
      <div ref={mapRef} className="w-full h-full" />

      {/* 非模态的城市信息弹出框 */}
      {selectedCity && (
        <div
          className="absolute top-1/2 left-1/2 z-10 max-w-md w-full -translate-x-1/2 -translate-y-1/2 bg-white p-4 shadow-lg rounded-2xl"
        >
          <div className="flex justify-between items-center mb-2">
            <h2 className="text-xl font-bold">城市信息</h2>
            <button
              className="px-2 py-1 text-sm font-semibold bg-gray-200 rounded hover:bg-gray-300"
              onClick={() => setSelectedCity(null)}
            >
              关闭
            </button>
          </div>
          <div className="space-y-2">
            <p className="text-lg font-semibold">{selectedCity.name}</p>
            <p>排名: {selectedCity.rank}/20</p>
            <p>人口: {selectedCity.population}</p>
            <p>国家: {selectedCity.country}</p>
          </div>
        </div>
      )}
    </div>
  );
}

注意:在上述代码正常工作之前,您需要拥有一个谷歌云账户,设置API密钥,并启用地图JavaScript API。

摘要

随着这些令人印象深刻的更新,开放AI显著提高了其画布产品的实用性。好吧,它不会说服任何当前的Cursor或Windsurf用户放弃他们的工具集……但谁知道开放AI将在接下来的几周和几个月内将这个产品推向何处。由于DeepSeek等公司的基本LLM业务可能受到挤压,他们可能会开始将注意力转向有利可图的编码助手市场。

也许未来的某一天,画布会得到极大的增强,独立出来,并单独对LLM使用收费。

当然,Cursor和其他人也可能在关注这个升级时感到恐慌,以防开放AI继续增加画布的功能而不收取额外费用。如果我们在不久的将来看到他们的月费减少,我们就会知道他们认为哪个未来更有可能。

但目前,画布仍然是它本来的样子。一个有用的,我会说相当令人印象深刻的工具,您可以根据需要随时使用。绝对值得一看。

Related Posts

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

AI 研究报告和论文写作 合并两个系统指令以获得两个模型的最佳效果 Perplexity AI 的 Deep Research 工具提供专家级的研究报告,而 OpenAI 的 ChatGPT-o3-mini-high 擅长推理。我发现你可以将它们结合起来生成令人难以置信的论文,这些论文比任何一个模型单独撰写的都要好。你只需要将这个一次性提示复制到 **

阅读更多
让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

Non members click here作为一名软件开发人员,多年来的一个发现总是让我感到惊讶,那就是人们还在 Excel

阅读更多
使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

10 个常见问题解答 本文是我推出的一个名为“10 个常见问题解答”的新系列的一部分。在本系列中,我旨在通过回答关于该主题的十个最常见问题来分解复杂的概念。我的目标是使用简单的语言和相关的类比,使这些想法易于理解。 图片来自 [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=medium&utm_medi

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

在AI军备竞赛中分辨事实与虚构 DeepSeek AI真的是它所宣传的游戏规则改变者,还是仅仅聪明的营销和战略炒作?👀 虽然一些人将其视为AI效率的革命性飞跃,但另一些人则认为它的成功建立在借用(甚至窃取的)创新和可疑的做法之上。传言称,DeepSeek的首席执行官在疫情期间像囤积卫生纸一样囤积Nvidia芯片——这只是冰山一角。 从其声称的550万美元培训预算到使用Open

阅读更多
Type something to search...