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

【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>
  );
}

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

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值