【05】从0到1构建AI生成思维导图应用 -- 前端交互实现

news2024/9/20 7:47:59

【05】从0到1构建AI生成思维导图应用 – 前端交互实现

大家好!最近自己做了一个完全免费的AI生成思维导图的网站,支持下载,编辑和对接微信公众号,可以在这里体验:https://lt2mind.zeabur.app/
上一章:https://blog.csdn.net/m0_56699208/article/details/140061215?spm=1001.2014.3001.5502

上一章中,我们已经构建了完整的 生成思维导图的 AI 功能,并将其暴露为 API。接下来,我们要编写一套交互逻辑,供用户输入文字或链接,点击按钮,即可生成思维导图,并提供下载和编辑按钮。

import axios from "axios";
export const toMind = async (query: string) => {
    const url = 'https://api.coze.cn/open_api/v2/chat';
    const headers = {
    'Content-Type': 'application/json',
      'Authorization': "Bearer your api key"
    };
    const body = {
      "conversation_id": "1",
      "bot_id": "your bot id",
      "user": "29032201862555",
      "query": query,
      "stream": false
    };
  
    try {
      const response = await axios.post(url, body, { headers });
      console.log('Response:', response.data.messages[2].content);
      const urlPattern = /https:\/\/[^\s]+/g;
      let urls = response.data.messages[2].content.match(urlPattern);
      let imgUrl = urls[0]
      let editUrl = urls[1]
      return {imgUrl, editUrl}
    } catch (error) {
      console.error('Error:', error);
    }
  };

这段代码使用正则表达式/https://[^\s]+/g来匹配响应内容中的URL,包含两个属性imgUrl和editUrl,分别对应匹配到的第一个和第二个URL。这两个URL分别是图片的下载地址和对应在treemind里面的编辑地址。我们只需要在前端把链接给到对应的按钮上,即可实现交互逻辑:
完整代码:

"use client";
import { useState } from "react";
import { SignedOut, useUser } from "@clerk/nextjs";
import { Textarea } from "./ui/textarea";
import Header from "./header";
import Feature from "../components/feature";
import Img from "next/image";
import { Button } from "@/components/ui/button";
import { toMind } from "@/lib/coze";
import Link from "next/link";
import { Typewriter } from "react-simple-typewriter";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../components/ui/tooltip";

export default function Hero() {
  const { isSignedIn } = useUser();
  const [imgUrl, setImgUrl] = useState("");
  const [editUrl, setEditUrl] = useState("");
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (event: any) => {
    event.preventDefault(); // Prevent the default form submission behavior
    if (!isSignedIn) {
      //router.push('/sign-in');
      return;
    }
    setLoading(true);
    const inputValue = event.target.elements.textOrLink.value; // Get the value from the textarea
    const result = await toMind(inputValue); // Call the toMind function with the input value
    if (result) {
      setImgUrl(result.imgUrl);
      setEditUrl(result.editUrl);
    }
    setLoading(false);
  };

  return (
    <div className="flex flex-col bg">
      <header className="text-blue-500">
        <Header />
        <section className="container max-w-5xl px-4 md:px-6 py-6 md:py-10">
          <div className="text-center space-y-4 sm:mt-4">
            <h1 className="text-4xl md:text-6xl font-bold tracking-widest">
              LT2MIND
            </h1>
            <p className="text-lg md:text-xl max-w-3xl mx-auto italic">
              <Typewriter
                words={[
                  "Transform your text and links into beautiful mind maps with ease.",
                ]}
                loop={1}
                cursor
                cursorStyle=""
                typeSpeed={20}
                deleteSpeed={50}
                delaySpeed={1000}
              />
            </p>
          </div>
        </section>
        <Feature />
        <section className="py-12 md:py-20">
          <div className="container max-w-5xl px-4 md:px-6 grid grid-cols-1 md:grid-cols-2 gap-8">
            <div className="space-y-4">
              <h2 className="text-3xl font-bold text-purple-400">
                Convert to Mind Map
              </h2>
              <p className="text-muted-foreground">
                Enter your text or link and let LT2Mind do the rest. You may
                wait for one minute or more for the transition to complete.
              </p>
              <form className="flex gap-2" onSubmit={handleSubmit}>
                <div className="flex flex-col gap-2 h-[40vh] w-full">
                  <Textarea
                    name="textOrLink"
                    placeholder="Enter text or link..."
                    className="shadow-sm focus:border-none flex-1 resize-none bg"
                    style={{
                      outline: "none",
                      overflow: "auto",
                      scrollbarWidth: "none",
                      msOverflowStyle: "none",
                    }}
                  />

                  <style jsx>{`
                    textarea::-webkit-scrollbar {
                      display: none;
                    }
                  `}</style>
                  <TooltipProvider>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <div>
                          <Button
                            type="submit"
                            className="mt-2 w-full bg-pink-200 text-purple-500 hover:bg-pink-100"
                            disabled={!isSignedIn}
                          >
                            Convert
                          </Button>
                        </div>
                      </TooltipTrigger>
                      {!isSignedIn && (
                        <TooltipContent>
                          You need to sign in to convert
                        </TooltipContent>
                      )}
                    </Tooltip>
                  </TooltipProvider>
                </div>
              </form>
            </div>
            {loading ? (
              <div className="flex flex-col items-center justify-center gap-2">
                <div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-purple-500"></div>
                <p className="text-lg text-purple-400">converting...</p>
              </div>
            ) : imgUrl ? (
              <div className="flex flex-col items-center justify-center gap-2">
                <img
                  src={imgUrl}
                  alt="Image 1"
                  className="w-full h-full object-contain shadow-sm"
                />
                <div className="flex gap-x-4 w-full justify-center">
                  <Link href={editUrl} target="_blank" className="w-full">
                    <Button className="bg-pink-200 text-purple-500 w-full hover:bg-pink-100">
                      Edit in TreeMind
                    </Button>
                  </Link>
                  <a
                    href={imgUrl}
                    download="mindmap.jpeg"
                    target="_blank"
                    className="w-full"
                  >
                    <Button className="bg-pink-200 text-purple-500 w-full hover:bg-pink-100">
                      Download
                    </Button>
                  </a>
                </div>
              </div>
            ) : (
              <div className="flex flex-col items-center justify-center gap-2">
                <p className="text-lg text-purple-400">
                  Waiting For Conversion
                  <Typewriter
                    words={["..."]}
                    loop={true}
                    cursor
                    cursorStyle=""
                    typeSpeed={200}
                    deleteSpeed={50}
                    delaySpeed={2000}
                  />
                </p>
                {/* <div className="flex gap-x-4 w-full justify-center">
                <Skeleton className="w-full" />
                <Skeleton className="w-full" />
                </div> */}
              </div>
            )}
          </div>
        </section>
      </header>
    </div>
  );
}

这样,用户输入文字,点击按钮后,就能实现生成的逻辑:
在这里插入图片描述
在这里插入图片描述
生成完成后,用户可以点击按钮选择下载或是继续编辑。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1878105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5_Clark变换Simulink仿真详细步骤

一、Clark变换的计算过程 根据投影定理: Iα由Ia、Ib、Ic共同投影决定&#xff0c;根据几何原理&#xff0c;IαIa-cos(60&#xff09;*Ib-cos(60&#xff09;*Ic,即是IαIa-0.5*Ib-0.5*Ic Iβ由Ib、Ic共同投影决定&#xff0c;根据几何原理&#xff0c;Iβsin&#xff08;60&a…

下一代的JDK - GraalVM

GraalVM是最近几年Java相关的新技术领域不多的亮点之一&#xff0c; 被称之为革命性的下一代JDK&#xff0c;那么它究竟有什么神奇之处&#xff0c;又为当前的Java开发带来了一些什么样的改变呢&#xff0c;让我们来详细了解下 下一代的JDK 官网对GraalVM的介绍是 “GraalVM 是…

【Python机器学习】模型评估与改进——交叉验证

交叉验证是一种评估泛化性能的统计学方法&#xff0c;它比单次划分训练集和测试集的方法更稳定、前面。在交叉验证中&#xff0c;数据被多次划分&#xff0c;并且需要训练多个模型。最常用的交叉验证是k折交叉验证&#xff0c;其中k是由用户指定的数字&#xff0c;通常取5或10,…

MySQL高级-InnoDB引擎-事务日志- redo log(事务持久性的保证)

文章目录 1、redo log1.1、重做日志缓冲&#xff08;redo log buffer&#xff09;1.2、重做日志文件&#xff08;redo log file&#xff09; 2、如果没有redo log&#xff0c;可能会存在什么问题的&#xff1f;2.2、我们一起来分析一下。 2.2、那么&#xff0c;如何解决上述的问…

240629_昇思学习打卡-Day11-Vision Transformer中的self-Attention

240629_昇思学习打卡-Day11-Transformer中的self-Attention 根据昇思课程顺序来看呢&#xff0c;今儿应该看Vision Transformer图像分类这里了&#xff0c;但是大概看了一下官方api&#xff0c;发现我还是太笨了&#xff0c;看不太明白。正巧昨天学SSD的时候不是参考了太阳花的…

Databend db-archiver 数据归档压测报告

Databend db-archiver 数据归档压测报告 背景准备工作Create target databend table启动 small warehouse准备北京区阿里云 ECSdb-archiver 的配置文件准备一亿条源表数据开始压测 背景 本次压测目标为使用 db-archiver 从 MySQL 归档数据到 Databend Cloud&#xff0c; 归档的…

qt 开发笔记 动态链接库应用

1.概要 1.1 需求 库有两种&#xff0c;动态库和静态库&#xff0c;这里说的是动态库&#xff1b;动态库的加载方式有两种&#xff0c;一直是静态的一种是动态的&#xff0c;这里的静态加载是指静态加载动态&#xff0c;是一种加载动态库的方式。也有一种动态加载的方式&#…

衣服、帽子、鞋子相关深度学习数据集大合集(1)

最近收集了一大波关于衣物深度学习数据集&#xff0c;主要有衣服、帽子、鞋子、短裤、短袖、T恤等。 1、运动裤、短裤图片数据集 数据格式&#xff1a;图片 是否标注&#xff1a;已标注 标注格式&#xff1a;yolov8 图片数量&#xff1a;915张 查看地址&#xff1a;https…

# Sharding-JDBC从入门到精通(2)- Sharding-JDBC 介绍

Sharding-JDBC从入门到精通&#xff08;2&#xff09;- Sharding-JDBC 介绍 一、概述-分库分表所带来的问题 1、分库分表带来的问题 分库分表能有效的缓解了单机和单库带来的性能瓶颈和压力&#xff0c;突破网络 IO、硬件资源、连接数的瓶颈&#xff0c;同时也带来了一些问题…

容器进程

一、容器进程和宿主机进程的关系 容器在进程空间上和宿主机是隔离的&#xff0c;每创建一个容器&#xff0c;该容器都有一个独属的进程空间简称PID NameSpace。但是容器本质也是一个进程&#xff0c;自然是由其父进程创建的&#xff0c;这个可以使用ps aux命令验证。 | 容器视…

Thinger.io 支持多协议、插件化100%开源 IoT 企业级物联网平台

项目源码&#xff0c;文末联系小编 Thinger.io 是一个开源插件化物联网平台&#xff0c;提供了设备原型、扩展和设备连接管理所需的一切工具。我们的目标是使物联网的使用民主化&#xff0c;使其可供全世界使用&#xff0c;并简化大型物联网项目的开发。 01 Thinger.io 物联网平…

【C++】哈希表 --- 闭散列版本的实现

在无人问津日子里 正是登峰造极的好时机 ——《人民日报》 哈希表 --- 闭散列版本的实现 1 C中的哈希表2 哈希表底层2.1 功能2.1 哈希冲突2.3 开散列与闭散列 3 闭散列版本的实现3.1 框架搭建3.2 仿函数设计3.3 插入函数3.4 查找函数3.5 删除函数 Thanks♪(&#xff65;ω&a…

windows 10 安装tcping 使用教程

1 官网下载:tcping下载 2 复制tcping 到win10系统目录C:\Windows\System32 3 tcping 网址测试,可以指定端口 4 tcping 测试端口联通 5 tcping http模式

LeetCode 算法: 合并 K 个升序链表 c++

原题链接&#x1f517;&#xff1a;合并 K 个升序链表 难度&#xff1a;困难⭐️⭐️⭐️ 题目 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists […

Hugging Face Accelerate 两个后端的故事:FSDP 与 DeepSpeed

社区中有两个流行的零冗余优化器 (Zero Redundancy Optimizer&#xff0c;ZeRO)算法实现&#xff0c;一个来自DeepSpeed&#xff0c;另一个来自PyTorch。Hugging FaceAccelerate对这两者都进行了集成并通过接口暴露出来&#xff0c;以供最终用户在训练/微调模型时自主选择其中之…

Python | Leetcode Python题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; class Solution:def hammingWeight(self, n: int) -> int:ret 0while n:n & n - 1ret 1return ret

PAE:从潮流报告中提炼有效产品属性

本文将介绍PAE&#xff0c;一种用于包含 PDF格式的文本和图像的产品属性提取算法。目前大部分的方法侧重于从标题或产品描述中提取属性&#xff0c;或利用现有产品图像中的视觉信息。与之前的工作相比&#xff0c;PAE从潮流趋势报告的PDF文件中提取属性&#xff0c;提取的属性包…

ISO26262标准

什么是ISO26262&#xff1f; ISO 26262(国际功能安全标准)是一个涵盖整个汽车产品开发过程的汽车功能安全标准。ISO 26262继承或改编自工业自动化行业的安全要求标准IEC61508&#xff0c;但专门为汽车行业量身定制。最新版本是ISO26262-1:2018。 它包括诸如需求分析、安全分析…

一个简单的文件上传功能

代码如下&#xff1a; PostMapping("/upload")public ResponseEntity<String> handleFileUpload(RequestParam(value "uploadDirectory") String uploadDirectory,RequestParam("fileName") MultipartFile fileName) {try {// 确保文件不…

乱扔垃圾自动识别摄像头

如今&#xff0c;随着城市化进程的加快和人们生活水平的提高&#xff0c;环境保护和城市美观成为社会关注的焦点。乱扔垃圾问题长期困扰着城市管理者和居民&#xff0c;给城市环境卫生带来严重挑战。为了有效解决这一问题&#xff0c;乱扔垃圾自动识别摄像头应运而生&#xff0…