【AI】⭐️搭建一个简单的个人问答网页

目录

🍸前言

🍻一、环境配置

🍹二、具体实现

        2.1 接口改动

        2.2 静态页面

🍸三、测试

        3.1 页面如下

        3.2 问答测试

​🍹 四、章末


🍸前言

        小伙伴们大家好,上次在本地测试了智普大模型提供的免费 api ,并且在控台实现了结果的流式输出,文章链接如下:

【AI】✈️实现一个简单的问答服务-优快云博客

        但是只看控台还是不太行,费眼,鄙人对 html、css、js 这些也只是略懂一点,但是足以在已有接口的基础上改动下,搭配一个简易的前端页面,实现一个问答服务

🍻一、环境配置

        因为目前后端的接口环境已经有了,所以直接将静态页面跟后端接口放在一起,属于前后端不分离的项目

        后端环境:jdk8、springBoot

        前端使用:html、css、js

        大模型使用的依然是智普,可以看下之前的文章,申请个账号即可,比较简单

🍹二、具体实现

        2.1 接口改动

        接口会返回一个 SseEmitter(Server-Sent Events,服务器推送事件)用于在服务器与客户端之间进行流式数据传输;

        这里使用的 client 实例,可以参考上篇文章,为智普提供的操作api的实例;

        请求进来后,会打印下请求参数,然后新创建一个线程去异步执行,提高响应效率;

    @GetMapping("/testAi2")
    public SseEmitter testAi2(@RequestParam("question") String question) {
        // 创建 SseEmitter 对象,用于流式推送
        SseEmitter emitter = new SseEmitter();
        System.out.println("请求进来了,对应的问题是: " + question);

        // 创建新的线程来处理流式数据
        new Thread(() -> {
            try {
                // 获取流式数据
                List<ChatMessage> messages = new ArrayList<>();
                ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), question);
                messages.add(chatMessage);
                String requestId = UUID.randomUUID().toString();
                ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                        .model(Constants.ModelChatGLM4)
                        .stream(Boolean.TRUE)
                        .messages(messages)
                        .requestId(requestId)
                        .build();

                ModelApiResponse sseModelApiResp = client.invokeModelApi(chatCompletionRequest);

                if (sseModelApiResp.isSuccess()) {
                    AtomicBoolean isFirst = new AtomicBoolean(true);

                    // 将流数据映射到累加器并推送到前端
                    mapStreamToAccumulator(sseModelApiResp.getFlowable(), chatMessage)
                            .doOnNext(accumulator -> {

                                if (accumulator.getDelta() != null && accumulator.getDelta().getContent() != null) {
                                    // 通过 SSE 推送数据到前端
                                    try {
                                        emitter.send(accumulator.getDelta().getContent(), MediaType.TEXT_PLAIN);
                                    } catch (IOException e) {
                                        System.err.println("发送数据失败: " + e.getMessage());
                                        emitter.completeWithError(e);  // 发生错误时,关闭连接
                                    }
                                }
                            })
                            .doOnComplete(() -> {
                                try {
                                    // 在流完成时,发送 'end' 事件
                                    emitter.send("end", MediaType.TEXT_PLAIN); // 发送 'end' 标志
                                    emitter.complete(); // 完成 SSE 流
                                } catch (IOException e) {
                                    System.err.println("完成流时发送数据失败: " + e.getMessage());
                                    emitter.completeWithError(e);  // 发生错误时,关闭连接
                                }
                            })
                            .blockingLast();
                }
            } catch (Exception e) {
                System.err.println("处理过程中发生错误: " + e.getMessage());
                emitter.completeWithError(e);
            }
        }).start();

        return emitter;
    }
        2.2 静态页面

        css,js 跟 html 代码放到一起的,具体位置要在 resources/static 下面,这样项目启动后可以访问到这些静态资源;代码具体如下:因为对具体的使用不是很清楚,整体的搭建也是在 chatGpt 的帮助下,一步一步调试完善的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI Response</title>
  <style>
    body {
      font-family: 'Arial', sans-serif;
      background-color: #f4f7fc;
      color: #333;
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      flex-direction: column;
    }

    h1 {
      font-size: 2.5rem;
      color: #5c6bc0;
      margin-bottom: 20px;
    }

    .container {
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      padding: 30px;
      width: 100%;
      max-width: 600px;
      text-align: center;
    }

    input[type="text"] {
      width: 80%;
      padding: 12px;
      font-size: 1rem;
      border: 2px solid #ccc;
      border-radius: 4px;
      margin-bottom: 15px;
      transition: border-color 0.3s;
    }

    input[type="text"]:focus {
      border-color: #5c6bc0;
      outline: none;
    }

    button {
      padding: 12px 20px;
      font-size: 1rem;
      color: white;
      background-color: #5c6bc0;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      transition: background-color 0.3s;
    }

    button:hover {
      background-color: #4f5a92;
    }

    #response {
      display: none;
      background-color: #e3f2fd;
      border: 1px solid #90caf9;
      padding: 15px;
      border-radius: 4px;
      margin-top: 20px;
      text-align: left;
      max-height: 400px;
      overflow-y: auto;
      white-space: pre-line; /* 保持换行 */
      font-size: 1rem;
      color: #1e88e5;
    }

    /* 头像样式 */
    #wechat-avatar {
      position: fixed;
      bottom: 20px;
      right: 20px;
      width: 150px;  /* 调整头像大小 */
      height: 150px;
      border-radius: 50%;
      border: 3px solid #fff; /* 给头像加白色边框 */
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 轻微阴影 */
      cursor: pointer;
    }

  </style>
</head>
<body>
<h1>Ask the AI</h1>
<div class="container">
  <input type="text" id="question" placeholder="请输入问题" />
  <button id="askButton">提问</button>
  <div id="response"></div>
</div>

<!-- 微信头像,假设头像文件存放在 'images' 文件夹下 -->
<img id="wechat-avatar" src="uploads/weixinPic.jpg" alt="微信头像" title="点击联系我" onclick="window.open('https://blog.youkuaiyun.com/TM007_?spm=1000.2115.3001.5343');" />

<script>
  document.getElementById('askButton').addEventListener('click', function () {
    const question = document.getElementById('question').value.trim();
    if (!question) {
      alert("请输入一个问题!");
      return;
    }

    const responseDiv = document.getElementById('response');
    responseDiv.style.display = 'none'; // 隐藏答案区域,等待新问题的响应

    // 清空之前的回答
    responseDiv.innerHTML = '';

    // 创建 EventSource 对象
    const eventSource = new EventSource(`http://localhost:8888/test/testAi2?question=${encodeURIComponent(question)}`);

    // 监听 SSE 数据流
    eventSource.onmessage = function(event) {
      const data = event.data;
      if (data) {
        responseDiv.textContent += data; // 用 textContent 代替 innerHTML 以避免注入
        responseDiv.style.display = 'block'; // 显示答案区域
      }
    };

    // 监听 SSE 流的结束
    eventSource.addEventListener('end', function(event) {
      responseDiv.textContent += "\n回答完毕";  // 使用 \n 来保证换行
      eventSource.close(); // 关闭 SSE 连接
    });

    // 监听错误事件
    eventSource.onerror = function(event) {
      // 检查是否是正常关闭的连接
      if (eventSource.readyState === EventSource.CLOSED) {
        return;  // 如果连接已经被关闭,就不做任何处理
      }

      console.error("SSE 错误:", event);  // 输出错误日志以便调试
      eventSource.close(); // 关闭 SSE 连接,避免触发重复的错误
    };
  });
</script>
</body>
</html>

🍸三、测试

        启动后端项目,浏览器访问端口号+静态资源,本地地址如下:

http://localhost:8888/index2.html

        3.1 页面如下

       一个问题输入框,可点击的按钮,一个横幅,加上 右下角的图片可以点击跳转,具体跳转到哪的,不明说了!

        3.2 问答测试

         输入问题,点击提问,流式输出的整体速度还好,后端记录也存在

🍹 四、章末

        本地址是简单实现了页面上展示的功能,其中包含的问题还有很多,但是也能使用,留给后面在做更新,文章到这里既结束了~

### 构建具备AI问答功能的网页网站 构建一个具备AI问答功能的网页网站需要结合前端开发、后端开发以及自然语言处理技术。以下是实现这一目标的核心内容: #### 1. **选择合适的AI问答模型** 为了实现AI问答功能,可以选择预训练的模型或自定义训练模型。例如,可以使用Hugging Face提供的预训练模型[^3],这些模型已经在大量文本数据上进行了训练,能够很好地理解用户的问题并生成答案。 #### 2. **搭建后端服务** 后端服务负责处理用户的请求并将问题传递给AI模型进行处理。可以使用Python中的Flask框架来快速搭建一个后端API。以下是一个简单的Flask代码示例: ```python from flask import Flask, request, jsonify import transformers app = Flask(__name__) # 加载预训练模型 model = transformers.pipeline("question-answering") @app.route('/answer', methods=['POST']) def answer(): data = request.json question = data['question'] context = data['context'] result = model(question=question, context=context) return jsonify(result) if __name__ == '__main__': app.run(debug=True) ``` 这段代码展示了如何加载一个预训练的问答模型,并通过HTTP接口接收问题和上下文信息,返回答案[^3]。 #### 3. **设计前端界面** 前端界面是用户与AI交互的主要入口。可以使用HTML、CSS和JavaScript来设计一个简洁的用户界面。此外,可以通过AJAX或Fetch API将用户输入发送到后端API并显示结果。以下是一个简单前端代码示例: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AI问答系统</title> </head> <body> <h1>AI问答系统</h1> <textarea id="question" placeholder="请输入您的问题"></textarea><br> <button onclick="sendQuestion()">提交</button> <div id="answer"></div> <script> function sendQuestion() { const question = document.getElementById('question').value; fetch('/answer', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ question, context: "这是一个示例上下文" }) }) .then(response => response.json()) .then(data => { document.getElementById('answer').innerText = data.answer; }); } </script> </body> </html> ``` 此代码展示了一个简单的表单,允许用户输入问题并通过Fetch API将其发送到后端API[^4]。 #### 4. **集成AI助手到现有网站** 如果希望将AI助手嵌入到现有的网站中,可以参考悬浮窗模式的嵌入脚本[^4]。通过将AI助手的嵌入代码添加到网站的HTML文件中,用户可以在浏览网页时随时调用AI助手进行提问。 #### 5. **优化与扩展** 为了提高用户体验,可以进一步优化系统的性能和功能。例如: - 引入更复杂的对话管理机制以支持多轮对话。 - 使用缓存技术减少重复计算的时间。 - 提供多种语言支持以满足国际化需求。 --- ###
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

先锋 Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值