diff --git a/integrate_mcp_to_app.py b/integrate_mcp_to_app.py
new file mode 100644
index 00000000..f56d1d63
--- /dev/null
+++ b/integrate_mcp_to_app.py
@@ -0,0 +1,49 @@
+# integrate_mcp_to_app.py - 集成 MCP 到主应用的示例代码
+# 将以下代码添加到 app.py
+
+"""
+在 app.py 中添加以下内容:
+
+1. 在文件顶部导入:
+"""
+
+from mcp_chat_api import mcp_chat_bp
+
+"""
+2. 在 Flask app 初始化后注册蓝图:
+"""
+
+# 注册 MCP 聊天 API
+app.register_blueprint(mcp_chat_bp)
+
+"""
+3. 确保 CORS 配置允许 Next.js 应用访问:
+"""
+
+from flask_cors import CORS
+
+CORS(app, resources={
+ r"/api/*": {
+ "origins": [
+ "http://localhost:3000", # Next.js 开发环境
+ "http://localhost:3001", # 主应用
+ "http://49.232.185.254:*", # 生产服务器
+ ],
+ "supports_credentials": True, # 重要:允许携带 Cookie
+ "allow_headers": ["Content-Type", "Authorization"],
+ "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
+ }
+})
+
+"""
+4. Session 配置确保跨应用共享:
+"""
+
+app.config['SESSION_COOKIE_NAME'] = 'session' # 与现有保持一致
+app.config['SESSION_COOKIE_HTTPONLY'] = True
+app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' # 允许跨站点携带
+app.config['SESSION_COOKIE_PATH'] = '/' # 全路径可用
+
+# 生产环境额外配置
+# app.config['SESSION_COOKIE_DOMAIN'] = '.yourdomain.com' # 支持子域
+# app.config['SESSION_COOKIE_SECURE'] = True # HTTPS only
\ No newline at end of file
diff --git a/mcp_chat_api.py b/mcp_chat_api.py
new file mode 100644
index 00000000..a9d446f8
--- /dev/null
+++ b/mcp_chat_api.py
@@ -0,0 +1,233 @@
+# mcp_chat_api.py - MCP 聊天 API 端点
+# 添加到 app.py 或作为独立模块导入
+
+from flask import Blueprint, request, jsonify, session, Response
+import json
+import time
+from typing import Generator
+
+# 创建蓝图
+mcp_chat_bp = Blueprint('mcp_chat', __name__, url_prefix='/api/mcp')
+
+# 假设已有 mcp_server.py 中的相关功能
+# from mcp_server import process_message, get_available_tools, execute_code
+
+def check_chat_permission():
+ """检查用户是否有权限访问 AI 聊天功能"""
+ if not session.get('user_id'):
+ return False, '请先登录'
+
+ # 这里可以添加订阅检查逻辑
+ # user = User.query.get(session['user_id'])
+ # if user.subscription_tier not in ['premium', 'pro', 'enterprise']:
+ # return False, '需要订阅才能使用 AI 助手'
+
+ return True, None
+
+@mcp_chat_bp.route('/chat', methods=['POST'])
+def chat():
+ """处理聊天消息"""
+ # 权限检查
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ data = request.json
+ message = data.get('message', '')
+ session_id = data.get('sessionId', '')
+ model = data.get('model', 'claude-3-opus')
+
+ if not message:
+ return jsonify({'error': '消息不能为空'}), 400
+
+ try:
+ # 调用 MCP 处理消息
+ # response = process_message(
+ # message=message,
+ # user_id=session['user_id'],
+ # session_id=session_id,
+ # model=model
+ # )
+
+ # 临时模拟响应
+ response = {
+ 'reply': f'收到您的消息: "{message}"。这是一个模拟响应,实际部署时会调用 MCP 模型。',
+ 'sessionId': session_id,
+ 'timestamp': time.time()
+ }
+
+ return jsonify(response)
+
+ except Exception as e:
+ print(f"Chat error: {e}")
+ return jsonify({'error': '处理消息时出错'}), 500
+
+@mcp_chat_bp.route('/chat/stream', methods=['POST'])
+def chat_stream():
+ """流式处理聊天消息"""
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ data = request.json
+ message = data.get('message', '')
+ session_id = data.get('sessionId', '')
+
+ def generate() -> Generator[str, None, None]:
+ """生成 SSE 流"""
+ try:
+ # 这里应该调用实际的 MCP 流式 API
+ # for chunk in mcp_stream_message(message, session_id):
+ # yield f"data: {json.dumps(chunk)}\n\n"
+
+ # 临时模拟流式响应
+ words = f'这是对 "{message}" 的流式响应。每个字会逐个发送。'.split()
+ for word in words:
+ chunk = {'content': word + ' ', 'type': 'text'}
+ yield f"data: {json.dumps(chunk)}\n\n"
+ time.sleep(0.1) # 模拟延迟
+
+ yield "data: [DONE]\n\n"
+
+ except Exception as e:
+ error_chunk = {'error': str(e), 'type': 'error'}
+ yield f"data: {json.dumps(error_chunk)}\n\n"
+
+ return Response(
+ generate(),
+ mimetype='text/event-stream',
+ headers={
+ 'Cache-Control': 'no-cache',
+ 'X-Accel-Buffering': 'no', # Nginx 不缓冲
+ }
+ )
+
+@mcp_chat_bp.route('/tools', methods=['GET'])
+def get_tools():
+ """获取可用的 MCP 工具列表"""
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ # 这里应该返回实际的工具列表
+ tools = [
+ {
+ 'id': 'code_executor',
+ 'name': '代码执行器',
+ 'description': '执行 Python、JavaScript 等代码',
+ 'icon': 'code'
+ },
+ {
+ 'id': 'web_search',
+ 'name': '网页搜索',
+ 'description': '搜索网络信息',
+ 'icon': 'search'
+ },
+ {
+ 'id': 'calculator',
+ 'name': '计算器',
+ 'description': '执行数学计算',
+ 'icon': 'calculator'
+ }
+ ]
+
+ return jsonify(tools)
+
+@mcp_chat_bp.route('/execute', methods=['POST'])
+def execute_code():
+ """执行代码"""
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ data = request.json
+ code = data.get('code', '')
+ language = data.get('language', 'python')
+
+ if not code:
+ return jsonify({'error': '代码不能为空'}), 400
+
+ try:
+ # 实际执行代码
+ # result = execute_code_safely(code, language)
+
+ # 临时模拟
+ result = {
+ 'output': f'执行 {language} 代码成功\n输出: Hello World',
+ 'error': None,
+ 'executionTime': 0.023
+ }
+
+ return jsonify(result)
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@mcp_chat_bp.route('/generate-code', methods=['POST'])
+def generate_code():
+ """生成代码"""
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ data = request.json
+ prompt = data.get('prompt', '')
+ language = data.get('language', 'python')
+
+ if not prompt:
+ return jsonify({'error': '提示不能为空'}), 400
+
+ try:
+ # 调用 MCP 生成代码
+ # code = mcp_generate_code(prompt, language)
+
+ # 临时模拟
+ code = f'''# {prompt}
+def hello_world():
+ print("Hello, World!")
+
+if __name__ == "__main__":
+ hello_world()'''
+
+ return jsonify({
+ 'code': code,
+ 'language': language,
+ 'prompt': prompt
+ })
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+@mcp_chat_bp.route('/history', methods=['GET'])
+def get_history():
+ """获取聊天历史"""
+ has_permission, error_msg = check_chat_permission()
+ if not has_permission:
+ return jsonify({'error': error_msg}), 401 if error_msg == '请先登录' else 403
+
+ session_id = request.args.get('sessionId')
+
+ # 这里应该从数据库获取历史
+ # history = ChatHistory.query.filter_by(
+ # user_id=session['user_id'],
+ # session_id=session_id
+ # ).all()
+
+ # 临时模拟
+ history = [
+ {
+ 'role': 'user',
+ 'content': '你好',
+ 'timestamp': '2024-01-01T10:00:00Z'
+ },
+ {
+ 'role': 'assistant',
+ 'content': '你好!有什么可以帮助您的吗?',
+ 'timestamp': '2024-01-01T10:00:01Z'
+ }
+ ]
+
+ return jsonify(history)
+
+# 在 app.py 中注册蓝图
+# app.register_blueprint(mcp_chat_bp)
\ No newline at end of file
diff --git a/nginx-agentchat-config.conf b/nginx-agentchat-config.conf
new file mode 100644
index 00000000..0b18fdba
--- /dev/null
+++ b/nginx-agentchat-config.conf
@@ -0,0 +1,55 @@
+# Nginx 配置片段 - 添加到 valuefrontier.conf 的 HTTPS server 块中
+# 将这些配置添加到 443 端口的 server 块中,在其他 location 配置之前
+
+ # ============================================
+ # AI Chat 应用 (Next.js)
+ # ============================================
+
+ # AgentChat 应用代理 - 使用新路径避免与现有 /chat/ 冲突
+ location /ai-chat {
+ # 重写路径,去掉 /ai-chat 前缀
+ rewrite ^/ai-chat(.*)$ $1 break;
+
+ proxy_pass http://127.0.0.1:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # 保持 Cookie 传递(重要:Session 共享)
+ proxy_set_header Cookie $http_cookie;
+ proxy_pass_request_headers on;
+
+ # WebSocket 支持(如果需要实时功能)
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+
+ # 禁用缓冲,支持流式响应
+ proxy_buffering off;
+ proxy_cache off;
+
+ # 超时设置
+ proxy_connect_timeout 60s;
+ proxy_send_timeout 300s;
+ proxy_read_timeout 300s;
+ }
+
+ # Next.js 静态资源
+ location ~ ^/ai-chat/(_next|__nextjs) {
+ rewrite ^/ai-chat(.*)$ $1 break;
+
+ proxy_pass http://127.0.0.1:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # 静态资源缓存
+ expires 1y;
+ add_header Cache-Control "public, immutable";
+ }
+
+ # MCP API 已经配置在 /mcp/ 路径 (保持不变)
+ # location /mcp/ { ... } # 已存在,无需修改
\ No newline at end of file
diff --git a/src/components/Navbars/components/SecondaryNav/config.js b/src/components/Navbars/components/SecondaryNav/config.js
deleted file mode 100644
index e597649c..00000000
--- a/src/components/Navbars/components/SecondaryNav/config.js
+++ /dev/null
@@ -1,144 +0,0 @@
-// src/components/Navbars/components/SecondaryNav/config.js
-// 二级导航配置数据
-
-/**
- * 二级导航配置结构
- * - key: 匹配的路径前缀
- * - title: 导航组标题
- * - items: 导航项列表
- * - path: 路径
- * - label: 显示文本
- * - badges: 徽章列表 (可选)
- * - external: 是否外部链接 (可选)
- */
-export const secondaryNavConfig = {
- '/community': {
- title: '高频跟踪',
- items: [
- {
- path: '/community',
- label: '事件中心',
- badges: [
- { text: 'HOT', colorScheme: 'green' },
- { text: 'NEW', colorScheme: 'red' }
- ]
- },
- {
- path: '/concepts',
- label: '概念中心',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- },
- {
- path: '/data-browser',
- label: '数据浏览器',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- },
- '/concepts': {
- title: '高频跟踪',
- items: [
- {
- path: '/community',
- label: '事件中心',
- badges: [
- { text: 'HOT', colorScheme: 'green' },
- { text: 'NEW', colorScheme: 'red' }
- ]
- },
- {
- path: '/concepts',
- label: '概念中心',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- },
- {
- path: '/data-browser',
- label: '数据浏览器',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- },
- '/data-browser': {
- title: '高频跟踪',
- items: [
- {
- path: '/community',
- label: '事件中心',
- badges: [
- { text: 'HOT', colorScheme: 'green' },
- { text: 'NEW', colorScheme: 'red' }
- ]
- },
- {
- path: '/concepts',
- label: '概念中心',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- },
- {
- path: '/data-browser',
- label: '数据浏览器',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- },
- '/limit-analyse': {
- title: '行情复盘',
- items: [
- {
- path: '/limit-analyse',
- label: '涨停分析',
- badges: [{ text: 'FREE', colorScheme: 'blue' }]
- },
- {
- path: '/stocks',
- label: '个股中心',
- badges: [{ text: 'HOT', colorScheme: 'green' }]
- },
- {
- path: '/trading-simulation',
- label: '模拟盘',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- },
- '/stocks': {
- title: '行情复盘',
- items: [
- {
- path: '/limit-analyse',
- label: '涨停分析',
- badges: [{ text: 'FREE', colorScheme: 'blue' }]
- },
- {
- path: '/stocks',
- label: '个股中心',
- badges: [{ text: 'HOT', colorScheme: 'green' }]
- },
- {
- path: '/trading-simulation',
- label: '模拟盘',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- },
- '/trading-simulation': {
- title: '行情复盘',
- items: [
- {
- path: '/limit-analyse',
- label: '涨停分析',
- badges: [{ text: 'FREE', colorScheme: 'blue' }]
- },
- {
- path: '/stocks',
- label: '个股中心',
- badges: [{ text: 'HOT', colorScheme: 'green' }]
- },
- {
- path: '/trading-simulation',
- label: '模拟盘',
- badges: [{ text: 'NEW', colorScheme: 'red' }]
- }
- ]
- }
-};
diff --git a/src/components/Navbars/components/SecondaryNav/index.js b/src/components/Navbars/components/SecondaryNav/index.js
deleted file mode 100644
index e297a7fd..00000000
--- a/src/components/Navbars/components/SecondaryNav/index.js
+++ /dev/null
@@ -1,138 +0,0 @@
-// src/components/Navbars/components/SecondaryNav/index.js
-// 二级导航栏组件 - 显示当前一级菜单下的所有二级菜单项
-
-import React, { memo } from 'react';
-import {
- Box,
- Container,
- HStack,
- Text,
- Button,
- Flex,
- Badge,
- useColorModeValue
-} from '@chakra-ui/react';
-import { useNavigate, useLocation } from 'react-router-dom';
-import { useNavigationEvents } from '../../../../hooks/useNavigationEvents';
-import { secondaryNavConfig } from './config';
-
-/**
- * 二级导航栏组件
- * 根据当前路径显示对应的二级菜单项
- *
- * @param {Object} props
- * @param {boolean} props.showCompletenessAlert - 是否显示完整性提醒(影响 sticky top 位置)
- */
-const SecondaryNav = memo(({ showCompletenessAlert }) => {
- const navigate = useNavigate();
- const location = useLocation();
-
- // 颜色模式
- const navbarBg = useColorModeValue('gray.50', 'gray.700');
- const itemHoverBg = useColorModeValue('white', 'gray.600');
- const borderColorValue = useColorModeValue('gray.200', 'gray.600');
-
- // 导航埋点
- const navEvents = useNavigationEvents({ component: 'secondary_nav' });
-
- // 找到当前路径对应的二级导航配置
- const currentConfig = Object.keys(secondaryNavConfig).find(key =>
- location.pathname.includes(key)
- );
-
- // 如果没有匹配的二级导航,不显示
- if (!currentConfig) return null;
-
- const config = secondaryNavConfig[currentConfig];
-
- return (
-
-
-
- {/* 显示一级菜单标题 */}
-
- {config.title}:
-
-
- {/* 二级菜单项 */}
- {config.items.map((item, index) => {
- const isActive = location.pathname.includes(item.path);
-
- return item.external ? (
-
-
- {item.label}
- {item.badges && item.badges.length > 0 && (
-
- {item.badges.map((badge, bIndex) => (
-
- {badge.text}
-
- ))}
-
- )}
-
-
- ) : (
- {
- // 追踪侧边栏菜单点击
- navEvents.trackSidebarMenuClicked(item.label, item.path, 2, false);
- navigate(item.path);
- }}
- size="sm"
- variant="ghost"
- bg={isActive ? 'blue.50' : 'transparent'}
- color={isActive ? 'blue.600' : 'inherit'}
- fontWeight={isActive ? 'bold' : 'normal'}
- borderBottom={isActive ? '2px solid' : 'none'}
- borderColor="blue.600"
- borderRadius={isActive ? '0' : 'md'}
- _hover={{ bg: isActive ? 'blue.100' : itemHoverBg }}
- px={3}
- >
-
- {item.label}
- {item.badges && item.badges.length > 0 && (
-
- {item.badges.map((badge, bIndex) => (
-
- {badge.text}
-
- ))}
-
- )}
-
-
- );
- })}
-
-
-
- );
-});
-
-SecondaryNav.displayName = 'SecondaryNav';
-
-export default SecondaryNav;
diff --git a/src/views/AgentChat/.gitignore b/src/views/AgentChat/.gitignore
new file mode 100644
index 00000000..6c5d9561
--- /dev/null
+++ b/src/views/AgentChat/.gitignore
@@ -0,0 +1,21 @@
+# Next.js 应用忽略文件
+neuratalk/node_modules/
+neuratalk/.next/
+neuratalk/.env.local
+neuratalk/.env.production
+neuratalk/out/
+neuratalk/build/
+
+# 日志文件
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# IDE
+.idea
+.vscode
+
+# OS
+.DS_Store
+Thumbs.db
\ No newline at end of file
diff --git a/src/views/AgentChat/index.js b/src/views/AgentChat/index.js
deleted file mode 100644
index 6a1ce0e2..00000000
--- a/src/views/AgentChat/index.js
+++ /dev/null
@@ -1,1595 +0,0 @@
-// src/views/AgentChat/index_v4.js
-// Agent聊天页面 V4 - 黑金毛玻璃设计,带模型选择和工具选择
-
-import React, { useState, useEffect, useRef } from 'react';
-import { Global, css } from '@emotion/react';
-import {
- Box,
- Flex,
- VStack,
- HStack,
- Text,
- Input,
- IconButton,
- Button,
- Avatar,
- Heading,
- Divider,
- Spinner,
- Badge,
- useToast,
- Progress,
- Fade,
- Collapse,
- InputGroup,
- InputLeftElement,
- Menu,
- MenuButton,
- MenuList,
- MenuItem,
- Tooltip,
- Select,
- Checkbox,
- CheckboxGroup,
- Stack,
- Accordion,
- AccordionItem,
- AccordionButton,
- AccordionPanel,
- AccordionIcon,
- useDisclosure,
-} from '@chakra-ui/react';
-import {
- FiSend,
- FiSearch,
- FiPlus,
- FiMessageSquare,
- FiTrash2,
- FiMoreVertical,
- FiRefreshCw,
- FiDownload,
- FiCpu,
- FiUser,
- FiZap,
- FiClock,
- FiSettings,
- FiCheckCircle,
- FiChevronRight,
- FiTool,
-} from 'react-icons/fi';
-import { useAuth } from '@contexts/AuthContext';
-import { PlanCard } from '@components/ChatBot/PlanCard';
-import { StepResultCard } from '@components/ChatBot/StepResultCard';
-import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts';
-import { logger } from '@utils/logger';
-import axios from 'axios';
-
-/**
- * Agent消息类型
- */
-const MessageTypes = {
- USER: 'user',
- AGENT_THINKING: 'agent_thinking',
- AGENT_PLAN: 'agent_plan',
- AGENT_EXECUTING: 'agent_executing',
- AGENT_RESPONSE: 'agent_response',
- ERROR: 'error',
-};
-
-/**
- * 可用模型配置
- */
-const AVAILABLE_MODELS = [
- {
- id: 'kimi-k2',
- name: 'Kimi K2',
- description: '快速响应,适合日常对话',
- icon: '🚀',
- provider: 'Moonshot',
- },
- {
- id: 'kimi-k2-thinking',
- name: 'Kimi K2 Thinking',
- description: '深度思考,提供详细推理过程',
- icon: '🧠',
- provider: 'Moonshot',
- recommended: true,
- },
- {
- id: 'glm-4.6',
- name: 'GLM 4.6',
- description: '智谱AI最新模型,性能强大',
- icon: '⚡',
- provider: 'ZhipuAI',
- },
- {
- id: 'deepmoney',
- name: 'DeepMoney',
- description: '金融专业模型,擅长财经分析',
- icon: '💰',
- provider: 'Custom',
- },
- {
- id: 'gemini-3',
- name: 'Gemini 3',
- description: 'Google最新多模态模型',
- icon: '✨',
- provider: 'Google',
- },
-];
-
-/**
- * MCP工具分类配置
- */
-const MCP_TOOL_CATEGORIES = [
- {
- name: '新闻搜索',
- icon: '📰',
- tools: [
- { id: 'search_news', name: '全球新闻搜索', description: '搜索国际新闻、行业动态' },
- { id: 'search_china_news', name: '中国新闻搜索', description: 'KNN语义搜索中国新闻' },
- { id: 'search_medical_news', name: '医疗新闻搜索', description: '医药、医疗设备、生物技术' },
- ],
- },
- {
- name: '股票分析',
- icon: '📈',
- tools: [
- { id: 'search_limit_up_stocks', name: '涨停股票搜索', description: '搜索涨停股票及原因分析' },
- { id: 'get_stock_analysis', name: '个股分析', description: '获取股票深度分析报告' },
- { id: 'get_stock_concepts', name: '股票概念查询', description: '查询股票相关概念板块' },
- ],
- },
- {
- name: '概念板块',
- icon: '🏢',
- tools: [
- { id: 'search_concepts', name: '概念搜索', description: '搜索股票概念板块' },
- { id: 'get_concept_details', name: '概念详情', description: '获取概念板块详细信息' },
- { id: 'get_concept_statistics', name: '概念统计', description: '涨幅榜、活跃榜、连涨榜' },
- ],
- },
- {
- name: '公司信息',
- icon: '🏭',
- tools: [
- { id: 'search_roadshows', name: '路演搜索', description: '搜索上市公司路演活动' },
- { id: 'get_company_info', name: '公司信息', description: '获取公司基本面信息' },
- ],
- },
- {
- name: '数据分析',
- icon: '📊',
- tools: [
- { id: 'query_database', name: '数据库查询', description: 'SQL查询金融数据' },
- { id: 'get_market_overview', name: '市场概况', description: '获取市场整体行情' },
- ],
- },
-];
-
-/**
- * Agent聊天页面 V4 - 黑金毛玻璃设计
- */
-const AgentChatV4 = () => {
- const { user } = useAuth();
- const toast = useToast();
-
- // 确保组件总是返回有效的 React 元素
- if (!user) {
- return (
-
-
-
- 正在加载...
-
-
- );
- }
-
- // 会话相关状态
- const [sessions, setSessions] = useState([]);
- const [currentSessionId, setCurrentSessionId] = useState(null);
- const [isLoadingSessions, setIsLoadingSessions] = useState(true);
-
- // 消息相关状态
- const [messages, setMessages] = useState([]);
- const [inputValue, setInputValue] = useState('');
- const [isProcessing, setIsProcessing] = useState(false);
- const [currentProgress, setCurrentProgress] = useState(0);
-
- // 模型和工具配置状态
- const [selectedModel, setSelectedModel] = useState('kimi-k2-thinking');
- const [selectedTools, setSelectedTools] = useState(() => {
- // 默认全选所有工具
- const allToolIds = MCP_TOOL_CATEGORIES.flatMap(cat => cat.tools.map(t => t.id));
- return allToolIds;
- });
-
- // UI 状态
- const [searchQuery, setSearchQuery] = useState('');
-
- // 检测是否为移动设备(屏幕宽度小于 768px)
- const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
-
- // 根据设备类型设置侧边栏默认状态(移动端默认收起)
- const { isOpen: isSidebarOpen, onToggle: toggleSidebar } = useDisclosure({
- defaultIsOpen: !isMobile
- });
- const { isOpen: isRightPanelOpen, onToggle: toggleRightPanel } = useDisclosure({
- defaultIsOpen: !isMobile
- });
-
- // Refs
- const messagesEndRef = useRef(null);
- const inputRef = useRef(null);
-
- // 毛玻璃深灰金配色主题(类似编程工具的深色主题)
- const glassBg = 'rgba(30, 35, 40, 0.85)'; // 深灰色毛玻璃
- const glassHoverBg = 'rgba(40, 45, 50, 0.9)';
- const goldAccent = '#FFD700';
- const goldGradient = 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)';
- const darkBg = '#1a1d23'; // VS Code 风格的深灰背景
- const borderGold = 'rgba(255, 215, 0, 0.3)';
- const textGold = '#FFD700';
- const textWhite = '#E8E8E8'; // 柔和的白色
- const textGray = '#9BA1A6'; // 柔和的灰色
- const cardBg = 'rgba(40, 45, 50, 0.6)'; // 卡片背景(深灰毛玻璃)
-
- // ==================== 会话管理函数 ====================
-
- const loadSessions = async () => {
- if (!user?.id) return;
-
- setIsLoadingSessions(true);
- try {
- const response = await axios.get('/mcp/agent/sessions', {
- params: { user_id: String(user.id), limit: 50 },
- });
-
- if (response.data.success) {
- setSessions(response.data.data);
- logger.info('会话列表加载成功', response.data.data);
- }
- } catch (error) {
- logger.error('加载会话列表失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话列表',
- status: 'error',
- duration: 3000,
- });
- } finally {
- setIsLoadingSessions(false);
- }
- };
-
- const loadSessionHistory = async (sessionId) => {
- if (!sessionId) return;
-
- try {
- const response = await axios.get(`/mcp/agent/history/${sessionId}`, {
- params: { limit: 100 },
- });
-
- if (response.data.success) {
- const history = response.data.data;
- const formattedMessages = history.map((msg, idx) => ({
- id: `${sessionId}-${idx}`,
- type: msg.message_type === 'user' ? MessageTypes.USER : MessageTypes.AGENT_RESPONSE,
- content: msg.message,
- plan: msg.plan ? JSON.parse(msg.plan) : null,
- stepResults: msg.steps ? JSON.parse(msg.steps) : null,
- timestamp: msg.timestamp,
- }));
-
- setMessages(formattedMessages);
- logger.info('会话历史加载成功', formattedMessages);
- }
- } catch (error) {
- logger.error('加载会话历史失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话历史',
- status: 'error',
- duration: 3000,
- });
- }
- };
-
- const createNewSession = () => {
- setCurrentSessionId(null);
- setMessages([
- {
- id: Date.now(),
- type: MessageTypes.AGENT_RESPONSE,
- content: `你好${user?.nickname || ''}!我是价小前,北京价值前沿科技公司的AI投研助手。\n\n我会通过多步骤分析来帮助你深入了解金融市场。\n\n你可以问我:\n• 全面分析某只股票\n• 某个行业的投资机会\n• 今日市场热点\n• 某个概念板块的表现`,
- timestamp: new Date().toISOString(),
- },
- ]);
- };
-
- const switchSession = (sessionId) => {
- setCurrentSessionId(sessionId);
- loadSessionHistory(sessionId);
- };
-
- const deleteSession = async (sessionId) => {
- toast({
- title: '删除会话',
- description: '此功能尚未实现',
- status: 'info',
- duration: 2000,
- });
- };
-
- // ==================== 消息处理函数 ====================
-
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
-
- useEffect(() => {
- scrollToBottom();
- }, [messages]);
-
- // 监听窗口大小变化,动态更新移动端状态
- useEffect(() => {
- const handleResize = () => {
- const mobile = window.innerWidth < 768;
- setIsMobile(mobile);
- };
-
- window.addEventListener('resize', handleResize);
- return () => window.removeEventListener('resize', handleResize);
- }, []);
-
- // 在 AgentChat 页面隐藏 Bytedesk 客服插件(避免遮挡页面)
- useEffect(() => {
- // 隐藏 Bytedesk - 更安全的方式
- const hideBytedeskElements = () => {
- try {
- // 查找所有 Bytedesk 相关元素
- const bytedeskElements = document.querySelectorAll(
- '[class*="bytedesk"], [id*="bytedesk"], [class*="BytedeskWeb"], .bytedesk-widget'
- );
-
- // 保存原始 display 值
- const originalDisplays = new Map();
-
- bytedeskElements.forEach(el => {
- if (el && el.style) {
- originalDisplays.set(el, el.style.display);
- el.style.display = 'none';
- }
- });
-
- // 返回清理函数
- return () => {
- bytedeskElements.forEach(el => {
- if (el && el.style) {
- const originalDisplay = originalDisplays.get(el);
- if (originalDisplay !== undefined) {
- el.style.display = originalDisplay;
- } else {
- el.style.display = '';
- }
- }
- });
- };
- } catch (error) {
- console.warn('Failed to hide Bytedesk elements:', error);
- return () => {}; // 返回空清理函数
- }
- };
-
- const cleanup = hideBytedeskElements();
-
- // 组件卸载时恢复显示
- return cleanup;
- }, []);
-
- const addMessage = (message) => {
- setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
- };
-
- const handleSendMessage = async () => {
- if (!inputValue.trim() || isProcessing) return;
-
- const hasAccess = user?.subscription_type === 'max';
-
- if (!hasAccess) {
- logger.warn('AgentChat', '权限检查失败', {
- userId: user?.id,
- subscription_type: user?.subscription_type,
- });
-
- toast({
- title: '订阅升级',
- description: '「价小前投研」功能需要 Max 订阅。请前往设置页面升级您的订阅。',
- status: 'warning',
- duration: 5000,
- isClosable: true,
- });
- return;
- }
-
- const userMessage = {
- type: MessageTypes.USER,
- content: inputValue,
- timestamp: new Date().toISOString(),
- };
-
- addMessage(userMessage);
- const userInput = inputValue;
- setInputValue('');
- setIsProcessing(true);
- setCurrentProgress(0);
-
- let currentPlan = null;
- let stepResults = [];
- let executingMessageId = null;
-
- try {
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: '正在分析你的问题...',
- timestamp: new Date().toISOString(),
- });
-
- setCurrentProgress(10);
-
- const requestBody = {
- message: userInput,
- conversation_history: messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((m) => ({
- isUser: m.type === MessageTypes.USER,
- content: m.content,
- })),
- user_id: user?.id ? String(user.id) : 'anonymous',
- user_nickname: user?.nickname || user?.username || '匿名用户',
- user_avatar: user?.avatar || '',
- subscription_type: user?.subscription_type || 'free',
- session_id: currentSessionId,
- model: selectedModel, // 传递选中的模型
- tools: selectedTools, // 传递选中的工具
- };
-
- const response = await fetch('/mcp/agent/chat/stream', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(requestBody),
- });
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
- let buffer = '';
-
- let thinkingMessageId = null;
- let thinkingContent = '';
- let summaryMessageId = null;
- let summaryContent = '';
-
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- buffer = lines.pop();
-
- let currentEvent = null;
-
- for (const line of lines) {
- if (!line.trim() || line.startsWith(':')) continue;
-
- if (line.startsWith('event:')) {
- currentEvent = line.substring(6).trim();
- continue;
- }
-
- if (line.startsWith('data:')) {
- try {
- const data = JSON.parse(line.substring(5).trim());
-
- if (currentEvent === 'thinking') {
- if (!thinkingMessageId) {
- thinkingMessageId = Date.now();
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- id: thinkingMessageId,
- type: MessageTypes.AGENT_THINKING,
- content: '',
- timestamp: new Date().toISOString(),
- });
- }
- thinkingContent += data.content;
- setMessages((prev) =>
- prev.map((m) =>
- m.id === thinkingMessageId
- ? { ...m, content: thinkingContent }
- : m
- )
- );
- } else if (currentEvent === 'plan') {
- currentPlan = data;
- thinkingMessageId = null;
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_PLAN,
- content: '已制定执行计划',
- plan: data,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(30);
- } else if (currentEvent === 'step_complete') {
- const stepResult = {
- step_index: data.step_index,
- tool: data.tool,
- status: data.status,
- result: data.result,
- error: data.error,
- execution_time: data.execution_time,
- };
- stepResults.push(stepResult);
-
- setMessages((prev) =>
- prev.map((m) =>
- m.id === executingMessageId
- ? { ...m, stepResults: [...stepResults] }
- : m
- )
- );
-
- const progress = 40 + (stepResults.length / (currentPlan?.steps?.length || 5)) * 40;
- setCurrentProgress(Math.min(progress, 80));
- } else if (currentEvent === 'summary_chunk') {
- if (!summaryMessageId) {
- summaryMessageId = Date.now();
- summaryContent = '';
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- id: summaryMessageId,
- type: MessageTypes.AGENT_RESPONSE,
- content: '',
- plan: currentPlan,
- stepResults: stepResults,
- isStreaming: true,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(85);
- }
- summaryContent += data.content;
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? { ...m, content: summaryContent }
- : m
- )
- );
- } else if (currentEvent === 'summary') {
- if (summaryMessageId) {
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? {
- ...m,
- content: data.content || summaryContent,
- metadata: data.metadata,
- isStreaming: false,
- }
- : m
- )
- );
- } else {
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- type: MessageTypes.AGENT_RESPONSE,
- content: data.content,
- plan: currentPlan,
- stepResults: stepResults,
- metadata: data.metadata,
- isStreaming: false,
- timestamp: new Date().toISOString(),
- });
- }
- setCurrentProgress(100);
- } else if (currentEvent === 'status') {
- if (data.stage === 'planning') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(10);
- } else if (data.stage === 'executing') {
- const msgId = Date.now();
- executingMessageId = msgId;
- addMessage({
- id: msgId,
- type: MessageTypes.AGENT_EXECUTING,
- content: data.message,
- plan: currentPlan,
- stepResults: [],
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(40);
- } else if (data.stage === 'summarizing') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_EXECUTING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(80);
- }
- }
- } catch (e) {
- logger.error('解析 SSE 数据失败', e);
- }
- }
- }
- }
-
- loadSessions();
-
- } catch (error) {
- logger.error('Agent chat error', error);
-
- setMessages((prev) =>
- prev.filter(
- (m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING
- )
- );
-
- const errorMessage = error.response?.data?.detail || error.message || '处理失败';
-
- addMessage({
- type: MessageTypes.ERROR,
- content: `处理失败:${errorMessage}`,
- timestamp: new Date().toISOString(),
- });
-
- toast({
- title: '处理失败',
- description: errorMessage,
- status: 'error',
- duration: 5000,
- isClosable: true,
- });
- } finally {
- setIsProcessing(false);
- setCurrentProgress(0);
- inputRef.current?.focus();
- }
- };
-
- const handleKeyPress = (e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- handleSendMessage();
- }
- };
-
- const handleClearChat = () => {
- createNewSession();
- };
-
- const handleExportChat = () => {
- const chatText = messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((msg) => `[${msg.type === MessageTypes.USER ? '用户' : '价小前'}] ${msg.content}`)
- .join('\n\n');
-
- const blob = new Blob([chatText], { type: 'text/plain' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `chat_${new Date().toISOString().slice(0, 10)}.txt`;
- a.click();
- URL.revokeObjectURL(url);
- };
-
- // ==================== 工具选择处理 ====================
-
- const handleToolToggle = (toolId, isChecked) => {
- if (isChecked) {
- setSelectedTools((prev) => [...prev, toolId]);
- } else {
- setSelectedTools((prev) => prev.filter((id) => id !== toolId));
- }
- };
-
- const handleCategoryToggle = (categoryTools, isAllSelected) => {
- const toolIds = categoryTools.map((t) => t.id);
- if (isAllSelected) {
- // 全部取消选中
- setSelectedTools((prev) => prev.filter((id) => !toolIds.includes(id)));
- } else {
- // 全部选中
- setSelectedTools((prev) => {
- const newTools = [...prev];
- toolIds.forEach((id) => {
- if (!newTools.includes(id)) {
- newTools.push(id);
- }
- });
- return newTools;
- });
- }
- };
-
- // ==================== 初始化 ====================
-
- useEffect(() => {
- if (user) {
- loadSessions();
- createNewSession();
- }
- }, [user]);
-
- // ==================== 渲染 ====================
-
- const quickQuestions = [
- '全面分析贵州茅台这只股票',
- '今日涨停股票有哪些亮点',
- '新能源概念板块的投资机会',
- '半导体行业最新动态',
- ];
-
- const filteredSessions = sessions.filter(
- (session) =>
- !searchQuery ||
- session.last_message?.toLowerCase().includes(searchQuery.toLowerCase())
- );
-
- return (
- <>
- {/* 全局样式:确保页面正确显示 */}
-
-
- {/* 主内容区域 - 使用calc减去导航栏高度,避免内容被遮挡 */}
-
-
-
-
- {/* 左侧会话列表 */}
-
-
- {/* 侧边栏头部 */}
-
- }
- bg={goldGradient}
- color={darkBg}
- w="100%"
- onClick={createNewSession}
- size="sm"
- _hover={{
- transform: 'translateY(-2px)',
- boxShadow: '0 4px 20px rgba(255, 215, 0, 0.4)',
- }}
- transition="all 0.3s"
- fontWeight="bold"
- >
- 新建对话
-
-
-
-
-
-
- setSearchQuery(e.target.value)}
- bg="rgba(255, 255, 255, 0.05)"
- border="1px solid"
- borderColor={borderGold}
- color={textWhite}
- _placeholder={{ color: textGray }}
- _hover={{ borderColor: goldAccent }}
- _focus={{ borderColor: goldAccent, boxShadow: `0 0 0 1px ${goldAccent}` }}
- />
-
-
-
- {/* 会话列表 */}
-
- {isLoadingSessions ? (
-
-
-
- ) : filteredSessions.length === 0 ? (
-
-
-
- {searchQuery ? '没有找到匹配的对话' : '暂无对话记录'}
-
-
- ) : (
- filteredSessions.map((session) => (
- switchSession(session.session_id)}
- transition="all 0.2s"
- >
-
-
-
- {session.last_message || '新对话'}
-
-
-
-
- {new Date(session.last_timestamp).toLocaleDateString('zh-CN', {
- month: 'numeric',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- })}
-
-
- {session.message_count} 条
-
-
-
-
-
- }
- size="xs"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent }}
- onClick={(e) => e.stopPropagation()}
- />
-
- }
- color="red.400"
- bg="transparent"
- _hover={{ bg: 'rgba(255, 0, 0, 0.1)' }}
- onClick={(e) => {
- e.stopPropagation();
- deleteSession(session.session_id);
- }}
- >
- 删除对话
-
-
-
-
-
- ))
- )}
-
-
- {/* 用户信息 */}
-
-
-
-
-
- {user?.nickname || '未登录'}
-
-
- MAX 订阅
-
-
-
-
-
-
-
- {/* 主聊天区域 */}
-
- {/* 顶部操作栏 - 简化版 */}
-
- {/* 左侧 - 标题和模型显示 */}
-
- }
- size="sm"
- variant="ghost"
- color={goldAccent}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="历史对话"
- onClick={toggleSidebar}
- />
-
- 价小前 AI
-
-
- {AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name || '智能模型'}
-
-
-
- {/* 右侧 - 操作按钮 */}
-
- }
- size="sm"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent, bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="清空对话"
- onClick={handleClearChat}
- />
- }
- size="sm"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent, bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="导出对话"
- onClick={handleExportChat}
- />
- }
- size="sm"
- variant="ghost"
- color={goldAccent}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="设置"
- onClick={toggleRightPanel}
- />
-
-
-
- {/* 进度条 */}
- {isProcessing && (
- div': {
- background: goldGradient,
- },
- }}
- isAnimated
- />
- )}
-
- {/* 消息列表 */}
-
-
- {messages.map((message) => (
-
-
-
- ))}
-
-
-
-
- {/* 快捷问题 */}
- {messages.length <= 2 && !isProcessing && (
-
-
- 💡 试试这些问题:
-
-
- {quickQuestions.map((question, idx) => (
- {
- setInputValue(question);
- inputRef.current?.focus();
- }}
- >
- {question}
-
- ))}
-
-
- )}
-
- {/* 输入框 */}
-
-
- setInputValue(e.target.value)}
- onKeyPress={handleKeyPress}
- placeholder={isMobile ? "输入问题..." : "输入你的问题,我会进行深度分析..."}
- bg="rgba(255, 255, 255, 0.05)"
- border="1px solid"
- borderColor={borderGold}
- color={textWhite}
- _placeholder={{ color: textGray }}
- _focus={{ borderColor: goldAccent, boxShadow: `0 0 0 1px ${goldAccent}` }}
- mr={2}
- disabled={isProcessing}
- size={{ base: "md", md: "lg" }}
- />
-
- {isProcessing ? : (
- isMobile ? : 发送
- )}
-
-
-
-
-
- {/* 右侧配置面板 */}
-
-
-
- {/* 模型选择 */}
-
-
-
-
- 选择模型
-
-
-
- {AVAILABLE_MODELS.map((model) => (
- setSelectedModel(model.id)}
- transition="all 0.2s"
- _hover={{
- bg: 'rgba(255, 215, 0, 0.1)',
- borderColor: goldAccent,
- transform: 'translateX(4px)',
- }}
- position="relative"
- >
- {model.recommended && (
-
- 推荐
-
- )}
-
- {model.icon}
-
-
- {model.name}
-
-
- {model.description}
-
-
- {selectedModel === model.id && (
-
- )}
-
-
- ))}
-
-
-
-
-
- {/* 工具选择 */}
-
-
-
-
-
- MCP 工具
-
-
-
- {selectedTools.length} 个已选
-
-
-
-
- {MCP_TOOL_CATEGORIES.map((category, catIdx) => {
- const categoryToolIds = category.tools.map((t) => t.id);
- const selectedInCategory = categoryToolIds.filter((id) => selectedTools.includes(id));
- const isAllSelected = selectedInCategory.length === categoryToolIds.length;
- const isSomeSelected = selectedInCategory.length > 0 && !isAllSelected;
-
- return (
-
-
-
- {category.icon}
-
- {category.name}
-
-
- {selectedInCategory.length}/{category.tools.length}
-
-
-
-
-
-
- {/* 全选按钮 */}
- handleCategoryToggle(category.tools, isAllSelected)}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- >
- {isAllSelected ? '取消全选' : '全选'}
-
-
- {category.tools.map((tool) => (
- handleToolToggle(tool.id, e.target.checked)}
- colorScheme="yellow"
- size="sm"
- sx={{
- '.chakra-checkbox__control': {
- borderColor: borderGold,
- bg: 'rgba(255, 255, 255, 0.05)',
- _checked: {
- bg: goldGradient,
- borderColor: goldAccent,
- },
- },
- }}
- >
-
-
- {tool.name}
-
-
- {tool.description}
-
-
-
- ))}
-
-
-
- );
- })}
-
-
-
-
-
-
- >
- );
-};
-
-/**
- * 消息渲染器(深灰毛玻璃风格)
- */
-const MessageRenderer = ({ message, userAvatar }) => {
- const glassBg = 'rgba(30, 35, 40, 0.85)'; // 深灰色毛玻璃
- const cardBg = 'rgba(40, 45, 50, 0.6)'; // 卡片背景
- const goldAccent = '#FFD700';
- const goldGradient = 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)';
- const darkBg = '#1a1d23';
- const borderGold = 'rgba(255, 215, 0, 0.3)';
- const textWhite = '#E8E8E8'; // 柔和的白色
- const textGray = '#9BA1A6'; // 柔和的灰色
-
- switch (message.type) {
- case MessageTypes.USER:
- return (
-
-
-
-
- {message.content}
-
-
- }
- border="2px solid"
- borderColor={goldAccent}
- />
-
-
- );
-
- case MessageTypes.AGENT_THINKING:
- return (
-
-
-
-
-
-
-
-
-
- {message.content}
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_PLAN:
- return (
-
-
-
-
-
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_EXECUTING:
- return (
-
-
-
-
-
-
-
- {message.stepResults?.map((result, idx) => (
-
- ))}
-
-
-
- );
-
- case MessageTypes.AGENT_RESPONSE:
- return (
-
-
-
-
-
-
- {/* 最终总结 */}
-
- {message.isStreaming ? (
-
- {message.content}
-
- ) : (
-
- )}
-
- {message.metadata && (
-
- 总步骤: {message.metadata.total_steps}
- ✓ {message.metadata.successful_steps}
- {message.metadata.failed_steps > 0 && (
- ✗ {message.metadata.failed_steps}
- )}
- 耗时: {message.metadata.total_execution_time?.toFixed(1)}s
-
- )}
-
-
- {/* 执行详情(可选) */}
- {message.plan && message.stepResults && message.stepResults.length > 0 && (
-
-
-
- 📊 执行详情(点击展开查看)
-
- {message.stepResults.map((result, idx) => (
-
- ))}
-
- )}
-
-
-
- );
-
- case MessageTypes.ERROR:
- return (
-
-
-
-
-
-
- {message.content}
-
-
-
- );
-
- default:
- return null;
- }
-};
-
-export default AgentChatV4;
diff --git a/src/views/AgentChat/index_backup.js b/src/views/AgentChat/index_backup.js
deleted file mode 100644
index 5bb0ebd5..00000000
--- a/src/views/AgentChat/index_backup.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// src/views/AgentChat/index.js
-// Agent聊天页面
-
-import React from 'react';
-import {
- Box,
- Container,
- Heading,
- Text,
- VStack,
- useColorModeValue,
-} from '@chakra-ui/react';
-import { ChatInterfaceV2 } from '../../components/ChatBot';
-
-/**
- * Agent聊天页面
- * 提供基于MCP的AI助手对话功能
- */
-const AgentChat = () => {
- const bgColor = useColorModeValue('gray.50', 'gray.900');
- const cardBg = useColorModeValue('white', 'gray.800');
-
- return (
-
-
-
- {/* 页面标题 */}
-
- AI投资助手
-
- 基于MCP协议的智能投资顾问,支持股票查询、新闻搜索、概念分析等多种功能
-
-
-
- {/* 聊天界面 */}
-
-
-
-
-
-
- );
-};
-
-export default AgentChat;
diff --git a/src/views/AgentChat/index_v3.js b/src/views/AgentChat/index_v3.js
deleted file mode 100644
index 29d7097c..00000000
--- a/src/views/AgentChat/index_v3.js
+++ /dev/null
@@ -1,857 +0,0 @@
-// src/views/AgentChat/index_v3.js
-// Agent聊天页面 V3 - 带左侧会话列表和用户信息集成
-
-import React, { useState, useEffect, useRef } from 'react';
-import {
- Box,
- Flex,
- VStack,
- HStack,
- Text,
- Input,
- IconButton,
- Button,
- Avatar,
- Heading,
- Divider,
- Spinner,
- Badge,
- useColorModeValue,
- useToast,
- Progress,
- Fade,
- Collapse,
- useDisclosure,
- InputGroup,
- InputLeftElement,
- Menu,
- MenuButton,
- MenuList,
- MenuItem,
- Modal,
- ModalOverlay,
- ModalContent,
- ModalHeader,
- ModalBody,
- ModalCloseButton,
- Tooltip,
-} from '@chakra-ui/react';
-import {
- FiSend,
- FiSearch,
- FiPlus,
- FiMessageSquare,
- FiTrash2,
- FiMoreVertical,
- FiRefreshCw,
- FiDownload,
- FiCpu,
- FiUser,
- FiZap,
- FiClock,
-} from 'react-icons/fi';
-import { useAuth } from '@contexts/AuthContext';
-import { PlanCard } from '@components/ChatBot/PlanCard';
-import { StepResultCard } from '@components/ChatBot/StepResultCard';
-import { logger } from '@utils/logger';
-import axios from 'axios';
-
-/**
- * Agent消息类型
- */
-const MessageTypes = {
- USER: 'user',
- AGENT_THINKING: 'agent_thinking',
- AGENT_PLAN: 'agent_plan',
- AGENT_EXECUTING: 'agent_executing',
- AGENT_RESPONSE: 'agent_response',
- ERROR: 'error',
-};
-
-/**
- * Agent聊天页面 V3
- */
-const AgentChatV3 = () => {
- const { user } = useAuth(); // 获取当前用户信息
- const toast = useToast();
-
- // 会话相关状态
- const [sessions, setSessions] = useState([]);
- const [currentSessionId, setCurrentSessionId] = useState(null);
- const [isLoadingSessions, setIsLoadingSessions] = useState(true);
-
- // 消息相关状态
- const [messages, setMessages] = useState([]);
- const [inputValue, setInputValue] = useState('');
- const [isProcessing, setIsProcessing] = useState(false);
- const [currentProgress, setCurrentProgress] = useState(0);
-
- // UI 状态
- const [searchQuery, setSearchQuery] = useState('');
- const { isOpen: isSidebarOpen, onToggle: toggleSidebar } = useDisclosure({ defaultIsOpen: true });
-
- // Refs
- const messagesEndRef = useRef(null);
- const inputRef = useRef(null);
-
- // 颜色主题
- const bgColor = useColorModeValue('gray.50', 'gray.900');
- const sidebarBg = useColorModeValue('white', 'gray.800');
- const chatBg = useColorModeValue('white', 'gray.800');
- const inputBg = useColorModeValue('white', 'gray.700');
- const borderColor = useColorModeValue('gray.200', 'gray.600');
- const hoverBg = useColorModeValue('gray.100', 'gray.700');
- const activeBg = useColorModeValue('blue.50', 'blue.900');
- const userBubbleBg = useColorModeValue('blue.500', 'blue.600');
- const agentBubbleBg = useColorModeValue('white', 'gray.700');
-
- // ==================== 会话管理函数 ====================
-
- // 加载会话列表
- const loadSessions = async () => {
- if (!user?.id) return;
-
- setIsLoadingSessions(true);
- try {
- const response = await axios.get('/mcp/agent/sessions', {
- params: { user_id: user.id, limit: 50 },
- });
-
- if (response.data.success) {
- setSessions(response.data.data);
- logger.info('会话列表加载成功', response.data.data);
- }
- } catch (error) {
- logger.error('加载会话列表失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话列表',
- status: 'error',
- duration: 3000,
- });
- } finally {
- setIsLoadingSessions(false);
- }
- };
-
- // 加载会话历史
- const loadSessionHistory = async (sessionId) => {
- if (!sessionId) return;
-
- try {
- const response = await axios.get(`/mcp/agent/history/${sessionId}`, {
- params: { limit: 100 },
- });
-
- if (response.data.success) {
- const history = response.data.data;
-
- // 将历史记录转换为消息格式
- const formattedMessages = history.map((msg, idx) => ({
- id: `${sessionId}-${idx}`,
- type: msg.message_type === 'user' ? MessageTypes.USER : MessageTypes.AGENT_RESPONSE,
- content: msg.message,
- plan: msg.plan ? JSON.parse(msg.plan) : null,
- stepResults: msg.steps ? JSON.parse(msg.steps) : null,
- timestamp: msg.timestamp,
- }));
-
- setMessages(formattedMessages);
- logger.info('会话历史加载成功', formattedMessages);
- }
- } catch (error) {
- logger.error('加载会话历史失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话历史',
- status: 'error',
- duration: 3000,
- });
- }
- };
-
- // 创建新会话
- const createNewSession = () => {
- setCurrentSessionId(null);
- setMessages([
- {
- id: Date.now(),
- type: MessageTypes.AGENT_RESPONSE,
- content: `你好${user?.nickname || ''}!我是价小前,北京价值前沿科技公司的AI投研助手。\n\n我会通过多步骤分析来帮助你深入了解金融市场。\n\n你可以问我:\n• 全面分析某只股票\n• 某个行业的投资机会\n• 今日市场热点\n• 某个概念板块的表现`,
- timestamp: new Date().toISOString(),
- },
- ]);
- };
-
- // 切换会话
- const switchSession = (sessionId) => {
- setCurrentSessionId(sessionId);
- loadSessionHistory(sessionId);
- };
-
- // 删除会话(需要后端API支持)
- const deleteSession = async (sessionId) => {
- // TODO: 实现删除会话的后端API
- toast({
- title: '删除会话',
- description: '此功能尚未实现',
- status: 'info',
- duration: 2000,
- });
- };
-
- // ==================== 消息处理函数 ====================
-
- // 自动滚动到底部
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
-
- useEffect(() => {
- scrollToBottom();
- }, [messages]);
-
- // 添加消息
- const addMessage = (message) => {
- setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
- };
-
- // 发送消息
- const handleSendMessage = async () => {
- if (!inputValue.trim() || isProcessing) return;
-
- // 权限检查
- if (user?.id !== 'max') {
- toast({
- title: '权限不足',
- description: '「价小前投研」功能目前仅对特定用户开放。如需使用,请联系管理员。',
- status: 'warning',
- duration: 5000,
- isClosable: true,
- });
- return;
- }
-
- const userMessage = {
- type: MessageTypes.USER,
- content: inputValue,
- timestamp: new Date().toISOString(),
- };
-
- addMessage(userMessage);
- const userInput = inputValue;
- setInputValue('');
- setIsProcessing(true);
- setCurrentProgress(0);
-
- let currentPlan = null;
- let stepResults = [];
-
- try {
- // 1. 显示思考状态
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: '正在分析你的问题...',
- timestamp: new Date().toISOString(),
- });
-
- setCurrentProgress(10);
-
- // 2. 调用后端API(非流式)
- const response = await axios.post('/mcp/agent/chat', {
- message: userInput,
- conversation_history: messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((m) => ({
- isUser: m.type === MessageTypes.USER,
- content: m.content,
- })),
- user_id: user?.id || 'anonymous',
- user_nickname: user?.nickname || '匿名用户',
- user_avatar: user?.avatar || '',
- session_id: currentSessionId,
- });
-
- // 移除思考消息
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
-
- if (response.data.success) {
- const data = response.data;
-
- // 更新 session_id(如果是新会话)
- if (data.session_id && !currentSessionId) {
- setCurrentSessionId(data.session_id);
- }
-
- // 显示执行计划
- if (data.plan) {
- currentPlan = data.plan;
- addMessage({
- type: MessageTypes.AGENT_PLAN,
- content: '已制定执行计划',
- plan: data.plan,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(30);
- }
-
- // 显示执行步骤
- if (data.steps && data.steps.length > 0) {
- stepResults = data.steps;
- addMessage({
- type: MessageTypes.AGENT_EXECUTING,
- content: '正在执行步骤...',
- plan: currentPlan,
- stepResults: stepResults,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(70);
- }
-
- // 移除执行中消息
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_EXECUTING));
-
- // 显示最终结果
- addMessage({
- type: MessageTypes.AGENT_RESPONSE,
- content: data.final_answer || data.message || '处理完成',
- plan: currentPlan,
- stepResults: stepResults,
- metadata: data.metadata,
- timestamp: new Date().toISOString(),
- });
-
- setCurrentProgress(100);
-
- // 重新加载会话列表
- loadSessions();
- }
- } catch (error) {
- logger.error('Agent chat error', error);
-
- // 移除思考/执行中消息
- setMessages((prev) =>
- prev.filter(
- (m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING
- )
- );
-
- const errorMessage = error.response?.data?.error || error.message || '处理失败';
-
- addMessage({
- type: MessageTypes.ERROR,
- content: `处理失败:${errorMessage}`,
- timestamp: new Date().toISOString(),
- });
-
- toast({
- title: '处理失败',
- description: errorMessage,
- status: 'error',
- duration: 5000,
- isClosable: true,
- });
- } finally {
- setIsProcessing(false);
- setCurrentProgress(0);
- inputRef.current?.focus();
- }
- };
-
- // 处理键盘事件
- const handleKeyPress = (e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- handleSendMessage();
- }
- };
-
- // 清空对话
- const handleClearChat = () => {
- createNewSession();
- };
-
- // 导出对话
- const handleExportChat = () => {
- const chatText = messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((msg) => `[${msg.type === MessageTypes.USER ? '用户' : '价小前'}] ${msg.content}`)
- .join('\n\n');
-
- const blob = new Blob([chatText], { type: 'text/plain' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `chat_${new Date().toISOString().slice(0, 10)}.txt`;
- a.click();
- URL.revokeObjectURL(url);
- };
-
- // ==================== 初始化 ====================
-
- useEffect(() => {
- if (user) {
- loadSessions();
- createNewSession();
- }
- }, [user]);
-
- // ==================== 渲染 ====================
-
- // 快捷问题
- const quickQuestions = [
- '全面分析贵州茅台这只股票',
- '今日涨停股票有哪些亮点',
- '新能源概念板块的投资机会',
- '半导体行业最新动态',
- ];
-
- // 筛选会话
- const filteredSessions = sessions.filter(
- (session) =>
- !searchQuery ||
- session.last_message?.toLowerCase().includes(searchQuery.toLowerCase())
- );
-
- return (
-
- {/* 左侧会话列表 */}
-
-
- {/* 侧边栏头部 */}
-
- }
- colorScheme="blue"
- w="100%"
- onClick={createNewSession}
- size="sm"
- >
- 新建对话
-
-
- {/* 搜索框 */}
-
-
-
-
- setSearchQuery(e.target.value)}
- />
-
-
-
- {/* 会话列表 */}
-
- {isLoadingSessions ? (
-
-
-
- ) : filteredSessions.length === 0 ? (
-
-
-
- {searchQuery ? '没有找到匹配的对话' : '暂无对话记录'}
-
-
- ) : (
- filteredSessions.map((session) => (
- switchSession(session.session_id)}
- >
-
-
-
- {session.last_message || '新对话'}
-
-
-
-
- {new Date(session.last_timestamp).toLocaleDateString('zh-CN', {
- month: 'numeric',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- })}
-
-
- {session.message_count} 条
-
-
-
-
-
- }
- size="xs"
- variant="ghost"
- onClick={(e) => e.stopPropagation()}
- />
-
- }
- color="red.500"
- onClick={(e) => {
- e.stopPropagation();
- deleteSession(session.session_id);
- }}
- >
- 删除对话
-
-
-
-
-
- ))
- )}
-
-
- {/* 用户信息 */}
-
-
-
-
-
- {user?.nickname || '未登录'}
-
-
- {user?.id || 'anonymous'}
-
-
-
-
-
-
-
- {/* 主聊天区域 */}
-
- {/* 聊天头部 */}
-
-
-
- }
- size="sm"
- variant="ghost"
- aria-label="切换侧边栏"
- onClick={toggleSidebar}
- />
- } />
-
- 价小前投研
-
-
-
-
- 智能分析
-
-
-
- 多步骤深度研究
-
-
-
-
-
-
- }
- size="sm"
- variant="ghost"
- aria-label="清空对话"
- onClick={handleClearChat}
- />
- }
- size="sm"
- variant="ghost"
- aria-label="导出对话"
- onClick={handleExportChat}
- />
-
-
-
- {/* 进度条 */}
- {isProcessing && (
-
- )}
-
-
- {/* 消息列表 */}
-
-
- {messages.map((message) => (
-
-
-
- ))}
-
-
-
-
- {/* 快捷问题 */}
- {messages.length <= 2 && !isProcessing && (
-
-
- 💡 试试这些问题:
-
-
- {quickQuestions.map((question, idx) => (
- {
- setInputValue(question);
- inputRef.current?.focus();
- }}
- >
- {question}
-
- ))}
-
-
- )}
-
- {/* 输入框 */}
-
-
- setInputValue(e.target.value)}
- onKeyPress={handleKeyPress}
- placeholder="输入你的问题,我会进行深度分析..."
- bg={inputBg}
- border="1px"
- borderColor={borderColor}
- _focus={{ borderColor: 'blue.500', boxShadow: '0 0 0 1px #3182CE' }}
- mr={2}
- disabled={isProcessing}
- size="lg"
- />
- : }
- colorScheme="blue"
- aria-label="发送"
- onClick={handleSendMessage}
- isLoading={isProcessing}
- disabled={!inputValue.trim() || isProcessing}
- size="lg"
- />
-
-
-
-
- );
-};
-
-/**
- * 消息渲染器
- */
-const MessageRenderer = ({ message, userAvatar }) => {
- const userBubbleBg = useColorModeValue('blue.500', 'blue.600');
- const agentBubbleBg = useColorModeValue('white', 'gray.700');
- const borderColor = useColorModeValue('gray.200', 'gray.600');
-
- switch (message.type) {
- case MessageTypes.USER:
- return (
-
-
-
-
- {message.content}
-
-
- } />
-
-
- );
-
- case MessageTypes.AGENT_THINKING:
- return (
-
-
- } />
-
-
-
-
- {message.content}
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_PLAN:
- return (
-
-
- } />
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_EXECUTING:
- return (
-
-
- } />
-
-
- {message.stepResults?.map((result, idx) => (
-
- ))}
-
-
-
- );
-
- case MessageTypes.AGENT_RESPONSE:
- return (
-
-
- } />
-
- {/* 最终总结 */}
-
-
- {message.content}
-
-
- {/* 元数据 */}
- {message.metadata && (
-
- 总步骤: {message.metadata.total_steps}
- ✓ {message.metadata.successful_steps}
- {message.metadata.failed_steps > 0 && (
- ✗ {message.metadata.failed_steps}
- )}
- 耗时: {message.metadata.total_execution_time?.toFixed(1)}s
-
- )}
-
-
- {/* 执行详情(可选) */}
- {message.plan && message.stepResults && message.stepResults.length > 0 && (
-
-
-
- 📊 执行详情(点击展开查看)
-
- {message.stepResults.map((result, idx) => (
-
- ))}
-
- )}
-
-
-
- );
-
- case MessageTypes.ERROR:
- return (
-
-
- } />
-
- {message.content}
-
-
-
- );
-
- default:
- return null;
- }
-};
-
-export default AgentChatV3;
diff --git a/src/views/AgentChat/index_v3_backup.js b/src/views/AgentChat/index_v3_backup.js
deleted file mode 100644
index 40812bd7..00000000
--- a/src/views/AgentChat/index_v3_backup.js
+++ /dev/null
@@ -1,1039 +0,0 @@
-// src/views/AgentChat/index.js
-// Agent聊天页面 - 黑金毛玻璃设计,V4版本(带模型选择和工具选择)
-// 导出 V4 版本作为默认组件
-
-import React, { useState, useEffect, useRef } from 'react';
-import {
- Box,
- Flex,
- VStack,
- HStack,
- Text,
- Input,
- IconButton,
- Button,
- Avatar,
- Heading,
- Divider,
- Spinner,
- Badge,
- useColorModeValue,
- useToast,
- Progress,
- Fade,
- Collapse,
- useDisclosure,
- InputGroup,
- InputLeftElement,
- Menu,
- MenuButton,
- MenuList,
- MenuItem,
- Modal,
- ModalOverlay,
- ModalContent,
- ModalHeader,
- ModalBody,
- ModalCloseButton,
- Tooltip,
-} from '@chakra-ui/react';
-import {
- FiSend,
- FiSearch,
- FiPlus,
- FiMessageSquare,
- FiTrash2,
- FiMoreVertical,
- FiRefreshCw,
- FiDownload,
- FiCpu,
- FiUser,
- FiZap,
- FiClock,
-} from 'react-icons/fi';
-import { useAuth } from '@contexts/AuthContext';
-import { PlanCard } from '@components/ChatBot/PlanCard';
-import { StepResultCard } from '@components/ChatBot/StepResultCard';
-import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts';
-import { logger } from '@utils/logger';
-import axios from 'axios';
-
-/**
- * Agent消息类型
- */
-const MessageTypes = {
- USER: 'user',
- AGENT_THINKING: 'agent_thinking',
- AGENT_PLAN: 'agent_plan',
- AGENT_EXECUTING: 'agent_executing',
- AGENT_RESPONSE: 'agent_response',
- ERROR: 'error',
-};
-
-/**
- * Agent聊天页面 V3
- */
-const AgentChatV3 = () => {
- const { user } = useAuth(); // 获取当前用户信息
- const toast = useToast();
-
- // 会话相关状态
- const [sessions, setSessions] = useState([]);
- const [currentSessionId, setCurrentSessionId] = useState(null);
- const [isLoadingSessions, setIsLoadingSessions] = useState(true);
-
- // 消息相关状态
- const [messages, setMessages] = useState([]);
- const [inputValue, setInputValue] = useState('');
- const [isProcessing, setIsProcessing] = useState(false);
- const [currentProgress, setCurrentProgress] = useState(0);
-
- // UI 状态
- const [searchQuery, setSearchQuery] = useState('');
- const { isOpen: isSidebarOpen, onToggle: toggleSidebar } = useDisclosure({ defaultIsOpen: true });
-
- // Refs
- const messagesEndRef = useRef(null);
- const inputRef = useRef(null);
-
- // 颜色主题
- const bgColor = useColorModeValue('gray.50', 'gray.900');
- const sidebarBg = useColorModeValue('white', 'gray.800');
- const chatBg = useColorModeValue('white', 'gray.800');
- const inputBg = useColorModeValue('white', 'gray.700');
- const borderColor = useColorModeValue('gray.200', 'gray.600');
- const hoverBg = useColorModeValue('gray.100', 'gray.700');
- const activeBg = useColorModeValue('blue.50', 'blue.900');
- const userBubbleBg = useColorModeValue('blue.500', 'blue.600');
- const agentBubbleBg = useColorModeValue('white', 'gray.700');
-
- // ==================== 会话管理函数 ====================
-
- // 加载会话列表
- const loadSessions = async () => {
- if (!user?.id) return;
-
- setIsLoadingSessions(true);
- try {
- const response = await axios.get('/mcp/agent/sessions', {
- params: { user_id: String(user.id), limit: 50 },
- });
-
- if (response.data.success) {
- setSessions(response.data.data);
- logger.info('会话列表加载成功', response.data.data);
- }
- } catch (error) {
- logger.error('加载会话列表失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话列表',
- status: 'error',
- duration: 3000,
- });
- } finally {
- setIsLoadingSessions(false);
- }
- };
-
- // 加载会话历史
- const loadSessionHistory = async (sessionId) => {
- if (!sessionId) return;
-
- try {
- const response = await axios.get(`/mcp/agent/history/${sessionId}`, {
- params: { limit: 100 },
- });
-
- if (response.data.success) {
- const history = response.data.data;
-
- // 将历史记录转换为消息格式
- const formattedMessages = history.map((msg, idx) => ({
- id: `${sessionId}-${idx}`,
- type: msg.message_type === 'user' ? MessageTypes.USER : MessageTypes.AGENT_RESPONSE,
- content: msg.message,
- plan: msg.plan ? JSON.parse(msg.plan) : null,
- stepResults: msg.steps ? JSON.parse(msg.steps) : null,
- timestamp: msg.timestamp,
- }));
-
- setMessages(formattedMessages);
- logger.info('会话历史加载成功', formattedMessages);
- }
- } catch (error) {
- logger.error('加载会话历史失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话历史',
- status: 'error',
- duration: 3000,
- });
- }
- };
-
- // 创建新会话
- const createNewSession = () => {
- setCurrentSessionId(null);
- setMessages([
- {
- id: Date.now(),
- type: MessageTypes.AGENT_RESPONSE,
- content: `你好${user?.nickname || ''}!我是价小前,北京价值前沿科技公司的AI投研助手。\n\n我会通过多步骤分析来帮助你深入了解金融市场。\n\n你可以问我:\n• 全面分析某只股票\n• 某个行业的投资机会\n• 今日市场热点\n• 某个概念板块的表现`,
- timestamp: new Date().toISOString(),
- },
- ]);
- };
-
- // 切换会话
- const switchSession = (sessionId) => {
- setCurrentSessionId(sessionId);
- loadSessionHistory(sessionId);
- };
-
- // 删除会话(需要后端API支持)
- const deleteSession = async (sessionId) => {
- // TODO: 实现删除会话的后端API
- toast({
- title: '删除会话',
- description: '此功能尚未实现',
- status: 'info',
- duration: 2000,
- });
- };
-
- // ==================== 消息处理函数 ====================
-
- // 自动滚动到底部
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
-
- useEffect(() => {
- scrollToBottom();
- }, [messages]);
-
- // 添加消息
- const addMessage = (message) => {
- setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
- };
-
- // 发送消息(流式 SSE 版本)
- const handleSendMessage = async () => {
- if (!inputValue.trim() || isProcessing) return;
-
- // 权限检查 - 只允许 max 用户访问(与传导链分析权限保持一致)
- const hasAccess = user?.subscription_type === 'max';
-
- if (!hasAccess) {
- logger.warn('AgentChat', '权限检查失败', {
- userId: user?.id,
- username: user?.username,
- subscription_type: user?.subscription_type,
- userObject: user
- });
-
- toast({
- title: '订阅升级',
- description: '「价小前投研」功能需要 Max 订阅。请前往设置页面升级您的订阅。',
- status: 'warning',
- duration: 5000,
- isClosable: true,
- });
- return;
- }
-
- logger.info('AgentChat', '权限检查通过', {
- userId: user?.id,
- username: user?.username,
- subscription_type: user?.subscription_type
- });
-
- const userMessage = {
- type: MessageTypes.USER,
- content: inputValue,
- timestamp: new Date().toISOString(),
- };
-
- addMessage(userMessage);
- const userInput = inputValue;
- setInputValue('');
- setIsProcessing(true);
- setCurrentProgress(0);
-
- let currentPlan = null;
- let stepResults = [];
- let executingMessageId = null;
-
- try {
- // 1. 显示思考状态
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: '正在分析你的问题...',
- timestamp: new Date().toISOString(),
- });
-
- setCurrentProgress(10);
-
- // 2. 使用 EventSource 接收 SSE 流式数据
- const requestBody = {
- message: userInput,
- conversation_history: messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((m) => ({
- isUser: m.type === MessageTypes.USER,
- content: m.content,
- })),
- user_id: user?.id ? String(user.id) : 'anonymous',
- user_nickname: user?.nickname || user?.username || '匿名用户',
- user_avatar: user?.avatar || '',
- subscription_type: user?.subscription_type || 'free',
- session_id: currentSessionId,
- };
-
- // 使用 fetch API 进行 SSE 请求
- const response = await fetch('/mcp/agent/chat/stream', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(requestBody),
- });
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
- let buffer = '';
-
- // 流式状态变量
- let thinkingMessageId = null;
- let thinkingContent = '';
- let summaryMessageId = null;
- let summaryContent = '';
-
- // 读取流式数据
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- buffer = lines.pop(); // 保留不完整的行
-
- let currentEvent = null;
-
- for (const line of lines) {
- if (!line.trim() || line.startsWith(':')) continue;
-
- if (line.startsWith('event:')) {
- // 提取事件类型
- currentEvent = line.substring(6).trim();
- continue;
- }
-
- if (line.startsWith('data:')) {
- try {
- const data = JSON.parse(line.substring(5).trim());
-
- // 根据事件类型处理数据
- if (currentEvent === 'thinking') {
- // Kimi 流式思考过程
- if (!thinkingMessageId) {
- thinkingMessageId = Date.now();
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- id: thinkingMessageId,
- type: MessageTypes.AGENT_THINKING,
- content: '',
- timestamp: new Date().toISOString(),
- });
- }
- thinkingContent += data.content;
- // 实时更新思考内容
- setMessages((prev) =>
- prev.map((m) =>
- m.id === thinkingMessageId
- ? { ...m, content: thinkingContent }
- : m
- )
- );
- } else if (currentEvent === 'reasoning') {
- // Kimi 推理过程(可选显示)
- logger.info('Kimi reasoning:', data.content);
- } else if (currentEvent === 'plan') {
- // 收到执行计划
- currentPlan = data;
- thinkingMessageId = null;
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_PLAN,
- content: '已制定执行计划',
- plan: data,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(30);
- } else if (currentEvent === 'step_complete') {
- // 收到步骤完成事件
- const stepResult = {
- step_index: data.step_index,
- tool: data.tool,
- status: data.status,
- result: data.result,
- error: data.error,
- execution_time: data.execution_time,
- };
- stepResults.push(stepResult);
-
- // 更新执行中的消息
- setMessages((prev) =>
- prev.map((m) =>
- m.id === executingMessageId
- ? { ...m, stepResults: [...stepResults] }
- : m
- )
- );
-
- // 更新进度
- const progress = 40 + (stepResults.length / (currentPlan?.steps?.length || 5)) * 40;
- setCurrentProgress(Math.min(progress, 80));
- } else if (currentEvent === 'summary_chunk') {
- // 流式总结内容
- if (!summaryMessageId) {
- summaryMessageId = Date.now();
- summaryContent = '';
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- id: summaryMessageId,
- type: MessageTypes.AGENT_RESPONSE,
- content: '',
- plan: currentPlan,
- stepResults: stepResults,
- isStreaming: true, // 标记为流式输出中
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(85);
- }
- summaryContent += data.content;
- // 实时更新总结内容
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? { ...m, content: summaryContent }
- : m
- )
- );
- } else if (currentEvent === 'summary') {
- // 收到完整总结(包含元数据)
- if (summaryMessageId) {
- // 更新已有消息的元数据和内容,并标记流式输出完成
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? {
- ...m,
- content: data.content || summaryContent, // ✅ 使用后端返回的完整内容,如果没有则使用累积内容
- metadata: data.metadata,
- isStreaming: false, // ✅ 标记流式输出完成
- }
- : m
- )
- );
- } else {
- // 如果没有流式片段,直接显示完整总结
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- type: MessageTypes.AGENT_RESPONSE,
- content: data.content,
- plan: currentPlan,
- stepResults: stepResults,
- metadata: data.metadata,
- isStreaming: false, // 非流式,直接标记完成
- timestamp: new Date().toISOString(),
- });
- }
- setCurrentProgress(100);
- } else if (currentEvent === 'status') {
- // 状态更新
- if (data.stage === 'planning') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(10);
- } else if (data.stage === 'executing') {
- const msgId = Date.now();
- executingMessageId = msgId;
- addMessage({
- id: msgId,
- type: MessageTypes.AGENT_EXECUTING,
- content: data.message,
- plan: currentPlan,
- stepResults: [],
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(40);
- } else if (data.stage === 'summarizing') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_EXECUTING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(80);
- }
- }
- } catch (e) {
- logger.error('解析 SSE 数据失败', e);
- }
- }
- }
- }
-
- // 重新加载会话列表
- loadSessions();
-
- } catch (error) {
- logger.error('Agent chat error', error);
-
- // 移除思考/执行中消息
- setMessages((prev) =>
- prev.filter(
- (m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING
- )
- );
-
- const errorMessage = error.response?.data?.detail || error.message || '处理失败';
-
- addMessage({
- type: MessageTypes.ERROR,
- content: `处理失败:${errorMessage}`,
- timestamp: new Date().toISOString(),
- });
-
- toast({
- title: '处理失败',
- description: errorMessage,
- status: 'error',
- duration: 5000,
- isClosable: true,
- });
- } finally {
- setIsProcessing(false);
- setCurrentProgress(0);
- inputRef.current?.focus();
- }
- };
-
- // 处理键盘事件
- const handleKeyPress = (e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- handleSendMessage();
- }
- };
-
- // 清空对话
- const handleClearChat = () => {
- createNewSession();
- };
-
- // 导出对话
- const handleExportChat = () => {
- const chatText = messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((msg) => `[${msg.type === MessageTypes.USER ? '用户' : '价小前'}] ${msg.content}`)
- .join('\n\n');
-
- const blob = new Blob([chatText], { type: 'text/plain' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `chat_${new Date().toISOString().slice(0, 10)}.txt`;
- a.click();
- URL.revokeObjectURL(url);
- };
-
- // ==================== 初始化 ====================
-
- useEffect(() => {
- if (user) {
- loadSessions();
- createNewSession();
- }
- }, [user]);
-
- // ==================== 渲染 ====================
-
- // 快捷问题
- const quickQuestions = [
- '全面分析贵州茅台这只股票',
- '今日涨停股票有哪些亮点',
- '新能源概念板块的投资机会',
- '半导体行业最新动态',
- ];
-
- // 筛选会话
- const filteredSessions = sessions.filter(
- (session) =>
- !searchQuery ||
- session.last_message?.toLowerCase().includes(searchQuery.toLowerCase())
- );
-
- return (
-
- {/* 左侧会话列表 */}
-
-
- {/* 侧边栏头部 */}
-
- }
- colorScheme="blue"
- w="100%"
- onClick={createNewSession}
- size="sm"
- >
- 新建对话
-
-
- {/* 搜索框 */}
-
-
-
-
- setSearchQuery(e.target.value)}
- />
-
-
-
- {/* 会话列表 */}
-
- {isLoadingSessions ? (
-
-
-
- ) : filteredSessions.length === 0 ? (
-
-
-
- {searchQuery ? '没有找到匹配的对话' : '暂无对话记录'}
-
-
- ) : (
- filteredSessions.map((session) => (
- switchSession(session.session_id)}
- >
-
-
-
- {session.last_message || '新对话'}
-
-
-
-
- {new Date(session.last_timestamp).toLocaleDateString('zh-CN', {
- month: 'numeric',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- })}
-
-
- {session.message_count} 条
-
-
-
-
-
- }
- size="xs"
- variant="ghost"
- onClick={(e) => e.stopPropagation()}
- />
-
- }
- color="red.500"
- onClick={(e) => {
- e.stopPropagation();
- deleteSession(session.session_id);
- }}
- >
- 删除对话
-
-
-
-
-
- ))
- )}
-
-
- {/* 用户信息 */}
-
-
-
-
-
- {user?.nickname || '未登录'}
-
-
- {user?.id || 'anonymous'}
-
-
-
-
-
-
-
- {/* 主聊天区域 */}
-
- {/* 聊天头部 */}
-
-
-
- }
- size="sm"
- variant="ghost"
- aria-label="切换侧边栏"
- onClick={toggleSidebar}
- />
- } />
-
- 价小前投研
-
-
-
-
- 智能分析
-
-
-
- 多步骤深度研究
-
-
-
-
-
-
- }
- size="sm"
- variant="ghost"
- aria-label="清空对话"
- onClick={handleClearChat}
- />
- }
- size="sm"
- variant="ghost"
- aria-label="导出对话"
- onClick={handleExportChat}
- />
-
-
-
- {/* 进度条 */}
- {isProcessing && (
-
- )}
-
-
- {/* 消息列表 */}
-
-
- {messages.map((message) => (
-
-
-
- ))}
-
-
-
-
- {/* 快捷问题 */}
- {messages.length <= 2 && !isProcessing && (
-
-
- 💡 试试这些问题:
-
-
- {quickQuestions.map((question, idx) => (
- {
- setInputValue(question);
- inputRef.current?.focus();
- }}
- >
- {question}
-
- ))}
-
-
- )}
-
- {/* 输入框 */}
-
-
- setInputValue(e.target.value)}
- onKeyPress={handleKeyPress}
- placeholder="输入你的问题,我会进行深度分析..."
- bg={inputBg}
- border="1px"
- borderColor={borderColor}
- _focus={{ borderColor: 'blue.500', boxShadow: '0 0 0 1px #3182CE' }}
- mr={2}
- disabled={isProcessing}
- size="lg"
- />
- : }
- colorScheme="blue"
- aria-label="发送"
- onClick={handleSendMessage}
- isLoading={isProcessing}
- disabled={!inputValue.trim() || isProcessing}
- size="lg"
- />
-
-
-
-
- );
-};
-
-/**
- * 消息渲染器
- */
-const MessageRenderer = ({ message, userAvatar }) => {
- const userBubbleBg = useColorModeValue('blue.500', 'blue.600');
- const agentBubbleBg = useColorModeValue('white', 'gray.700');
- const borderColor = useColorModeValue('gray.200', 'gray.600');
-
- switch (message.type) {
- case MessageTypes.USER:
- return (
-
-
-
-
- {message.content}
-
-
- } />
-
-
- );
-
- case MessageTypes.AGENT_THINKING:
- return (
-
-
- } />
-
-
-
-
- {message.content}
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_PLAN:
- return (
-
-
- } />
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_EXECUTING:
- return (
-
-
- } />
-
-
- {message.stepResults?.map((result, idx) => (
-
- ))}
-
-
-
- );
-
- case MessageTypes.AGENT_RESPONSE:
- return (
-
-
- } />
-
- {/* 最终总结(支持 Markdown + ECharts) */}
-
- {/* 流式输出中显示纯文本,完成后才渲染 Markdown + 图表 */}
- {message.isStreaming ? (
-
- {message.content}
-
- ) : (
-
- )}
-
- {/* 元数据 */}
- {message.metadata && (
-
- 总步骤: {message.metadata.total_steps}
- ✓ {message.metadata.successful_steps}
- {message.metadata.failed_steps > 0 && (
- ✗ {message.metadata.failed_steps}
- )}
- 耗时: {message.metadata.total_execution_time?.toFixed(1)}s
-
- )}
-
-
- {/* 执行详情(可选) */}
- {message.plan && message.stepResults && message.stepResults.length > 0 && (
-
-
-
- 📊 执行详情(点击展开查看)
-
- {message.stepResults.map((result, idx) => (
-
- ))}
-
- )}
-
-
-
- );
-
- case MessageTypes.ERROR:
- return (
-
-
- } />
-
- {message.content}
-
-
-
- );
-
- default:
- return null;
- }
-};
-
-export default AgentChatV3;
diff --git a/src/views/AgentChat/index_v4.js b/src/views/AgentChat/index_v4.js
deleted file mode 100644
index d2ff7e2d..00000000
--- a/src/views/AgentChat/index_v4.js
+++ /dev/null
@@ -1,1519 +0,0 @@
-// src/views/AgentChat/index_v4.js
-// Agent聊天页面 V4 - 黑金毛玻璃设计,带模型选择和工具选择
-
-import React, { useState, useEffect, useRef } from 'react';
-import {
- Box,
- Flex,
- VStack,
- HStack,
- Text,
- Input,
- IconButton,
- Button,
- Avatar,
- Heading,
- Divider,
- Spinner,
- Badge,
- useToast,
- Progress,
- Fade,
- Collapse,
- InputGroup,
- InputLeftElement,
- Menu,
- MenuButton,
- MenuList,
- MenuItem,
- Tooltip,
- Select,
- Checkbox,
- CheckboxGroup,
- Stack,
- Accordion,
- AccordionItem,
- AccordionButton,
- AccordionPanel,
- AccordionIcon,
- useDisclosure,
-} from '@chakra-ui/react';
-import {
- FiSend,
- FiSearch,
- FiPlus,
- FiMessageSquare,
- FiTrash2,
- FiMoreVertical,
- FiRefreshCw,
- FiDownload,
- FiCpu,
- FiUser,
- FiZap,
- FiClock,
- FiSettings,
- FiCheckCircle,
- FiChevronRight,
- FiTool,
-} from 'react-icons/fi';
-import { useAuth } from '@contexts/AuthContext';
-import { PlanCard } from '@components/ChatBot/PlanCard';
-import { StepResultCard } from '@components/ChatBot/StepResultCard';
-import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts';
-import { logger } from '@utils/logger';
-import axios from 'axios';
-
-/**
- * Agent消息类型
- */
-const MessageTypes = {
- USER: 'user',
- AGENT_THINKING: 'agent_thinking',
- AGENT_PLAN: 'agent_plan',
- AGENT_EXECUTING: 'agent_executing',
- AGENT_RESPONSE: 'agent_response',
- ERROR: 'error',
-};
-
-/**
- * 可用模型配置
- */
-const AVAILABLE_MODELS = [
- {
- id: 'kimi-k2',
- name: 'Kimi K2',
- description: '快速响应,适合日常对话',
- icon: '🚀',
- provider: 'Moonshot',
- },
- {
- id: 'kimi-k2-thinking',
- name: 'Kimi K2 Thinking',
- description: '深度思考,提供详细推理过程',
- icon: '🧠',
- provider: 'Moonshot',
- recommended: true,
- },
- {
- id: 'glm-4.6',
- name: 'GLM 4.6',
- description: '智谱AI最新模型,性能强大',
- icon: '⚡',
- provider: 'ZhipuAI',
- },
- {
- id: 'deepmoney',
- name: 'DeepMoney',
- description: '金融专业模型,擅长财经分析',
- icon: '💰',
- provider: 'Custom',
- },
- {
- id: 'gemini-3',
- name: 'Gemini 3',
- description: 'Google最新多模态模型',
- icon: '✨',
- provider: 'Google',
- },
-];
-
-/**
- * MCP工具分类配置
- */
-const MCP_TOOL_CATEGORIES = [
- {
- name: '新闻搜索',
- icon: '📰',
- tools: [
- { id: 'search_news', name: '全球新闻搜索', description: '搜索国际新闻、行业动态' },
- { id: 'search_china_news', name: '中国新闻搜索', description: 'KNN语义搜索中国新闻' },
- { id: 'search_medical_news', name: '医疗新闻搜索', description: '医药、医疗设备、生物技术' },
- ],
- },
- {
- name: '股票分析',
- icon: '📈',
- tools: [
- { id: 'search_limit_up_stocks', name: '涨停股票搜索', description: '搜索涨停股票及原因分析' },
- { id: 'get_stock_analysis', name: '个股分析', description: '获取股票深度分析报告' },
- { id: 'get_stock_concepts', name: '股票概念查询', description: '查询股票相关概念板块' },
- ],
- },
- {
- name: '概念板块',
- icon: '🏢',
- tools: [
- { id: 'search_concepts', name: '概念搜索', description: '搜索股票概念板块' },
- { id: 'get_concept_details', name: '概念详情', description: '获取概念板块详细信息' },
- { id: 'get_concept_statistics', name: '概念统计', description: '涨幅榜、活跃榜、连涨榜' },
- ],
- },
- {
- name: '公司信息',
- icon: '🏭',
- tools: [
- { id: 'search_roadshows', name: '路演搜索', description: '搜索上市公司路演活动' },
- { id: 'get_company_info', name: '公司信息', description: '获取公司基本面信息' },
- ],
- },
- {
- name: '数据分析',
- icon: '📊',
- tools: [
- { id: 'query_database', name: '数据库查询', description: 'SQL查询金融数据' },
- { id: 'get_market_overview', name: '市场概况', description: '获取市场整体行情' },
- ],
- },
-];
-
-/**
- * Agent聊天页面 V4 - 黑金毛玻璃设计
- */
-const AgentChatV4 = () => {
- const { user } = useAuth();
- const toast = useToast();
-
- // 会话相关状态
- const [sessions, setSessions] = useState([]);
- const [currentSessionId, setCurrentSessionId] = useState(null);
- const [isLoadingSessions, setIsLoadingSessions] = useState(true);
-
- // 消息相关状态
- const [messages, setMessages] = useState([]);
- const [inputValue, setInputValue] = useState('');
- const [isProcessing, setIsProcessing] = useState(false);
- const [currentProgress, setCurrentProgress] = useState(0);
-
- // 模型和工具配置状态
- const [selectedModel, setSelectedModel] = useState('kimi-k2-thinking');
- const [selectedTools, setSelectedTools] = useState(() => {
- // 默认全选所有工具
- const allToolIds = MCP_TOOL_CATEGORIES.flatMap(cat => cat.tools.map(t => t.id));
- return allToolIds;
- });
-
- // UI 状态
- const [searchQuery, setSearchQuery] = useState('');
- const { isOpen: isSidebarOpen, onToggle: toggleSidebar } = useDisclosure({ defaultIsOpen: true });
- const { isOpen: isRightPanelOpen, onToggle: toggleRightPanel } = useDisclosure({ defaultIsOpen: true });
-
- // Refs
- const messagesEndRef = useRef(null);
- const inputRef = useRef(null);
-
- // 毛玻璃黑金配色主题
- const glassBg = 'rgba(20, 20, 20, 0.7)';
- const glassHoverBg = 'rgba(30, 30, 30, 0.8)';
- const goldAccent = '#FFD700';
- const goldGradient = 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)';
- const darkBg = '#0A0A0A';
- const borderGold = 'rgba(255, 215, 0, 0.3)';
- const textGold = '#FFD700';
- const textWhite = '#FFFFFF';
- const textGray = '#CCCCCC';
-
- // ==================== 会话管理函数 ====================
-
- const loadSessions = async () => {
- if (!user?.id) return;
-
- setIsLoadingSessions(true);
- try {
- const response = await axios.get('/mcp/agent/sessions', {
- params: { user_id: String(user.id), limit: 50 },
- });
-
- if (response.data.success) {
- setSessions(response.data.data);
- logger.info('会话列表加载成功', response.data.data);
- }
- } catch (error) {
- logger.error('加载会话列表失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话列表',
- status: 'error',
- duration: 3000,
- });
- } finally {
- setIsLoadingSessions(false);
- }
- };
-
- const loadSessionHistory = async (sessionId) => {
- if (!sessionId) return;
-
- try {
- const response = await axios.get(`/mcp/agent/history/${sessionId}`, {
- params: { limit: 100 },
- });
-
- if (response.data.success) {
- const history = response.data.data;
- const formattedMessages = history.map((msg, idx) => ({
- id: `${sessionId}-${idx}`,
- type: msg.message_type === 'user' ? MessageTypes.USER : MessageTypes.AGENT_RESPONSE,
- content: msg.message,
- plan: msg.plan ? JSON.parse(msg.plan) : null,
- stepResults: msg.steps ? JSON.parse(msg.steps) : null,
- timestamp: msg.timestamp,
- }));
-
- setMessages(formattedMessages);
- logger.info('会话历史加载成功', formattedMessages);
- }
- } catch (error) {
- logger.error('加载会话历史失败', error);
- toast({
- title: '加载失败',
- description: '无法加载会话历史',
- status: 'error',
- duration: 3000,
- });
- }
- };
-
- const createNewSession = () => {
- setCurrentSessionId(null);
- setMessages([
- {
- id: Date.now(),
- type: MessageTypes.AGENT_RESPONSE,
- content: `你好${user?.nickname || ''}!我是价小前,北京价值前沿科技公司的AI投研助手。\n\n我会通过多步骤分析来帮助你深入了解金融市场。\n\n你可以问我:\n• 全面分析某只股票\n• 某个行业的投资机会\n• 今日市场热点\n• 某个概念板块的表现`,
- timestamp: new Date().toISOString(),
- },
- ]);
- };
-
- const switchSession = (sessionId) => {
- setCurrentSessionId(sessionId);
- loadSessionHistory(sessionId);
- };
-
- const deleteSession = async (sessionId) => {
- toast({
- title: '删除会话',
- description: '此功能尚未实现',
- status: 'info',
- duration: 2000,
- });
- };
-
- // ==================== 消息处理函数 ====================
-
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
-
- useEffect(() => {
- scrollToBottom();
- }, [messages]);
-
- const addMessage = (message) => {
- setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
- };
-
- const handleSendMessage = async () => {
- if (!inputValue.trim() || isProcessing) return;
-
- const hasAccess = user?.subscription_type === 'max';
-
- if (!hasAccess) {
- logger.warn('AgentChat', '权限检查失败', {
- userId: user?.id,
- subscription_type: user?.subscription_type,
- });
-
- toast({
- title: '订阅升级',
- description: '「价小前投研」功能需要 Max 订阅。请前往设置页面升级您的订阅。',
- status: 'warning',
- duration: 5000,
- isClosable: true,
- });
- return;
- }
-
- const userMessage = {
- type: MessageTypes.USER,
- content: inputValue,
- timestamp: new Date().toISOString(),
- };
-
- addMessage(userMessage);
- const userInput = inputValue;
- setInputValue('');
- setIsProcessing(true);
- setCurrentProgress(0);
-
- let currentPlan = null;
- let stepResults = [];
- let executingMessageId = null;
-
- try {
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: '正在分析你的问题...',
- timestamp: new Date().toISOString(),
- });
-
- setCurrentProgress(10);
-
- const requestBody = {
- message: userInput,
- conversation_history: messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((m) => ({
- isUser: m.type === MessageTypes.USER,
- content: m.content,
- })),
- user_id: user?.id ? String(user.id) : 'anonymous',
- user_nickname: user?.nickname || user?.username || '匿名用户',
- user_avatar: user?.avatar || '',
- subscription_type: user?.subscription_type || 'free',
- session_id: currentSessionId,
- model: selectedModel, // 传递选中的模型
- tools: selectedTools, // 传递选中的工具
- };
-
- const response = await fetch('/mcp/agent/chat/stream', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(requestBody),
- });
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
- let buffer = '';
-
- let thinkingMessageId = null;
- let thinkingContent = '';
- let summaryMessageId = null;
- let summaryContent = '';
-
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- buffer = lines.pop();
-
- let currentEvent = null;
-
- for (const line of lines) {
- if (!line.trim() || line.startsWith(':')) continue;
-
- if (line.startsWith('event:')) {
- currentEvent = line.substring(6).trim();
- continue;
- }
-
- if (line.startsWith('data:')) {
- try {
- const data = JSON.parse(line.substring(5).trim());
-
- if (currentEvent === 'thinking') {
- if (!thinkingMessageId) {
- thinkingMessageId = Date.now();
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- id: thinkingMessageId,
- type: MessageTypes.AGENT_THINKING,
- content: '',
- timestamp: new Date().toISOString(),
- });
- }
- thinkingContent += data.content;
- setMessages((prev) =>
- prev.map((m) =>
- m.id === thinkingMessageId
- ? { ...m, content: thinkingContent }
- : m
- )
- );
- } else if (currentEvent === 'plan') {
- currentPlan = data;
- thinkingMessageId = null;
- thinkingContent = '';
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_PLAN,
- content: '已制定执行计划',
- plan: data,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(30);
- } else if (currentEvent === 'step_complete') {
- const stepResult = {
- step_index: data.step_index,
- tool: data.tool,
- status: data.status,
- result: data.result,
- error: data.error,
- execution_time: data.execution_time,
- };
- stepResults.push(stepResult);
-
- setMessages((prev) =>
- prev.map((m) =>
- m.id === executingMessageId
- ? { ...m, stepResults: [...stepResults] }
- : m
- )
- );
-
- const progress = 40 + (stepResults.length / (currentPlan?.steps?.length || 5)) * 40;
- setCurrentProgress(Math.min(progress, 80));
- } else if (currentEvent === 'summary_chunk') {
- if (!summaryMessageId) {
- summaryMessageId = Date.now();
- summaryContent = '';
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- id: summaryMessageId,
- type: MessageTypes.AGENT_RESPONSE,
- content: '',
- plan: currentPlan,
- stepResults: stepResults,
- isStreaming: true,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(85);
- }
- summaryContent += data.content;
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? { ...m, content: summaryContent }
- : m
- )
- );
- } else if (currentEvent === 'summary') {
- if (summaryMessageId) {
- setMessages((prev) =>
- prev.map((m) =>
- m.id === summaryMessageId
- ? {
- ...m,
- content: data.content || summaryContent,
- metadata: data.metadata,
- isStreaming: false,
- }
- : m
- )
- );
- } else {
- setMessages((prev) =>
- prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
- );
- addMessage({
- type: MessageTypes.AGENT_RESPONSE,
- content: data.content,
- plan: currentPlan,
- stepResults: stepResults,
- metadata: data.metadata,
- isStreaming: false,
- timestamp: new Date().toISOString(),
- });
- }
- setCurrentProgress(100);
- } else if (currentEvent === 'status') {
- if (data.stage === 'planning') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(10);
- } else if (data.stage === 'executing') {
- const msgId = Date.now();
- executingMessageId = msgId;
- addMessage({
- id: msgId,
- type: MessageTypes.AGENT_EXECUTING,
- content: data.message,
- plan: currentPlan,
- stepResults: [],
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(40);
- } else if (data.stage === 'summarizing') {
- setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_EXECUTING));
- addMessage({
- type: MessageTypes.AGENT_THINKING,
- content: data.message,
- timestamp: new Date().toISOString(),
- });
- setCurrentProgress(80);
- }
- }
- } catch (e) {
- logger.error('解析 SSE 数据失败', e);
- }
- }
- }
- }
-
- loadSessions();
-
- } catch (error) {
- logger.error('Agent chat error', error);
-
- setMessages((prev) =>
- prev.filter(
- (m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING
- )
- );
-
- const errorMessage = error.response?.data?.detail || error.message || '处理失败';
-
- addMessage({
- type: MessageTypes.ERROR,
- content: `处理失败:${errorMessage}`,
- timestamp: new Date().toISOString(),
- });
-
- toast({
- title: '处理失败',
- description: errorMessage,
- status: 'error',
- duration: 5000,
- isClosable: true,
- });
- } finally {
- setIsProcessing(false);
- setCurrentProgress(0);
- inputRef.current?.focus();
- }
- };
-
- const handleKeyPress = (e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- handleSendMessage();
- }
- };
-
- const handleClearChat = () => {
- createNewSession();
- };
-
- const handleExportChat = () => {
- const chatText = messages
- .filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
- .map((msg) => `[${msg.type === MessageTypes.USER ? '用户' : '价小前'}] ${msg.content}`)
- .join('\n\n');
-
- const blob = new Blob([chatText], { type: 'text/plain' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `chat_${new Date().toISOString().slice(0, 10)}.txt`;
- a.click();
- URL.revokeObjectURL(url);
- };
-
- // ==================== 工具选择处理 ====================
-
- const handleToolToggle = (toolId, isChecked) => {
- if (isChecked) {
- setSelectedTools((prev) => [...prev, toolId]);
- } else {
- setSelectedTools((prev) => prev.filter((id) => id !== toolId));
- }
- };
-
- const handleCategoryToggle = (categoryTools, isAllSelected) => {
- const toolIds = categoryTools.map((t) => t.id);
- if (isAllSelected) {
- // 全部取消选中
- setSelectedTools((prev) => prev.filter((id) => !toolIds.includes(id)));
- } else {
- // 全部选中
- setSelectedTools((prev) => {
- const newTools = [...prev];
- toolIds.forEach((id) => {
- if (!newTools.includes(id)) {
- newTools.push(id);
- }
- });
- return newTools;
- });
- }
- };
-
- // ==================== 初始化 ====================
-
- useEffect(() => {
- if (user) {
- loadSessions();
- createNewSession();
- }
- }, [user]);
-
- // ==================== 渲染 ====================
-
- const quickQuestions = [
- '全面分析贵州茅台这只股票',
- '今日涨停股票有哪些亮点',
- '新能源概念板块的投资机会',
- '半导体行业最新动态',
- ];
-
- const filteredSessions = sessions.filter(
- (session) =>
- !searchQuery ||
- session.last_message?.toLowerCase().includes(searchQuery.toLowerCase())
- );
-
- return (
-
- {/* 背景装饰 - 黄金光晕效果 */}
-
-
-
- {/* 左侧会话列表 */}
-
-
- {/* 侧边栏头部 */}
-
- }
- bg={goldGradient}
- color={darkBg}
- w="100%"
- onClick={createNewSession}
- size="sm"
- _hover={{
- transform: 'translateY(-2px)',
- boxShadow: '0 4px 20px rgba(255, 215, 0, 0.4)',
- }}
- transition="all 0.3s"
- fontWeight="bold"
- >
- 新建对话
-
-
-
-
-
-
- setSearchQuery(e.target.value)}
- bg="rgba(255, 255, 255, 0.05)"
- border="1px solid"
- borderColor={borderGold}
- color={textWhite}
- _placeholder={{ color: textGray }}
- _hover={{ borderColor: goldAccent }}
- _focus={{ borderColor: goldAccent, boxShadow: `0 0 0 1px ${goldAccent}` }}
- />
-
-
-
- {/* 会话列表 */}
-
- {isLoadingSessions ? (
-
-
-
- ) : filteredSessions.length === 0 ? (
-
-
-
- {searchQuery ? '没有找到匹配的对话' : '暂无对话记录'}
-
-
- ) : (
- filteredSessions.map((session) => (
- switchSession(session.session_id)}
- transition="all 0.2s"
- >
-
-
-
- {session.last_message || '新对话'}
-
-
-
-
- {new Date(session.last_timestamp).toLocaleDateString('zh-CN', {
- month: 'numeric',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- })}
-
-
- {session.message_count} 条
-
-
-
-
-
- }
- size="xs"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent }}
- onClick={(e) => e.stopPropagation()}
- />
-
- }
- color="red.400"
- bg="transparent"
- _hover={{ bg: 'rgba(255, 0, 0, 0.1)' }}
- onClick={(e) => {
- e.stopPropagation();
- deleteSession(session.session_id);
- }}
- >
- 删除对话
-
-
-
-
-
- ))
- )}
-
-
- {/* 用户信息 */}
-
-
-
-
-
- {user?.nickname || '未登录'}
-
-
- MAX 订阅
-
-
-
-
-
-
-
- {/* 主聊天区域 */}
-
- {/* 聊天头部 */}
-
-
-
- }
- size="sm"
- variant="ghost"
- color={goldAccent}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="切换侧边栏"
- onClick={toggleSidebar}
- />
-
-
-
-
- 价小前投研
-
-
-
-
- AI 深度分析
-
-
-
- {AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name || '智能模型'}
-
-
-
-
-
-
- }
- size="sm"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent, bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="清空对话"
- onClick={handleClearChat}
- />
- }
- size="sm"
- variant="ghost"
- color={textGray}
- _hover={{ color: goldAccent, bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="导出对话"
- onClick={handleExportChat}
- />
- }
- size="sm"
- variant="ghost"
- color={goldAccent}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- aria-label="设置"
- onClick={toggleRightPanel}
- />
-
-
-
- {/* 进度条 */}
- {isProcessing && (
- div': {
- background: goldGradient,
- },
- }}
- isAnimated
- />
- )}
-
-
- {/* 消息列表 */}
-
-
- {messages.map((message) => (
-
-
-
- ))}
-
-
-
-
- {/* 快捷问题 */}
- {messages.length <= 2 && !isProcessing && (
-
-
- 💡 试试这些问题:
-
-
- {quickQuestions.map((question, idx) => (
- {
- setInputValue(question);
- inputRef.current?.focus();
- }}
- >
- {question}
-
- ))}
-
-
- )}
-
- {/* 输入框 */}
-
-
- setInputValue(e.target.value)}
- onKeyPress={handleKeyPress}
- placeholder="输入你的问题,我会进行深度分析..."
- bg="rgba(255, 255, 255, 0.05)"
- border="1px solid"
- borderColor={borderGold}
- color={textWhite}
- _placeholder={{ color: textGray }}
- _focus={{ borderColor: goldAccent, boxShadow: `0 0 0 1px ${goldAccent}` }}
- mr={2}
- disabled={isProcessing}
- size="lg"
- />
-
- {isProcessing ? : 发送 }
-
-
-
-
-
- {/* 右侧配置面板 */}
-
-
-
- {/* 模型选择 */}
-
-
-
-
- 选择模型
-
-
-
- {AVAILABLE_MODELS.map((model) => (
- setSelectedModel(model.id)}
- transition="all 0.2s"
- _hover={{
- bg: 'rgba(255, 215, 0, 0.1)',
- borderColor: goldAccent,
- transform: 'translateX(4px)',
- }}
- position="relative"
- >
- {model.recommended && (
-
- 推荐
-
- )}
-
- {model.icon}
-
-
- {model.name}
-
-
- {model.description}
-
-
- {selectedModel === model.id && (
-
- )}
-
-
- ))}
-
-
-
-
-
- {/* 工具选择 */}
-
-
-
-
-
- MCP 工具
-
-
-
- {selectedTools.length} 个已选
-
-
-
-
- {MCP_TOOL_CATEGORIES.map((category, catIdx) => {
- const categoryToolIds = category.tools.map((t) => t.id);
- const selectedInCategory = categoryToolIds.filter((id) => selectedTools.includes(id));
- const isAllSelected = selectedInCategory.length === categoryToolIds.length;
- const isSomeSelected = selectedInCategory.length > 0 && !isAllSelected;
-
- return (
-
-
-
- {category.icon}
-
- {category.name}
-
-
- {selectedInCategory.length}/{category.tools.length}
-
-
-
-
-
-
- {/* 全选按钮 */}
- handleCategoryToggle(category.tools, isAllSelected)}
- _hover={{ bg: 'rgba(255, 215, 0, 0.1)' }}
- >
- {isAllSelected ? '取消全选' : '全选'}
-
-
- {category.tools.map((tool) => (
- handleToolToggle(tool.id, e.target.checked)}
- colorScheme="yellow"
- size="sm"
- sx={{
- '.chakra-checkbox__control': {
- borderColor: borderGold,
- bg: 'rgba(255, 255, 255, 0.05)',
- _checked: {
- bg: goldGradient,
- borderColor: goldAccent,
- },
- },
- }}
- >
-
-
- {tool.name}
-
-
- {tool.description}
-
-
-
- ))}
-
-
-
- );
- })}
-
-
-
-
-
-
- );
-};
-
-/**
- * 消息渲染器(黑金毛玻璃风格)
- */
-const MessageRenderer = ({ message, userAvatar }) => {
- const glassBg = 'rgba(20, 20, 20, 0.7)';
- const goldAccent = '#FFD700';
- const goldGradient = 'linear-gradient(135deg, #FFD700 0%, #FFA500 100%)';
- const darkBg = '#0A0A0A';
- const borderGold = 'rgba(255, 215, 0, 0.3)';
- const textWhite = '#FFFFFF';
- const textGray = '#CCCCCC';
-
- switch (message.type) {
- case MessageTypes.USER:
- return (
-
-
-
-
- {message.content}
-
-
- }
- border="2px solid"
- borderColor={goldAccent}
- />
-
-
- );
-
- case MessageTypes.AGENT_THINKING:
- return (
-
-
-
-
-
-
-
-
-
- {message.content}
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_PLAN:
- return (
-
-
-
-
-
-
-
-
-
-
- );
-
- case MessageTypes.AGENT_EXECUTING:
- return (
-
-
-
-
-
-
-
- {message.stepResults?.map((result, idx) => (
-
- ))}
-
-
-
- );
-
- case MessageTypes.AGENT_RESPONSE:
- return (
-
-
-
-
-
-
- {/* 最终总结 */}
-
- {message.isStreaming ? (
-
- {message.content}
-
- ) : (
-
- )}
-
- {message.metadata && (
-
- 总步骤: {message.metadata.total_steps}
- ✓ {message.metadata.successful_steps}
- {message.metadata.failed_steps > 0 && (
- ✗ {message.metadata.failed_steps}
- )}
- 耗时: {message.metadata.total_execution_time?.toFixed(1)}s
-
- )}
-
-
- {/* 执行详情(可选) */}
- {message.plan && message.stepResults && message.stepResults.length > 0 && (
-
-
-
- 📊 执行详情(点击展开查看)
-
- {message.stepResults.map((result, idx) => (
-
- ))}
-
- )}
-
-
-
- );
-
- case MessageTypes.ERROR:
- return (
-
-
-
-
-
-
- {message.content}
-
-
-
- );
-
- default:
- return null;
- }
-};
-
-export default AgentChatV4;
diff --git a/src/views/AgentChat/neuratalk/.gitignore b/src/views/AgentChat/neuratalk/.gitignore
new file mode 100644
index 00000000..5ef6a520
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/.gitignore
@@ -0,0 +1,41 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files (can opt-in for committing if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/src/views/AgentChat/neuratalk/README.md b/src/views/AgentChat/neuratalk/README.md
new file mode 100644
index 00000000..e215bc4c
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/README.md
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/src/views/AgentChat/neuratalk/app/auth/check-email/page.tsx b/src/views/AgentChat/neuratalk/app/auth/check-email/page.tsx
new file mode 100644
index 00000000..871e1d71
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/check-email/page.tsx
@@ -0,0 +1,5 @@
+import CheckEmailPage from "@/templates/Auth/CheckEmailPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/auth/enter-code/page.tsx b/src/views/AgentChat/neuratalk/app/auth/enter-code/page.tsx
new file mode 100644
index 00000000..5fc4d597
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/enter-code/page.tsx
@@ -0,0 +1,5 @@
+import EnterCodePage from "@/templates/Auth/EnterCodePage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/auth/forgot-password/page.tsx b/src/views/AgentChat/neuratalk/app/auth/forgot-password/page.tsx
new file mode 100644
index 00000000..aa5c2dad
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/forgot-password/page.tsx
@@ -0,0 +1,5 @@
+import ForgotPasswordPage from "@/templates/Auth/ForgotPasswordPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/auth/reset-password/page.tsx b/src/views/AgentChat/neuratalk/app/auth/reset-password/page.tsx
new file mode 100644
index 00000000..4c1754a3
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/reset-password/page.tsx
@@ -0,0 +1,5 @@
+import ResetPasswordPage from "@/templates/Auth/ResetPasswordPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/auth/sign-in/page.tsx b/src/views/AgentChat/neuratalk/app/auth/sign-in/page.tsx
new file mode 100644
index 00000000..c5692a09
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/sign-in/page.tsx
@@ -0,0 +1,5 @@
+import SignInPage from "@/templates/Auth/SignInPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/auth/sign-up/page.tsx b/src/views/AgentChat/neuratalk/app/auth/sign-up/page.tsx
new file mode 100644
index 00000000..2599ed73
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/auth/sign-up/page.tsx
@@ -0,0 +1,5 @@
+import SignUpPage from "@/templates/Auth/SignUpPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/data-analytics/page.tsx b/src/views/AgentChat/neuratalk/app/data-analytics/page.tsx
new file mode 100644
index 00000000..f3fd0257
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/data-analytics/page.tsx
@@ -0,0 +1,5 @@
+import DataAnalyticsPage from "@/templates/DataAnalyticsPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/document-generation/page.tsx b/src/views/AgentChat/neuratalk/app/document-generation/page.tsx
new file mode 100644
index 00000000..6126b0b4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/document-generation/page.tsx
@@ -0,0 +1,5 @@
+import DocumentGenerationPage from "@/templates/DocumentGenerationPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/documents/page.tsx b/src/views/AgentChat/neuratalk/app/documents/page.tsx
new file mode 100644
index 00000000..1b884fb1
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/documents/page.tsx
@@ -0,0 +1,5 @@
+import DocumentsPage from "@/templates/DocumentsPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/favicon.ico b/src/views/AgentChat/neuratalk/app/favicon.ico
new file mode 100644
index 00000000..b1f2c79f
Binary files /dev/null and b/src/views/AgentChat/neuratalk/app/favicon.ico differ
diff --git a/src/views/AgentChat/neuratalk/app/generate-code/page.tsx b/src/views/AgentChat/neuratalk/app/generate-code/page.tsx
new file mode 100644
index 00000000..a9b41b00
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/generate-code/page.tsx
@@ -0,0 +1,5 @@
+import GenerateCodePage from "@/templates/GenerateCodePage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/globals.css b/src/views/AgentChat/neuratalk/app/globals.css
new file mode 100644
index 00000000..07f78443
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/globals.css
@@ -0,0 +1,411 @@
+@import "tailwindcss";
+@plugin "tailwind-scrollbar";
+
+@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
+
+:root {
+ --static-white: #ffffff;
+ --static-black: #0e121b;
+ --white-0: #ffffff;
+ --strong-950: #0e121b;
+ --bg-weak-50: #f9fafc;
+ --bg-surface-800: #222530;
+ --bg-soft-200: #e1e4ea;
+ --bg-sub-300: #cacfd8;
+ --text-sub-600: #525866;
+ --text-disabled-300: #cacfd8;
+ --text-soft-400: #99a0ae;
+ --faded-light: #e1e4ea;
+ --faded-base: #717784;
+ --faded-dark: #222530;
+ --faded-lighter: #f2f5f8;
+ --error-base: #fb3748;
+ --error-light: #ffc0c5;
+ --error-dark: #681219;
+ --error-lighter: #ffebec;
+ --warning-dark: #682f12;
+ --warning-base: #ff8447;
+ --warning-light: #ffd5c0;
+ --warning-lighter: #fff1eb;
+ --information-dark: #122368;
+ --information-base: #335cff;
+ --information-light: #c0d5ff;
+ --information-lighter: #ebf1ff;
+ --success-dark: #0b4627;
+ --success-base: #1fc16b;
+ --success-light: #c2f5da;
+ --success-lighter: #e0faec;
+ --away-dark: #624c18;
+ --away-base: #f6b51e;
+ --away-light: #ffecc0;
+ --away-lighter: #fffaeb;
+ --feature-dark: #351a75;
+ --feature-base: #7d52f4;
+ --feature-light: #cac0ff;
+ --feature-lighter: #efebff;
+ --verified-dark: #124b68;
+ --verified-base: #47c2ff;
+ --verified-light: #c0eaff;
+ --verified-lighter: #ebf8ff;
+ --highlighted-dark: #68123d;
+ --highlighted-base: #fb4ba3;
+ --highlighted-light: #ffc0df;
+ --highlighted-lighter: #ffebf4;
+ --stable-dark: #0b463e;
+ --stable-base: #22d3bb;
+ --stable-light: #c2f5ee;
+ --stable-lighter: #e4fbf8;
+ --stroke-soft-200: #e1e4ea;
+ --stroke-strong-950: #0e121b;
+ --stroke-white-0: #ffffff;
+ --stroke-sub-300: #cacfd8;
+ --icon-sub-600: #525866;
+ --icon-strong-950: #0e121b;
+ --icon-soft-400: #99a0ae;
+ --icon-disabled-300: #cacfd8;
+ --icon-white-0: #ffffff;
+ --social-apple: #000000;
+ --social-twitter: #010101;
+ --social-github: #24292f;
+ --social-notion: #1e2226;
+ --social-tidal: #000000;
+ --social-amazon: #353e47;
+ --social-zendesk: #16140d;
+ --illustration-strong-400: #99a0ae;
+ --illustration-sub-300: #cacfd8;
+ --illustration-soft-200: #e1e4ea;
+ --illustration-weak-100: #f2f5f8;
+ --illustration-white-0: #ffffff;
+ --overlay: rgba(2, 13, 23, 0.24);
+ --blue-50: #ebf1ff;
+ --blue-100: #d5e2ff;
+ --blue-200: #c0d5ff;
+ --blue-300: #97baff;
+ --blue-400: #6895ff;
+ --blue-500: #335cff;
+ --blue-600: #3559e9;
+ --blue-700: #2547d0;
+ --blue-800: #1f3bad;
+ --blue-900: #182f8b;
+ --blue-950: #122368;
+ --green-50: #e0faec;
+ --green-100: #d0fbe9;
+ --green-200: #c2f5da;
+ --green-300: #84ebb4;
+ --green-400: #3ee089;
+ --green-500: #1fc16b;
+ --green-600: #1daf61;
+ --green-700: #178c4e;
+ --green-800: #1a7544;
+ --green-900: #16643b;
+ --green-950: #0b4627;
+}
+
+[data-theme="dark"] {
+ --white-0: #0e121b;
+ --strong-950: #ffffff;
+ --bg-weak-50: #181b25;
+ --bg-surface-800: #e1e4ea;
+ --bg-soft-200: #2b303b;
+ --bg-sub-300: #525866;
+ --text-sub-600: #99a0ae;
+ --text-disabled-300: #525866;
+ --text-soft-400: #717784;
+ --faded-light: rgba(153, 160, 174, 0.24);
+ --faded-base: #717784;
+ --faded-dark: #cacfd8;
+ --faded-lighter: rgba(153, 160, 174, 0.16);
+ --error-base: #e93544;
+ --error-light: rgba(251, 55, 72, 0.24);
+ --error-dark: #ff6875;
+ --error-lighter: rgba(251, 55, 72, 0.16);
+ --warning-dark: #ff9a68;
+ --warning-base: #e97135;
+ --warning-light: rgba(255, 145, 71, 0.24);
+ --warning-lighter: rgba(255, 145, 71, 0.16);
+ --information-dark: #6895ff;
+ --information-base: #335cff;
+ --information-light: rgba(71, 108, 255, 0.24);
+ --information-lighter: rgba(71, 108, 255, 0.16);
+ --success-dark: #3ee089;
+ --success-base: #1daf61;
+ --success-light: rgba(31, 193, 107, 0.16);
+ --success-lighter: rgba(31, 193, 107, 0.1);
+ --away-dark: #ffd268;
+ --away-base: #e6a819;
+ --away-light: rgba(251, 198, 75, 0.24);
+ --away-lighter: rgba(251, 198, 75, 0.16);
+ --feature-dark: #8c71f6;
+ --feature-base: #7d52f4;
+ --feature-light: rgba(120, 77, 239, 0.24);
+ --feature-lighter: rgba(120, 77, 239, 0.16);
+ --verified-dark: #68cdff;
+ --verified-base: #35ade9;
+ --verified-light: rgba(71, 194, 255, 0.24);
+ --verified-lighter: rgba(71, 194, 255, 0.16);
+ --highlighted-dark: #ff68b3;
+ --highlighted-base: #e9358f;
+ --highlighted-light: rgba(251, 75, 163, 0.24);
+ --highlighted-lighter: rgba(251, 75, 163, 0.16);
+ --stable-dark: #3fdec9;
+ --stable-base: #1daf9c;
+ --stable-light: rgba(34, 211, 187, 0.24);
+ --stable-lighter: rgba(34, 211, 187, 0.16);
+ --stroke-soft-200: #2b303b;
+ --stroke-strong-950: #ffffff;
+ --stroke-white-0: #0e121b;
+ --stroke-sub-300: #525866;
+ --icon-sub-600: #99a0ae;
+ --icon-strong-950: #ffffff;
+ --icon-soft-400: #717784;
+ --icon-disabled-300: #525866;
+ --icon-white-0: #0e121b;
+ --social-apple: #ffffff;
+ --social-twitter: #ffffff;
+ --social-github: #ffffff;
+ --social-notion: #ffffff;
+ --social-tidal: #ffffff;
+ --social-amazon: #ffffff;
+ --social-zendesk: #ffffff;
+ --illustration-strong-400: #525866;
+ --illustration-sub-300: #2b303b;
+ --illustration-soft-200: #222530;
+ --illustration-weak-100: #181b25;
+ --illustration-white-0: #0e121b;
+ --overlay: rgba(82, 88, 102, 0.32);
+}
+
+@theme {
+ --breakpoint-*: initial;
+ --breakpoint-sm: 480px;
+ --breakpoint-md: 767px;
+ --breakpoint-lg: 1023px;
+ --breakpoint-xl: 1259px;
+ --breakpoint-2xl: 1419px;
+ --breakpoint-3xl: 1719px;
+ --breakpoint-4xl: 1899px;
+ --color-static-white: var(--static-white);
+ --color-static-black: var(--static-black);
+ --color-white-0: var(--white-0);
+ --color-strong-950: var(--strong-950);
+ --color-weak-50: var(--bg-weak-50);
+ --color-surface-800: var(--bg-surface-800);
+ --color-soft-200: var(--bg-soft-200);
+ --color-sub-300: var(--bg-sub-300);
+ --color-sub-600: var(--text-sub-600);
+ --color-disabled-300: var(--text-disabled-300);
+ --color-soft-400: var(--text-soft-400);
+ --color-faded-light: var(--faded-light);
+ --color-faded-base: var(--faded-base);
+ --color-faded-dark: var(--faded-dark);
+ --color-faded-lighter: var(--faded-lighter);
+ --color-error-base: var(--error-base);
+ --color-error-light: var(--error-light);
+ --color-error-dark: var(--error-dark);
+ --color-error-lighter: var(--error-lighter);
+ --color-warning-dark: var(--warning-dark);
+ --color-warning-base: var(--warning-base);
+ --color-warning-light: var(--warning-light);
+ --color-warning-lighter: var(--warning-lighter);
+ --color-information-dark: var(--information-dark);
+ --color-information-base: var(--information-base);
+ --color-information-light: var(--information-light);
+ --color-information-lighter: var(--information-lighter);
+ --color-success-dark: var(--success-dark);
+ --color-success-base: var(--success-base);
+ --color-success-light: var(--success-light);
+ --color-success-lighter: var(--success-lighter);
+ --color-away-dark: var(--away-dark);
+ --color-away-base: var(--away-base);
+ --color-away-light: var(--away-light);
+ --color-away-lighter: var(--away-lighter);
+ --color-feature-dark: var(--feature-dark);
+ --color-feature-base: var(--feature-base);
+ --color-feature-light: var(--feature-light);
+ --color-feature-lighter: var(--feature-lighter);
+ --color-verified-dark: var(--verified-dark);
+ --color-verified-base: var(--verified-base);
+ --color-verified-light: var(--verified-light);
+ --color-verified-lighter: var(--verified-lighter);
+ --color-highlighted-dark: var(--highlighted-dark);
+ --color-highlighted-base: var(--highlighted-base);
+ --color-highlighted-light: var(--highlighted-light);
+ --color-highlighted-lighter: var(--highlighted-lighter);
+ --color-stable-dark: var(--stable-dark);
+ --color-stable-base: var(--stable-base);
+ --color-stable-light: var(--stable-light);
+ --color-stable-lighter: var(--stable-lighter);
+ --color-stroke-soft-200: var(--stroke-soft-200);
+ --color-stroke-strong-950: var(--stroke-strong-950);
+ --color-stroke-white-0: var(--stroke-white-0);
+ --color-stroke-sub-300: var(--stroke-sub-300);
+ --color-icon-sub-600: var(--icon-sub-600);
+ --color-icon-strong-950: var(--icon-strong-950);
+ --color-icon-soft-400: var(--icon-soft-400);
+ --color-icon-disabled-300: var(--icon-disabled-300);
+ --color-icon-white-0: var(--icon-white-0);
+ --color-social-apple: var(--social-apple);
+ --color-social-twitter: var(--social-twitter);
+ --color-social-github: var(--social-github);
+ --color-social-notion: var(--social-notion);
+ --color-social-tidal: var(--social-tidal);
+ --color-social-amazon: var(--social-amazon);
+ --color-social-zendesk: var(--social-zendesk);
+ --color-illustration-strong-400: var(--illustration-strong-400);
+ --color-illustration-sub-300: var(--illustration-sub-300);
+ --color-illustration-soft-200: var(--illustration-soft-200);
+ --color-illustration-weak-100: var(--illustration-weak-100);
+ --color-illustration-white-0: var(--illustration-white-0);
+ --color-overlay: var(--overlay);
+ --color-blue-50: var(--blue-50);
+ --color-blue-100: var(--blue-100);
+ --color-blue-200: var(--blue-200);
+ --color-blue-300: var(--blue-300);
+ --color-blue-400: var(--blue-400);
+ --color-blue-500: var(--blue-500);
+ --color-blue-600: var(--blue-600);
+ --color-blue-700: var(--blue-700);
+ --color-blue-800: var(--blue-800);
+ --color-blue-900: var(--blue-900);
+ --color-blue-950: var(--blue-950);
+ --color-green-50: var(--green-50);
+ --color-green-100: var(--green-100);
+ --color-green-200: var(--green-200);
+ --color-green-300: var(--green-300);
+ --color-green-400: var(--green-400);
+ --color-green-500: var(--green-500);
+ --color-green-600: var(--green-600);
+ --color-green-700: var(--green-700);
+ --color-green-800: var(--green-800);
+ --color-green-900: var(--green-900);
+ --color-green-950: var(--green-950);
+ --default-transition-duration: 0.2s;
+ --font-satoshi: var(--font-satoshi);
+ --font-inter: var(--font-inter);
+ --font-inter-display: var(--font-inter-display);
+ --text-0: 0;
+ --text-h1: 4rem;
+ --text-h1--line-height: 1.09;
+ --text-h1--letter-spacing: -0.01em;
+ --text-h1--font-weight: 700;
+ --text-h3: 2.5rem;
+ --text-h3--line-height: 1.2;
+ --text-h3--letter-spacing: -0.01em;
+ --text-h3--font-weight: 500;
+ --text-h4: 2.25rem;
+ --text-h4--line-height: 1.5;
+ --text-h4--letter-spacing: -0.005em;
+ --text-h4--font-weight: 500;
+ --text-h5: 1.75rem;
+ --text-h5--line-height: 1.5;
+ --text-h5--letter-spacing: 0;
+ --text-h5--font-weight: 700;
+ --text-h6: 1.25rem;
+ --text-h6--line-height: 1.5;
+ --text-h6--letter-spacing: 0;
+ --text-h6--font-weight: 500;
+ --text-label-xl: 1.5rem;
+ --text-label-xl--line-height: 1.33;
+ --text-label-xl--letter-spacing: -0.015em;
+ --text-label-xl--font-weight: 500;
+ --text-label-lg: 1.125rem;
+ --text-label-lg--line-height: 1.5;
+ --text-label-lg--letter-spacing: -0.015em;
+ --text-label-lg--font-weight: 500;
+ --text-label-md: 1rem;
+ --text-label-md--line-height: 1.5;
+ --text-label-md--letter-spacing: -0.011em;
+ --text-label-md--font-weight: 500;
+ --text-label-sm: 0.875rem;
+ --text-label-sm--line-height: 1.4;
+ --text-label-sm--letter-spacing: -0.006em;
+ --text-label-sm--font-weight: 500;
+ --text-label-xs: 0.75rem;
+ --text-label-xs--line-height: 1.33;
+ --text-label-xs--letter-spacing: 0;
+ --text-label-xs--font-weight: 500;
+ --text-p-xl: 1.25rem;
+ --text-p-xl--line-height: 1.5;
+ --text-p-xl--letter-spacing: -0.015em;
+ --text-p-xl--font-weight: 400;
+ --text-p-lg: 1.125rem;
+ --text-p-lg--line-height: 1.33;
+ --text-p-lg--letter-spacing: -0.015em;
+ --text-p-lg--font-weight: 400;
+ --text-p-md: 1rem;
+ --text-p-md--line-height: 1.5;
+ --text-p-md--letter-spacing: -0.011em;
+ --text-p-md--font-weight: 300;
+ --text-p-sm: 0.875rem;
+ --text-p-sm--line-height: 1.5;
+ --text-p-sm--letter-spacing: -0.006em;
+ --text-p-sm--font-weight: 400;
+ --text-p-xs: 0.75rem;
+ --text-p-xs--line-height: 1.33;
+ --text-p-xs--letter-spacing: 0;
+ --text-p-xs--font-weight: 400;
+ --text-sub-md: 1rem;
+ --text-sub-md--line-height: 1.5;
+ --text-sub-md--letter-spacing: 0;
+ --text-sub-md--font-weight: 700;
+ --text-sub-sm: 0.875rem;
+ --text-sub-sm--line-height: 1.4;
+ --text-sub-sm--letter-spacing: 0.06em;
+ --text-sub-sm--font-weight: 500;
+ --text-sub-xs: 0.75rem;
+ --text-sub-xs--line-height: 1.33;
+ --text-sub-xs--letter-spacing: 0.04em;
+ --text-sub-xs--font-weight: 500;
+ --text-sub-2xs: 0.6875rem;
+ --text-sub-2xs--line-height: 1.1;
+ --text-sub-2xs--letter-spacing: 0.02em;
+ --text-sub-2xs--font-weight: 500;
+}
+
+@layer base {
+ button {
+ @apply cursor-pointer;
+ }
+}
+
+@layer components {
+ .text-h3 {
+ @apply font-inter-display;
+ }
+ .text-label-xl,
+ .text-p-lg,
+ .text-sub-sm,
+ .text-sub-xs,
+ .text-sub-2xs {
+ @apply font-inter;
+ }
+ .chat-wrapper {
+ @apply flex flex-col h-[calc(100svh-8.25rem)] bg-white-0 rounded-3xl shadow-[0_0_1.25rem_0_rgba(0,0,0,0.03)] max-2xl:h-[calc(100svh-7.125rem)] max-lg:h-[calc(100svh-6.125rem)] max-md:h-[calc(100svh-5rem)] max-md:rounded-xl;
+ }
+ .content h3 {
+ @apply mb-5 text-h3 max-2xl:text-[2rem] max-md:text-[1.6rem];
+ }
+ .content p {
+ @apply text-label-md not-last:mb-4 max-md:text-p-sm max-md:not-last:mb-2;
+ }
+ .recharts-surface {
+ @apply outline-none;
+ }
+ .recharts-sector {
+ @apply stroke-transparent outline-none;
+ }
+}
+
+/* SVG Progress Animation */
+@keyframes progress {
+ from {
+ stroke-dashoffset: 100.48;
+ }
+ to {
+ stroke-dashoffset: 0;
+ }
+}
+
+.animate-progress {
+ animation: progress linear forwards;
+}
diff --git a/src/views/AgentChat/neuratalk/app/history/page.tsx b/src/views/AgentChat/neuratalk/app/history/page.tsx
new file mode 100644
index 00000000..893e0682
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/history/page.tsx
@@ -0,0 +1,5 @@
+import HistoryPage from "@/templates/HistoryPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/image-generation/page.tsx b/src/views/AgentChat/neuratalk/app/image-generation/page.tsx
new file mode 100644
index 00000000..fdf93e00
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/image-generation/page.tsx
@@ -0,0 +1,5 @@
+import ImageGenerationPage from "@/templates/ImageGenerationPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/layout.tsx b/src/views/AgentChat/neuratalk/app/layout.tsx
new file mode 100644
index 00000000..897d3938
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/layout.tsx
@@ -0,0 +1,158 @@
+import type { Metadata } from "next";
+import { Inter } from "next/font/google";
+import localFont from "next/font/local";
+import Providers from "./providers";
+import "./globals.css";
+
+const inter = Inter({
+ variable: "--font-inter",
+ subsets: ["latin"],
+});
+
+const satoshi = localFont({
+ src: [
+ {
+ path: "../public/fonts/Satoshi-Light.woff2",
+ weight: "300",
+ },
+ {
+ path: "../public/fonts/Satoshi-Regular.woff2",
+ weight: "400",
+ },
+ {
+ path: "../public/fonts/Satoshi-Medium.woff2",
+ weight: "500",
+ },
+ {
+ path: "../public/fonts/Satoshi-Bold.woff2",
+ weight: "700",
+ },
+ ],
+ variable: "--font-satoshi",
+});
+
+const interDisplay = localFont({
+ src: [
+ {
+ path: "../public/fonts/InterDisplay-Medium.woff2",
+ weight: "500",
+ },
+ ],
+ variable: "--font-inter-display",
+});
+
+export const metadata: Metadata = {
+ title: "NeuraTalk",
+ description: "NeuraTalk: Coded AI Chat Companion",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+ {/* Description no longer than 155 characters */}
+
+
+ {/* NeuraTalk: Coded AI Chat Companion */}
+
+
+ {/* Twitter Card data */}
+
+
+
+
+
+ {/* Twitter Summary card images must be at least 120x120px */}
+
+
+ {/* Open Graph data for Facebook */}
+
+
+
+
+
+
+
+
+ {/* Open Graph data for LinkedIn */}
+
+
+
+
+
+ {/* Open Graph data for Pinterest */}
+
+
+
+
+
+
+ {children}
+
+
+ );
+}
diff --git a/src/views/AgentChat/neuratalk/app/page.tsx b/src/views/AgentChat/neuratalk/app/page.tsx
new file mode 100644
index 00000000..72729129
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/page.tsx
@@ -0,0 +1,15 @@
+// 可以选择使用原始主页或直接进入聊天
+// import HomePage from "@/templates/HomePage";
+import MCPChat from "@/components/Chat/MCPChat";
+
+export default function Page() {
+ // 直接显示聊天界面
+ return (
+
+
+
+ );
+
+ // 或者使用原始主页
+ // return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/providers.tsx b/src/views/AgentChat/neuratalk/app/providers.tsx
new file mode 100644
index 00000000..74d4f22b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/providers.tsx
@@ -0,0 +1,13 @@
+"use client";
+
+import { ThemeProvider } from "next-themes";
+
+const Providers = ({ children }: { children: React.ReactNode }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default Providers;
diff --git a/src/views/AgentChat/neuratalk/app/research/page.tsx b/src/views/AgentChat/neuratalk/app/research/page.tsx
new file mode 100644
index 00000000..35c9334e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/research/page.tsx
@@ -0,0 +1,5 @@
+import ResearchPage from "@/templates/ResearchPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/templates/page.tsx b/src/views/AgentChat/neuratalk/app/templates/page.tsx
new file mode 100644
index 00000000..34e8b118
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/templates/page.tsx
@@ -0,0 +1,5 @@
+import TemplatesPage from "@/templates/TemplatesPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/app/write-copy/page.tsx b/src/views/AgentChat/neuratalk/app/write-copy/page.tsx
new file mode 100644
index 00000000..567b60a1
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/app/write-copy/page.tsx
@@ -0,0 +1,5 @@
+import WriteCopyPage from "@/templates/WriteCopyPage";
+
+export default function Page() {
+ return ;
+}
diff --git a/src/views/AgentChat/neuratalk/components/Actions/index.tsx b/src/views/AgentChat/neuratalk/components/Actions/index.tsx
new file mode 100644
index 00000000..8a2c0290
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Actions/index.tsx
@@ -0,0 +1,47 @@
+import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
+import Icon from "@/components/Icon";
+
+type Props = {
+ className?: string;
+ classNameButton?: string;
+ items: {
+ name: string;
+ onClick: () => void;
+ }[];
+};
+
+const Actions = ({ className, classNameButton, items }: Props) => {
+ return (
+
+
+
+
+
+ {items.map((item, index) => (
+ item.onClick()}
+ as="button"
+ >
+ {item.name}
+
+ ))}
+
+
+ );
+};
+
+export default Actions;
diff --git a/src/views/AgentChat/neuratalk/components/Answer/index.tsx b/src/views/AgentChat/neuratalk/components/Answer/index.tsx
new file mode 100644
index 00000000..3a2982a3
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Answer/index.tsx
@@ -0,0 +1,25 @@
+import Image from "@/components/Image";
+
+type Props = {
+ children: React.ReactNode;
+};
+
+const Answer = ({ children }: Props) => (
+
+
+
+
+
+
Odyssey AI
+ {children}
+
+
+);
+
+export default Answer;
diff --git a/src/views/AgentChat/neuratalk/components/ApiIntegrator/index.tsx b/src/views/AgentChat/neuratalk/components/ApiIntegrator/index.tsx
new file mode 100644
index 00000000..7b547523
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ApiIntegrator/index.tsx
@@ -0,0 +1,70 @@
+import { useState } from "react";
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import CodeEditor from "@/components/CodeEditor";
+
+const ApiIntegrator = () => {
+ const [code, setCode] = useState(`{
+ "location": "Paris",
+ "temperature": 18,
+ "condition": "Partly Cloudy"
+}`);
+
+ return (
+
+
+
+ Use the API to get the current weather in Paris.
+
+
+ https://api.weatherly.ai/v1/current
+
+
+
+
+
+
+ Absolutely! Here's the result for the API
+ setup, for the current weather in paris.
+
+
+
🔧 API Example
+
+ API Name: Weatherly API
+
+ Endpoint: https://api.weatherly.ai/v1/current
+
+ Method: GET
+
+ Query Params:
+
+ city=Paris
+ unit=celsius
+
+
+ Response Example:
+
+
+
+
+ It’s currently 18°C and partly cloudy in Paris. A lovely
+ day to be outside!
+
+
+
+
+ );
+};
+
+export default ApiIntegrator;
diff --git a/src/views/AgentChat/neuratalk/components/Article/index.tsx b/src/views/AgentChat/neuratalk/components/Article/index.tsx
new file mode 100644
index 00000000..52f0b1de
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Article/index.tsx
@@ -0,0 +1,53 @@
+import Icon from "@/components/Icon";
+import Button from "@/components/Button";
+
+type Props = {
+ content: React.ReactNode;
+ onEdit: () => void;
+};
+
+const Article = ({ content, onEdit }: Props) => (
+
+
+
+
+ Document
+
+
+
+
+
+
+ Donwload Article
+
+
+ Edit Article
+
+
+
+ {content}
+
+
+);
+
+export default Article;
diff --git a/src/views/AgentChat/neuratalk/components/Browser/content.tsx b/src/views/AgentChat/neuratalk/components/Browser/content.tsx
new file mode 100644
index 00000000..c56af747
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Browser/content.tsx
@@ -0,0 +1,18 @@
+export const content = [
+ {
+ id: 0,
+ title: "The STAUD – A Creative Powerhouse",
+ description:
+ "Key features: Smooth animations, seamless navigation, and intuitive user flow.",
+ link: "http://webflow.com/theSTAUD.com",
+ image: "/images/browser-pic-1.jpg",
+ },
+ {
+ id: 1,
+ title: "New Horizon – Connecting you to faith",
+ description:
+ "Key features: Smooth animations, seamless navigation, and intuitive user flow.",
+ link: "http://webflow.com/newHorizon.com",
+ image: "/images/browser-pic-2.jpg",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/Browser/index.tsx b/src/views/AgentChat/neuratalk/components/Browser/index.tsx
new file mode 100644
index 00000000..16dce869
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Browser/index.tsx
@@ -0,0 +1,71 @@
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import Image from "@/components/Image";
+import Icon from "@/components/Icon";
+import Actions from "@/components/Actions";
+
+import { content } from "./content";
+
+const actions = [
+ { name: "Edit", onClick: () => {} },
+ { name: "Delete", onClick: () => {} },
+ { name: "Copy", onClick: () => {} },
+];
+
+const Browser = () => {
+ return (
+
+
+ what is the most beatiful website made using{" "}
+ webflow
+
+
+
+ If you're searching for the most beautiful websites
+ built with Webflow, there are several standout examples that
+ showcase the platform's capabilities in design,
+ interactivity, and storytelling. Here are some notable ones:
+
+
+ {content.map((item, index) => (
+
+
+ 🌟 {index + 1}. {item.title}
+
+
{item.description}
+
+ {item.link}
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default Browser;
diff --git a/src/views/AgentChat/neuratalk/components/Button/index.tsx b/src/views/AgentChat/neuratalk/components/Button/index.tsx
new file mode 100644
index 00000000..b58cea80
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Button/index.tsx
@@ -0,0 +1,88 @@
+import React from "react";
+import Link, { LinkProps } from "next/link";
+import Icon from "@/components/Icon";
+
+type CommonProps = {
+ className?: string;
+ icon?: string;
+ children?: React.ReactNode;
+ isBlack?: boolean;
+ isWhite?: boolean;
+ isRed?: boolean;
+ isBlue?: boolean;
+ isStroke?: boolean;
+ isCircle?: boolean;
+};
+
+type ButtonAsButton = {
+ as?: "button";
+} & React.ButtonHTMLAttributes;
+
+type ButtonAsAnchor = {
+ as: "a";
+} & React.AnchorHTMLAttributes;
+
+type ButtonAsLink = {
+ as: "link";
+} & LinkProps;
+
+type ButtonProps = CommonProps &
+ (ButtonAsButton | ButtonAsAnchor | ButtonAsLink);
+
+const Button: React.FC = ({
+ className,
+ icon,
+ children,
+ isBlack,
+ isWhite,
+ isRed,
+ isBlue,
+ isStroke,
+ isCircle,
+ as = "button",
+ ...props
+}) => {
+ const isLink = as === "link";
+ const Component: React.ElementType = isLink ? Link : as;
+
+ return (
+
+ {icon && (
+
+ )}
+ {children}
+
+ );
+};
+
+export default Button;
diff --git a/src/views/AgentChat/neuratalk/components/Calculator/index.tsx b/src/views/AgentChat/neuratalk/components/Calculator/index.tsx
new file mode 100644
index 00000000..10f80d08
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Calculator/index.tsx
@@ -0,0 +1,42 @@
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+
+const Calculator = () => {
+ return (
+
+
+ solve this problem for me:
+
+ Find the derivative of f(x) = x³ + 2x² - 7
+
+
+ Sure here is the response:
+
+
✅ Step-by-step solution:
+
+
We’ll differentiate f(x) term by term:
+
+
+ Derivative of x³ is:
+ → 3x²
+
+
+ Derivative of 2x² is:
+ → 2 × 2x = 4x
+
+
+ Derivative of constant -7 is:
+ → 0
+
+
+
+
🎯 Final Answer:
+
f'(x) = 3x² + 4x
+
+
+
+ );
+};
+
+export default Calculator;
diff --git a/src/views/AgentChat/neuratalk/components/Chart/data.tsx b/src/views/AgentChat/neuratalk/components/Chart/data.tsx
new file mode 100644
index 00000000..5314fec7
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Chart/data.tsx
@@ -0,0 +1,30 @@
+export const data = [
+ {
+ name: "Oct 16",
+ tp: 32456,
+ },
+ {
+ name: "Oct 17",
+ tp: 52456,
+ },
+ {
+ name: "Oct 18",
+ tp: 21456,
+ },
+ {
+ name: "Oct 19",
+ tp: 27456,
+ },
+ {
+ name: "Oct 20",
+ tp: 52456,
+ },
+ {
+ name: "Oct 21",
+ tp: 22456,
+ },
+ {
+ name: "Oct 22",
+ tp: 32456,
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/Chart/index.tsx b/src/views/AgentChat/neuratalk/components/Chart/index.tsx
new file mode 100644
index 00000000..58f5db4b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Chart/index.tsx
@@ -0,0 +1,162 @@
+import { useState } from "react";
+import {
+ ResponsiveContainer,
+ AreaChart,
+ Area,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+} from "recharts";
+import millify from "millify";
+import Select from "@/components/Select";
+import Icon from "@/components/Icon";
+
+import { data } from "./data";
+
+const durationOptions = [
+ { id: 1, name: "Last 7 days" },
+ { id: 2, name: "Last 14 days" },
+ { id: 3, name: "Last 21 days" },
+];
+
+const Chart = ({}) => {
+ const [duration, setDuration] = useState(durationOptions[0]);
+
+ const formatterYAxis = (value: number) => {
+ if (value === 0) {
+ return "$0";
+ }
+ return `$${millify(value, {
+ lowercase: false,
+ })}`;
+ };
+
+ const CustomTooltip = ({ payload }: { payload: { value: number }[] }) => {
+ if (payload && payload.length) {
+ return (
+
+ Bitcoin : ${payload[0].value}
+
+ );
+ }
+ return null;
+ };
+
+ return (
+
+
+
+
Bitcoin
+
+
+
+
+ Oct 16 - Oct 22 2025
+
+
+
+
+
$94,112
+
+
+ 12%
+
+
+ vs last Week
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ cursor={{
+ stroke: "var(--strong-950)",
+ strokeDasharray: "5 5",
+ }}
+ />
+
+
+
+
+
+
+ );
+};
+
+export default Chart;
diff --git a/src/views/AgentChat/neuratalk/components/Chat/Head/index.tsx b/src/views/AgentChat/neuratalk/components/Chat/Head/index.tsx
new file mode 100644
index 00000000..1dbc1d47
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Chat/Head/index.tsx
@@ -0,0 +1,62 @@
+import { useState } from "react";
+import Icon from "@/components/Icon";
+import ModalShare from "@/components/ModalShare";
+import Actions from "@/components/Actions";
+
+const actions = [
+ { name: "New chat", onClick: () => {} },
+ { name: "Move to folder", onClick: () => {} },
+ { name: "Clear chat", onClick: () => {} },
+ { name: "Delete chat", onClick: () => {} },
+];
+
+type ButtonProps = {
+ icon: string;
+ onClick: () => void;
+};
+
+const Button = ({ icon, onClick }: ButtonProps) => (
+
+
+
+);
+
+type Props = {
+ title?: React.ReactNode;
+};
+
+const Head = ({ title }: Props) => {
+ const [visible, setVisible] = useState(false);
+
+ return (
+ <>
+
+ {title ? (
+ title
+ ) : (
+
+
+
Ask your AI
+
+ Beta
+
+
+ )}
+
+
setVisible(true)} />
+ {}} />
+
+
+
+ setVisible(false)} />
+ >
+ );
+};
+
+export default Head;
diff --git a/src/views/AgentChat/neuratalk/components/Chat/MCPChat.tsx b/src/views/AgentChat/neuratalk/components/Chat/MCPChat.tsx
new file mode 100644
index 00000000..63567c7f
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Chat/MCPChat.tsx
@@ -0,0 +1,288 @@
+// components/Chat/MCPChat.tsx - 集成 MCP 的聊天组件
+'use client';
+
+import React, { useState, useRef, useEffect } from 'react';
+import { mcpService } from '../../services/mcp-real';
+import { useAuth } from '../../hooks/useAuth';
+import styles from './MCPChat.module.css';
+
+interface Message {
+ id: string;
+ role: 'user' | 'assistant' | 'system';
+ content: string;
+ timestamp: Date;
+ isStreaming?: boolean;
+}
+
+export default function MCPChat() {
+ const [messages, setMessages] = useState([]);
+ const [input, setInput] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
+ const [streamingMessage, setStreamingMessage] = useState('');
+ const [tools, setTools] = useState([]);
+ const messagesEndRef = useRef(null);
+ const { user, isAuthenticated, canAccessChat, loading: authLoading } = useAuth();
+
+ // 加载可用工具
+ useEffect(() => {
+ if (isAuthenticated && canAccessChat) {
+ loadTools();
+ }
+ }, [isAuthenticated, canAccessChat]);
+
+ // 自动滚动到底部
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+ }, [messages, streamingMessage]);
+
+ const loadTools = async () => {
+ try {
+ const availableTools = await mcpService.getTools();
+ setTools(availableTools);
+ console.log('Available tools:', availableTools);
+ } catch (error) {
+ console.error('Failed to load tools:', error);
+ }
+ };
+
+ const handleSend = async () => {
+ if (!input.trim() || isLoading) return;
+
+ const userMessage: Message = {
+ id: Date.now().toString(),
+ role: 'user',
+ content: input,
+ timestamp: new Date(),
+ };
+
+ setMessages(prev => [...prev, userMessage]);
+ setInput('');
+ setIsLoading(true);
+ setStreamingMessage('');
+
+ try {
+ // 创建助手消息占位符
+ const assistantMessage: Message = {
+ id: (Date.now() + 1).toString(),
+ role: 'assistant',
+ content: '',
+ timestamp: new Date(),
+ isStreaming: true,
+ };
+
+ setMessages(prev => [...prev, assistantMessage]);
+
+ // 流式接收回复
+ let fullContent = '';
+ for await (const chunk of mcpService.streamMessage(input)) {
+ fullContent += chunk;
+ setStreamingMessage(fullContent);
+ }
+
+ // 更新最终消息
+ setMessages(prev =>
+ prev.map(msg =>
+ msg.id === assistantMessage.id
+ ? { ...msg, content: fullContent, isStreaming: false }
+ : msg
+ )
+ );
+ setStreamingMessage('');
+ } catch (error) {
+ console.error('Send message error:', error);
+ setMessages(prev => [
+ ...prev,
+ {
+ id: Date.now().toString(),
+ role: 'system',
+ content: '抱歉,发送消息时出错了。请稍后重试。',
+ timestamp: new Date(),
+ },
+ ]);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleToolCall = async (toolName: string) => {
+ // 示例:调用工具
+ try {
+ setIsLoading(true);
+ const result = await mcpService.callTool(toolName, {});
+ console.log('Tool result:', result);
+
+ // 显示工具结果
+ setMessages(prev => [
+ ...prev,
+ {
+ id: Date.now().toString(),
+ role: 'system',
+ content: `工具 ${toolName} 执行结果:${JSON.stringify(result.result, null, 2)}`,
+ timestamp: new Date(),
+ },
+ ]);
+ } catch (error) {
+ console.error('Tool call error:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ // 权限检查
+ if (authLoading) {
+ return (
+
+ );
+ }
+
+ if (!isAuthenticated) {
+ return (
+
+ );
+ }
+
+ if (!canAccessChat) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {/* 侧边栏 - 工具列表 */}
+
+
可用工具
+
+ {tools.map(tool => (
+
handleToolCall(tool.name)}
+ disabled={isLoading}
+ className="w-full text-left p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-50"
+ >
+ {tool.name}
+
+ {tool.description}
+
+
+ ))}
+
+
+ {/* 用户信息 */}
+
+
+
+ {user?.username?.[0]?.toUpperCase()}
+
+
+
{user?.username}
+
{user?.subscription_tier}
+
+
+
+
+
+ {/* 主聊天区域 */}
+
+ {/* 消息列表 */}
+
+ {messages.map(msg => (
+
+
+ {msg.isStreaming ? (
+
+ {streamingMessage || (
+ 思考中...
+ )}
+
+ ) : (
+
{msg.content}
+ )}
+
+ {msg.timestamp.toLocaleTimeString()}
+
+
+
+ ))}
+
+
+
+ {/* 输入区域 */}
+
+
+ setInput(e.target.value)}
+ onKeyPress={e => e.key === 'Enter' && handleSend()}
+ disabled={isLoading}
+ placeholder="输入消息..."
+ className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
+ />
+
+ {isLoading ? '发送中...' : '发送'}
+
+
+
+ {/* 快捷操作 */}
+
+ setInput('/help')}
+ className="text-sm text-blue-600 hover:underline"
+ >
+ 帮助
+
+ setInput('/tools')}
+ className="text-sm text-blue-600 hover:underline"
+ >
+ 查看工具
+
+ mcpService.clearHistory()}
+ className="text-sm text-red-600 hover:underline"
+ >
+ 清空历史
+
+
+
+
+
+ );
+}
+
+// CSS 模块文件需要单独创建
\ No newline at end of file
diff --git a/src/views/AgentChat/neuratalk/components/Chat/index.tsx b/src/views/AgentChat/neuratalk/components/Chat/index.tsx
new file mode 100644
index 00000000..2b6f6cee
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Chat/index.tsx
@@ -0,0 +1,26 @@
+import PanelMessage from "@/components/PanelMessage";
+import Head from "./Head";
+
+type Props = {
+ titleHead?: React.ReactNode;
+ hidePanelMessage?: boolean;
+ children: React.ReactNode;
+};
+
+const Chat = ({ titleHead, hidePanelMessage, children }: Props) => {
+ return (
+
+
+
+ {children}
+
+ {!hidePanelMessage && }
+
+ );
+};
+
+export default Chat;
diff --git a/src/views/AgentChat/neuratalk/components/CodeEditor/index.tsx b/src/views/AgentChat/neuratalk/components/CodeEditor/index.tsx
new file mode 100644
index 00000000..17522a8d
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/CodeEditor/index.tsx
@@ -0,0 +1,107 @@
+import { useState } from "react";
+import { useTheme } from "next-themes";
+import Editor from "@monaco-editor/react";
+import Icon from "@/components/Icon";
+import Button from "@/components/Button";
+
+interface CodeEditorProps {
+ title?: string;
+ language?: string;
+ initialCode?: string;
+ onCodeChange?: (code: string) => void;
+ onGenerate?: () => void;
+ isGenerating?: boolean;
+}
+
+const CodeEditor = ({
+ title = "Code Editor",
+ language = "python",
+ initialCode = "",
+ onCodeChange,
+ onGenerate,
+ isGenerating = false,
+}: CodeEditorProps) => {
+ const [code, setCode] = useState(initialCode);
+ const { theme } = useTheme();
+
+ const handleEditorChange = (value: string | undefined) => {
+ const newCode = value || "";
+ setCode(newCode);
+ onCodeChange?.(newCode);
+ };
+
+ const handleCopyCode = async () => {
+ try {
+ await navigator.clipboard.writeText(code);
+ console.log("Code copied to clipboard!");
+ } catch (err) {
+ console.error("Failed to copy code: ", err);
+ }
+ };
+
+ return (
+
+
+
+ {title}
+
+ Copy Code
+
+
+
+
+
+
+
+
+
+ {onGenerate && (
+
+
+ {isGenerating ? "Generating Code..." : "Generate Code"}
+
+
+ )}
+
+ );
+};
+
+export default CodeEditor;
diff --git a/src/views/AgentChat/neuratalk/components/EditorArticle/index.tsx b/src/views/AgentChat/neuratalk/components/EditorArticle/index.tsx
new file mode 100644
index 00000000..a40e1c90
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/EditorArticle/index.tsx
@@ -0,0 +1,149 @@
+import Icon from "@/components/Icon";
+import Button from "@/components/Button";
+import { useState, useRef, useEffect } from "react";
+
+type Props = {
+ content: React.ReactNode;
+ onBack: () => void;
+};
+
+const EditorArticle = ({ content, onBack }: Props) => {
+ const [isTextSelected, setIsTextSelected] = useState(false);
+ const [selectionPosition, setSelectionPosition] = useState({
+ top: 0,
+ left: 0,
+ });
+ const contentRef = useRef(null);
+
+ const handleTextSelection = () => {
+ const selection = window.getSelection();
+ if (selection && selection.toString().trim().length > 0) {
+ const range = selection.getRangeAt(0);
+ const rect = range.getBoundingClientRect();
+ const contentRect = contentRef.current?.getBoundingClientRect();
+
+ if (contentRect) {
+ setSelectionPosition({
+ top: rect.top - contentRect.top - 50,
+ left: rect.left - contentRect.left + rect.width / 2 - 100,
+ });
+ setIsTextSelected(true);
+ }
+ } else {
+ setIsTextSelected(false);
+ }
+ };
+
+ const handleFormatText = (format: string) => {
+ const selection = window.getSelection();
+ if (selection && selection.rangeCount > 0) {
+ const range = selection.getRangeAt(0);
+ const selectedText = selection.toString();
+
+ if (selectedText) {
+ let formattedText = selectedText;
+
+ switch (format) {
+ case "bold":
+ formattedText = `${selectedText} `;
+ break;
+ case "italic":
+ formattedText = `${selectedText} `;
+ break;
+ case "underline":
+ formattedText = `${selectedText} `;
+ break;
+ case "strikethrough":
+ formattedText = `${selectedText} `;
+ break;
+ }
+
+ range.deleteContents();
+ const tempDiv = document.createElement("div");
+ tempDiv.innerHTML = formattedText;
+ const fragment = document.createDocumentFragment();
+ while (tempDiv.firstChild) {
+ fragment.appendChild(tempDiv.firstChild);
+ }
+ range.insertNode(fragment);
+
+ selection.removeAllRanges();
+ setIsTextSelected(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ document.addEventListener("selectionchange", handleTextSelection);
+ return () => {
+ document.removeEventListener(
+ "selectionchange",
+ handleTextSelection
+ );
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+ Non-Disclosure Agreement Document
+
+
+ Save Document
+
+
+
+ {content}
+ {isTextSelected && (
+
+ handleFormatText("bold")}
+ className="flex justify-center items-center size-7 hover:bg-soft-200 rounded transition-colors"
+ >
+ B
+
+ handleFormatText("italic")}
+ className="flex justify-center items-center size-7 hover:bg-soft-200 rounded transition-colors"
+ >
+ I
+
+ handleFormatText("underline")}
+ className="flex justify-center items-center size-7 hover:bg-soft-200 rounded transition-colors"
+ >
+ U
+
+ handleFormatText("strikethrough")}
+ className="flex justify-center items-center size-7 hover:bg-soft-200 rounded transition-colors"
+ >
+ S
+
+
+ )}
+
+
+ );
+};
+
+export default EditorArticle;
diff --git a/src/views/AgentChat/neuratalk/components/Field/index.tsx b/src/views/AgentChat/neuratalk/components/Field/index.tsx
new file mode 100644
index 00000000..f8e64a7c
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Field/index.tsx
@@ -0,0 +1,89 @@
+import { useState } from "react";
+import Icon from "@/components/Icon";
+
+type FieldProps = {
+ className?: string;
+ classInput?: string;
+ label?: string;
+ textarea?: boolean;
+ type?: string;
+ required?: boolean;
+ isSmall?: boolean;
+};
+
+const Field = ({
+ className,
+ classInput,
+ label,
+ textarea,
+ type,
+ required,
+ isSmall,
+ ...inputProps
+}: FieldProps &
+ React.InputHTMLAttributes &
+ React.TextareaHTMLAttributes) => {
+ const [showPassword, setShowPassword] = useState(false);
+
+ const error = false;
+
+ return (
+
+ {label && (
+
+ {label}
+ {required && * }
+
+ )}
+
+ {textarea ? (
+
+ ) : (
+
+ )}
+ {type === "password" && (
+ setShowPassword(!showPassword)}
+ >
+
+
+ )}
+
+
+ );
+};
+
+export default Field;
diff --git a/src/views/AgentChat/neuratalk/components/FileConverter/Converter/index.tsx b/src/views/AgentChat/neuratalk/components/FileConverter/Converter/index.tsx
new file mode 100644
index 00000000..3e56153e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/FileConverter/Converter/index.tsx
@@ -0,0 +1,44 @@
+import { FadeLoader } from "react-spinners";
+import Image from "@/components/Image";
+
+const Converter = ({}) => {
+ return (
+
+
+
+
+ Converting your file .....
+
+
+
+
+
+
+
+
Docment res.XLS
+
+
+
+
+ );
+};
+
+export default Converter;
diff --git a/src/views/AgentChat/neuratalk/components/FileConverter/File/index.tsx b/src/views/AgentChat/neuratalk/components/FileConverter/File/index.tsx
new file mode 100644
index 00000000..81c5d684
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/FileConverter/File/index.tsx
@@ -0,0 +1,28 @@
+import Image from "@/components/Image";
+
+type Props = {
+ name: string;
+ size: string;
+};
+
+const File = ({ name, size }: Props) => (
+
+);
+
+export default File;
diff --git a/src/views/AgentChat/neuratalk/components/FileConverter/index.tsx b/src/views/AgentChat/neuratalk/components/FileConverter/index.tsx
new file mode 100644
index 00000000..9c850c22
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/FileConverter/index.tsx
@@ -0,0 +1,26 @@
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import File from "./File";
+import Converter from "./Converter";
+
+const FileConverter = () => {
+ return (
+
+
+
+ Convert this file from DOC to XLS please
+
+
+
+
+
+ Sure converting your document to xls now:
+
+
+
+
+ );
+};
+
+export default FileConverter;
diff --git a/src/views/AgentChat/neuratalk/components/Gallery/Preview/index.tsx b/src/views/AgentChat/neuratalk/components/Gallery/Preview/index.tsx
new file mode 100644
index 00000000..719640a4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Gallery/Preview/index.tsx
@@ -0,0 +1,54 @@
+import { useState } from "react";
+import Image from "@/components/Image";
+import ModalView from "@/components/ModalView";
+
+type Props = {
+ className?: string;
+ image: string;
+ index: number;
+};
+
+const Preview = ({ className, image, index }: Props) => {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}
+ >
+
+ {index === 0 && (
+
+ )}
+
+ setOpen(false)}
+ image={image}
+ />
+ >
+ );
+};
+
+export default Preview;
diff --git a/src/views/AgentChat/neuratalk/components/Gallery/index.tsx b/src/views/AgentChat/neuratalk/components/Gallery/index.tsx
new file mode 100644
index 00000000..671e7ac4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Gallery/index.tsx
@@ -0,0 +1,22 @@
+import Preview from "./Preview";
+
+const Gallery = ({}) => {
+ return (
+
+ {[
+ "/images/image-2.jpg",
+ "/images/image-3.jpg",
+ "/images/image-4.jpg",
+ ].map((image, index) => (
+
+ ))}
+
+ );
+};
+
+export default Gallery;
diff --git a/src/views/AgentChat/neuratalk/components/Header/SpecialOffer/index.tsx b/src/views/AgentChat/neuratalk/components/Header/SpecialOffer/index.tsx
new file mode 100644
index 00000000..93af6a6e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Header/SpecialOffer/index.tsx
@@ -0,0 +1,47 @@
+import { useState } from "react";
+import Button from "@/components/Button";
+import Modal from "@/components/Modal";
+import ModalPlan from "@/components/ModalPlan";
+
+const SpecialOffer = ({}) => {
+ const [open, setOpen] = useState(false);
+ const [openModalPlan, setOpenModalPlan] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}
+ />
+ setOpen(false)}
+ >
+ Special Offer
+
+ Upgrade today and get 20% off your first month.
+
+ {
+ setOpen(false);
+ setOpenModalPlan(true);
+ }}
+ >
+ Claim Offer
+
+
+ setOpenModalPlan(false)}
+ />
+ >
+ );
+};
+
+export default SpecialOffer;
diff --git a/src/views/AgentChat/neuratalk/components/Header/index.tsx b/src/views/AgentChat/neuratalk/components/Header/index.tsx
new file mode 100644
index 00000000..b038c5a6
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Header/index.tsx
@@ -0,0 +1,57 @@
+import { useState } from "react";
+import Button from "@/components/Button";
+import ModalPlan from "@/components/ModalPlan";
+import Icon from "@/components/Icon";
+import SpecialOffer from "./SpecialOffer";
+
+type Props = {
+ onOpenSidebar: () => void;
+ onToggleTools: () => void;
+};
+
+const Header = ({ onOpenSidebar, onToggleTools }: Props) => {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+
+
+
+
+
+
+ Chat With AI
+
+
+ Break down lengthy texts into concise summaries to
+ grasp.
+
+
+
+ setOpen(true)}
+ >
+ Upgrade
+
+
+
+
+
+
+ setOpen(false)} />
+ >
+ );
+};
+
+export default Header;
diff --git a/src/views/AgentChat/neuratalk/components/Icon/index.tsx b/src/views/AgentChat/neuratalk/components/Icon/index.tsx
new file mode 100644
index 00000000..5e3cfa21
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Icon/index.tsx
@@ -0,0 +1,116 @@
+type IconsType = {
+ [key: string]: string;
+};
+
+const icons: IconsType = {
+ "add-team":
+ "M7.082 2.71c1.956 0 3.542 1.586 3.542 3.542S9.038 9.793 7.082 9.793 3.54 8.208 3.54 6.252 5.126 2.71 7.082 2.71zm4.166 0c1.956 0 3.542 1.586 3.542 3.542s-1.586 3.542-3.542 3.542c-.345 0-.625-.28-.625-.625s.28-.625.625-.625a2.29 2.29 0 1 0 0-4.583c-.345 0-.625-.28-.625-.625s.28-.625.625-.625zM7.082 3.96a2.29 2.29 0 1 0 0 4.583 2.29 2.29 0 1 0 0-4.583zm1.548 7.083a4.69 4.69 0 0 1 2.678.825c.284.197.354.586.157.87s-.586.354-.87.157c-.56-.388-1.243-.603-1.965-.603H5.534c-1.802 0-3.244 1.331-3.244 2.946 0 .432.402.804.923.804h7.738c.345 0 .625.28.625.625s-.28.625-.625.625H3.213c-1.189 0-2.173-.908-2.173-2.054 0-2.329 2.023-4.196 4.494-4.196h3.095zm7.202 0c.345 0 .625.28.625.625v1.875h1.875c.314 0 .574.231.618.533l.007.092c0 .345-.28.625-.625.625h-1.875v1.875c0 .314-.231.574-.533.618l-.092.007c-.345 0-.625-.28-.625-.625v-1.875h-1.875c-.314 0-.574-.231-.618-.533l-.007-.092c0-.345.28-.625.625-.625h1.875v-1.875c0-.314.231-.574.533-.618l.092-.007z",
+ "ai-chat":
+ "M11.859 1.56c3.818.251 6.856 3.304 7.106 7.131a16.83 16.83 0 0 1 0 2.17c-.25 3.828-3.288 6.88-7.106 7.131-1.222.08-2.497.08-3.718 0-.487-.032-1-.147-1.441-.327l-.465-.183.025.009-.008.008c-.038.031-.107.08-.201.148l-.075.054c-.75.547-1.603.822-2.69.796-.933-.022-1.163-.066-1.434-.525-.277-.468-.206-.665.309-1.631.401-.752.501-1.355.307-1.706-.841-1.251-1.35-2.497-1.433-3.774a16.84 16.84 0 0 1 0-2.17c.25-3.828 3.288-6.88 7.106-7.131a28.68 28.68 0 0 1 3.718 0zM8.224 2.801c-3.186.21-5.727 2.762-5.936 5.97-.043.662-.043 1.348 0 2.01.067 1.03.496 2.08 1.252 3.209.474.851.309 1.847-.269 2.932l-.147.278-.025.047.014.001.093.003.11.003c.804.019 1.386-.168 1.914-.554.552-.404.617-.445.879-.476s.323-.013 1.068.291a3.48 3.48 0 0 0 1.046.236c1.165.077 2.385.077 3.551 0 3.186-.21 5.727-2.762 5.936-5.971a15.6 15.6 0 0 0 0-2.01c-.209-3.208-2.75-5.761-5.936-5.97a27.41 27.41 0 0 0-3.551 0zm.102 4.089c.52 0 .982.33 1.147.819l1.542 4.582a.62.62 0 0 1-.397.787.63.63 0 0 1-.794-.393l-.416-1.233H7.244l-.414 1.233a.63.63 0 0 1-.704.416l-.09-.023a.62.62 0 0 1-.397-.787L7.18 7.709c.165-.489.626-.819 1.147-.819zm4.605 0c.347 0 .628.278.628.622v4.976c0 .343-.281.622-.628.622s-.628-.278-.628-.622V7.512c0-.343.281-.622.628-.622zM8.326 8.235l-.664 1.972H8.99l-.664-1.972z",
+ "ai-programming":
+ "M9.582 4.373c.345 0 .625.28.625.625s-.28.625-.625.625c-4.469 0-5.51.118-6.355.829-.782.658-.929 1.454-.937 4.892v.64c.008 3.438.155 4.234.937 4.892.823.693 1.831.823 6.009.829h.691c4.178-.006 5.186-.136 6.009-.829.805-.678.937-1.503.937-5.212v-.473l-.023-1.766-.01-.23c-.017-.345.249-.638.593-.655s.638.249.655.593l.035 2.046v.485c0 4.147-.158 5.138-1.382 6.168-1.155.973-2.244 1.117-6.811 1.123h-.698c-4.567-.006-5.656-.15-6.811-1.123-1.19-1.002-1.372-1.966-1.381-5.83v-.338c0-4.147.158-5.138 1.382-6.168 1.184-.997 2.299-1.123 7.16-1.123zm1.031 4.199c.327.109.504.463.395.791l-1.667 5c-.109.327-.463.504-.791.395s-.504-.463-.395-.791l1.667-5c.109-.327.463-.504.791-.395zm2.711.953l1.022.881c.722.622.862.78.862 1.259s-.14.637-.862 1.259l-1.022.881c-.261.225-.656.196-.881-.065s-.196-.656.065-.881l1.022-.881.346-.299.018-.013-.018-.014-.248-.214-.098-.085-1.022-.881c-.261-.225-.291-.62-.065-.881s.62-.291.881-.065zm-6.602.065c.225.261.196.656-.065.881l-1.022.881-.346.299-.019.014.019.013.248.214.098.085 1.022.881c.261.225.291.62.065.881s-.62.291-.881.065l-1.022-.881c-.721-.622-.862-.78-.862-1.259s.14-.637.861-1.259l1.022-.881c.261-.225.656-.196.881.065zm9.28-8.142l.215.581c.315.853.405 1.044.556 1.195s.343.241 1.195.556l.581.215c.544.201.544.971 0 1.172l-.581.215c-.853.315-1.044.405-1.195.556s-.241.342-.556 1.195l-.215.581c-.201.544-.971.544-1.172 0l-.215-.581-.336-.852c-.079-.167-.144-.267-.221-.343-.152-.152-.343-.241-1.195-.556l-.581-.215c-.544-.201-.544-.971 0-1.172l.581-.215c.853-.316 1.044-.405 1.195-.556.076-.076.142-.176.221-.343s.147-.341.336-.852l.215-.581c.201-.544.971-.544 1.172 0zm-.588 1.954l-.004.011c-.136.288-.279.506-.468.695-.178.178-.336.296-.603.426l-.102.047.102.048c.234.114.383.218.537.362l.066.064c.189.189.332.406.468.695l.004.011.049-.103a2 2 0 0 1 .362-.537l.064-.066c.178-.178.336-.296.603-.426l.101-.048-.101-.047a2 2 0 0 1-.536-.362l-.066-.064c-.178-.178-.296-.335-.426-.603l-.049-.103z",
+ "ai-search":
+ "M9.168 3.123c.345 0 .625.28.625.625s-.28.625-.625.625A5.21 5.21 0 0 0 3.96 9.582a5.21 5.21 0 0 0 5.208 5.208 5.21 5.21 0 0 0 5.208-5.208c0-.345.28-.625.625-.625s.625.28.625.625a6.43 6.43 0 0 1-1.472 4.104l2.955 2.954c.244.244.244.64 0 .884s-.64.244-.884 0l-2.955-2.954a6.43 6.43 0 0 1-4.103 1.471A6.46 6.46 0 0 1 2.71 9.582a6.46 6.46 0 0 1 6.458-6.458zm4.337-.425l.215.581c.315.853.405 1.044.556 1.195s.343.241 1.195.556l.581.215c.544.201.544.971 0 1.172l-.581.215c-.853.316-1.044.405-1.195.556s-.241.342-.556 1.195l-.215.581c-.201.544-.971.544-1.172 0l-.215-.581-.336-.852c-.079-.167-.144-.267-.221-.343-.152-.152-.343-.241-1.195-.556l-.581-.215c-.544-.201-.544-.971 0-1.172l.581-.215c.853-.316 1.044-.405 1.195-.556s.241-.343.556-1.195l.215-.581c.201-.544.971-.544 1.172 0zm-.587 1.955l-.047.102c-.13.267-.248.424-.426.603s-.336.296-.603.426l-.102.047.102.048c.234.114.383.218.537.362l.066.064c.189.189.332.406.468.695l.004.011.049-.103a2 2 0 0 1 .362-.537l.064-.066c.178-.178.335-.296.603-.426l.101-.048-.101-.047a2 2 0 0 1-.537-.362l-.066-.064c-.178-.178-.296-.335-.426-.603l-.048-.102z",
+ "alert-circle":
+ "M10 1a9 9 0 1 1 0 18 9 9 0 1 1 0-18zm0 1.256c-4.277 0-7.744 3.467-7.744 7.744S5.723 17.744 10 17.744s7.744-3.467 7.744-7.744S14.277 2.256 10 2.256zm-.008 9.419a.84.84 0 0 1 .847.837c0 .462-.375.837-.837.837a.84.84 0 0 1-.847-.837c0-.462.375-.837.837-.837zm.007-5.651a.63.63 0 0 1 .628.628V10a.63.63 0 0 1-.628.628.63.63 0 0 1-.628-.628V6.651a.63.63 0 0 1 .628-.628z",
+ analytic:
+ "M10.366 1.5c4.542.008 5.645.182 6.798 1.336C18.348 4.02 18.5 5.15 18.5 10v.366c-.008 4.542-.182 5.645-1.335 6.798C15.98 18.348 14.85 18.5 10 18.5h-.366c-4.542-.008-5.645-.182-6.798-1.336S1.508 14.905 1.5 10.348v-.714c.008-4.542.182-5.645 1.336-6.798S5.095 1.508 9.652 1.5h.714zM10 2.744c-4.434 0-5.45.137-6.285.972S2.744 5.566 2.744 10s.137 5.449.972 6.285 1.85.972 6.285.972h.352c4.137-.008 5.12-.159 5.932-.971.835-.835.971-1.851.971-6.285v-.352c-.008-4.137-.159-5.12-.971-5.932-.835-.835-1.851-.972-6.285-.972zm-4.146 9.951a.62.62 0 0 1 .622.622v1.658a.62.62 0 1 1-1.244 0v-1.658a.62.62 0 0 1 .622-.622zM10 11.866a.62.62 0 0 1 .622.622v2.488a.62.62 0 1 1-1.244 0v-2.488a.62.62 0 0 1 .622-.622zm4.146-1.658a.62.62 0 0 1 .622.622v4.146a.62.62 0 1 1-1.244 0v-4.146a.62.62 0 0 1 .622-.622zm.194-5.07l.411 1.359a.62.62 0 0 1-1.191.36l-.13-.431-.118.168c-1.953 2.665-4.861 3.648-7.999 3.61l-.315-.007a.62.62 0 1 1 .041-1.243c2.868.096 5.503-.727 7.24-3.056l.084-.118-.611.099a.62.62 0 0 1-.689-.417l-.024-.098a.62.62 0 0 1 .515-.713l1.576-.253c.47-.06 1.023.248 1.21.741z",
+ archive:
+ "M16.971 2.199C18 3.229 18.13 4.194 18.13 8.332v3.333c0 4.137-.13 5.103-1.159 6.132-1.001 1.001-1.941 1.151-5.795 1.159H8.834c-3.854-.008-4.794-.158-5.795-1.159s-1.151-1.941-1.159-5.795V8.332c0-4.137.13-5.103 1.159-6.132C4.04 1.198 4.981 1.048 8.834 1.04h2.004c4.137 0 5.103.13 6.132 1.159zm-.091 8.424H3.13v1.363c.007 3.448.134 4.269.793 4.928s1.479.786 4.928.793h2.308c3.448-.007 4.269-.134 4.928-.793.679-.679.793-1.529.793-5.248v-1.042zm-4.375 2.917c.345 0 .625.28.625.625s-.28.625-.625.625h-5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h5zM11.159 2.29H8.851c-3.448.007-4.269.134-4.928.793s-.786 1.479-.793 4.928v1.362h13.75V8.332c0-3.719-.114-4.569-.793-5.248-.639-.639-1.43-.778-4.621-.792l-.306-.001zm1.346 2.916c.345 0 .625.28.625.625s-.28.625-.625.625h-5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h5z",
+ arrow: "M12.953 5.127l.684.529 1.499 1.248.708.648C16.922 8.581 17.5 9.332 17.5 10s-.578 1.419-1.656 2.448l-.708.648-1.499 1.248-.684.529c-.286.214-.688.152-.899-.138a.66.66 0 0 1 .136-.912l.655-.507 1.447-1.204.67-.613.809-.847H3.143c-.355 0-.643-.292-.643-.652s.288-.652.643-.652h12.63a11.94 11.94 0 0 0-.81-.847l-.67-.613-1.447-1.204-.655-.507a.66.66 0 0 1-.136-.912c.211-.29.613-.352.899-.138z",
+ api: "M17.201 2.802c1.161 1.161 1.334 2.27 1.342 6.849v.7c-.008 4.579-.181 5.688-1.342 6.849s-2.27 1.334-6.849 1.342h-.7c-4.579-.008-5.688-.181-6.849-1.342s-1.334-2.27-1.342-6.849v-.35c0-4.874.153-6.009 1.342-7.199 1.161-1.161 2.27-1.334 6.849-1.342h.35c4.874 0 6.009.153 7.199 1.342zm-6.863-.092h-.672c-4.172.007-5.162.158-5.979.976-.839.839-.976 1.859-.976 6.315v.336c.007 4.172.158 5.162.976 5.979s1.807.969 5.979.976h.672c4.172-.007 5.162-.158 5.979-.976s.969-1.807.976-5.979v-.672c-.007-4.172-.158-5.162-.976-5.979-.796-.796-1.755-.96-5.657-.975l-.323-.001zM6.829 7.261l1.562 3.75.521 1.25c.133.319-.018.685-.337.817s-.685-.018-.817-.337l-.361-.865H5.451l-.273.823c-.098.295-.395.468-.692.42l-.099-.024c-.327-.109-.504-.463-.395-.791l.417-1.25 1.25-3.75c.183-.548.948-.576 1.17-.043zm5.257-.385c1.035 0 1.875.839 1.875 1.875s-.84 1.875-1.875 1.875h-1.042v1.875c0 .314-.231.574-.533.618l-.092.007c-.345 0-.625-.28-.625-.625V8.085c0-.278.004-.343.051-.488a1.04 1.04 0 0 1 .669-.669c.146-.047.211-.051.488-.051h1.083zm3.333 0c.345 0 .625.28.625.625v5c0 .345-.28.625-.625.625s-.625-.28-.625-.625v-5c0-.345.28-.625.625-.625zM6.316 9.283l-.448 1.344h1.008l-.56-1.344zm5.77-1.156h-1.042v1.25h1.042c.345 0 .625-.28.625-.625s-.28-.625-.625-.625z",
+ bell: "M10.005 1.04c1.085 0 1.875.517 1.875 1.563 0 .389-.112.787-.306 1.135 2.625.668 4.608 2.98 4.756 5.804l.017.38.005.12c.053 1.276.206 1.8.759 2.214.641.481 1.018 1.235 1.018 2.037 0 1.185-.938 2.164-2.125 2.164h-2.938c-.29 1.426-1.551 2.5-3.062 2.5s-2.773-1.073-3.062-2.5H4.005c-1.187 0-2.125-.98-2.125-2.164 0-.801.377-1.556 1.018-2.037.553-.415.706-.939.759-2.214l.005-.12.017-.38c.149-2.824 2.131-5.136 4.757-5.805-.194-.347-.307-.744-.307-1.133 0-1.045.79-1.562 1.875-1.562zm1.768 15.417H8.237c.257.728.952 1.25 1.768 1.25s1.511-.522 1.768-1.25zM10.019 4.79h-.014l-.014-.001-.21.006c-2.602.113-4.715 2.187-4.853 4.812l-.016.364-.005.122c-.068 1.626-.309 2.45-1.258 3.163-.326.245-.518.629-.518 1.037 0 .506.391.914.875.914h12c.484 0 .875-.408.875-.914 0-.408-.192-.792-.518-1.037-.95-.712-1.191-1.536-1.258-3.163l-.005-.122-.016-.364c-.142-2.696-2.365-4.81-5.063-4.817zm-.014-2.5c-.478 0-.625.096-.625.313 0 .435.366.93.619.937l.012-.001.054-.008c.248-.068.565-.524.565-.929 0-.216-.147-.312-.625-.312z",
+ browser:
+ "M17.201 2.802c1.161 1.161 1.334 2.27 1.342 6.849v.7c-.008 4.579-.181 5.688-1.342 6.849s-2.27 1.334-6.849 1.342h-.7c-4.579-.008-5.688-.181-6.849-1.342s-1.334-2.27-1.342-6.849v-.35c0-4.874.153-6.009 1.342-7.199 1.161-1.161 2.27-1.334 6.849-1.342h.35c4.874 0 6.009.153 7.199 1.342zm.08 5.323L2.723 8.125l-.013 1.876v.336c.007 4.172.158 5.162.976 5.979s1.807.969 5.979.976h.672c4.172-.007 5.162-.158 5.979-.976s.969-1.807.976-5.979v-.672l-.012-1.54zM10.338 2.71h-.672c-4.172.007-5.162.158-5.979.976-.592.592-.835 1.274-.926 3.189l14.483.001c-.092-1.915-.334-2.597-.926-3.189-.796-.796-1.755-.96-5.657-.975l-.323-.001zM5.842 4.168c.46 0 .833.373.833.833s-.373.833-.833.833c-.468 0-.841-.373-.841-.833s.373-.833.833-.833zm3.334 0c.46 0 .833.373.833.833s-.373.833-.833.833c-.468 0-.841-.373-.841-.833s.373-.833.833-.833z",
+ build: "M11.841 17H3.25 1.614C1.275 17 1 16.723 1 16.382s.275-.618.614-.618h1.023v-10.5c0-.546.196-1.072.549-1.482l.11-.119C3.717 3.239 4.29 3 4.886 3h5.318c.597 0 1.169.239 1.591.663s.659 1.001.659 1.601V6.5h2.659a2.24 2.24 0 0 1 1.472.552l.119.111c.422.425.659 1.001.659 1.601v7h1.023c.311 0 .567.232.608.534l.006.084c0 .341-.275.618-.614.618H16.75h-4.909zm.614-1.235h3.682v-7c0-.234-.079-.46-.223-.641l-.077-.087a1.02 1.02 0 0 0-.723-.302h-2.659v8.029zm-2.25-11.529H4.886a1.02 1.02 0 0 0-.723.302c-.192.193-.3.455-.3.728v10.5h7.364V7.118 5.265c0-.273-.108-.535-.3-.728a1.02 1.02 0 0 0-.723-.302zm-1.636 6.176c.339 0 .614.277.614.618s-.275.618-.614.618H6.523c-.339 0-.614-.277-.614-.618s.275-.618.614-.618h2.045zm0-3.294c.339 0 .614.277.614.618s-.275.618-.614.618H6.523c-.339 0-.614-.277-.614-.618s.275-.618.614-.618h2.045z",
+ burger: "M3.333 5c-.46 0-.833.373-.833.833s.373.833.833.833h13.333c.46 0 .833-.373.833-.833S17.127 5 16.667 5H3.333zm0 4.167c-.46 0-.833.373-.833.833s.373.833.833.833h13.333c.46 0 .833-.373.833-.833s-.373-.833-.833-.833H3.333zm0 4.167c-.46 0-.833.373-.833.833s.373.833.833.833h13.333c.46 0 .833-.373.833-.833s-.373-.833-.833-.833H3.333z",
+ calendar:
+ "M13.333.66a1 1 0 0 1 .974.771l.01.063.683-.001a3.5 3.5 0 0 1 3.495 3.308l.005.192v2.5 8.333a3.5 3.5 0 0 1-3.5 3.5H5a3.5 3.5 0 0 1-3.5-3.5V7.493v-2.5a3.5 3.5 0 0 1 3.5-3.5l.682.001.011-.063A1 1 0 0 1 6.55.667L6.667.66a1 1 0 0 1 .974.771l.011.063h4.697l.012-.063a1 1 0 0 1 .857-.764l.117-.007zM16.5 8.493h-13v7.334a1.5 1.5 0 0 0 1.356 1.493l.144.007h10a1.5 1.5 0 0 0 1.5-1.5V8.493zm-2.193-4.937a1 1 0 0 1-1.947 0l-.012-.063H7.651l-.011.063a1 1 0 0 1-.857.764l-.117.007a1 1 0 0 1-.974-.771l-.011-.063H5a1.5 1.5 0 0 0-1.493 1.356l-.007.144v1.5h13v-1.5A1.5 1.5 0 0 0 15.144 3.5L15 3.493h-.683l-.01.063z",
+ calculator:
+ "M17.177 2.664c1.21 1.089 1.366 2.132 1.366 6.546v1.583c0 4.414-.156 5.457-1.366 6.546-1.158 1.042-2.254 1.197-6.826 1.204h-.699c-4.572-.007-5.668-.162-6.826-1.204-1.179-1.061-1.357-2.077-1.366-6.205V9.21c0-4.414.156-5.457 1.366-6.546C3.984 1.622 5.08 1.467 9.652 1.46h.349c4.866 0 5.989.136 7.175 1.204zm-6.839.046h-.673c-4.18.007-5.182.144-6.003.883S2.71 5.227 2.71 9.21v1.908c.008 3.708.156 4.576.952 5.292.821.738 1.823.876 6.003.883h.673c4.18-.007 5.182-.144 6.003-.883s.952-1.634.952-5.617V9.21c0-3.983-.134-4.88-.952-5.617-.799-.719-1.77-.869-5.679-.882l-.323-.001zm-1.647 8.444l.087.072c.244.244.244.64 0 .884l-1.017 1.016 1.017 1.017c.217.217.241.554.072.797l-.072.087c-.244.244-.64.244-.884 0L6.877 14.01l-1.016 1.017c-.217.217-.554.241-.797.072l-.087-.072c-.244-.244-.244-.64 0-.884l1.016-1.017-1.016-1.016c-.217-.217-.241-.554-.072-.797l.072-.087c.244-.244.64-.244.884 0l1.016 1.016 1.017-1.016c.217-.217.554-.241.797-.072zm6.311 2.806c.345 0 .625.28.625.625s-.28.625-.625.625h-3.333c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333zm0-2.5c.345 0 .625.28.625.625s-.28.625-.625.625h-3.333c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333zm-1.667-7.083c.345 0 .625.28.625.625l-.001 1.041h1.042c.314 0 .574.231.618.533l.007.092c0 .345-.28.625-.625.625H13.96l.001 1.042c0 .314-.231.574-.533.618l-.092.007c-.345 0-.625-.28-.625-.625l-.001-1.042h-1.041c-.314 0-.574-.231-.618-.533l-.007-.092c0-.345.28-.625.625-.625h1.041l.001-1.041c0-.314.231-.574.533-.618l.092-.007zm-5 1.667c.345 0 .625.28.625.625s-.28.625-.625.625H5.002c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333z",
+ chat: "M12.998 9.454l1.4.824v4.506c0 1.839-1.522 3.346-3.419 3.346a3.44 3.44 0 0 1-2.579-1.149l.056-.031 4.219-2.39a.48.48 0 0 0 .242-.408l.081-4.698zm-9.957 2.674l.074.043 4.219 2.39a.48.48 0 0 0 .464.004l4.195-2.285-.027 1.584-3.981 2.255c-1.64.929-3.734.374-4.676-1.226-.514-.874-.581-1.88-.268-2.764zm9.395-5.715l3.987 2.259c1.635.926 2.188 2.97 1.25 4.565a3.41 3.41 0 0 1-2.32 1.617v-.034-4.814a.48.48 0 0 0-.236-.412l-4.095-2.411 1.413-.769zm-7.78-1.255l-.001 4.848a.48.48 0 0 0 .235.412l2.42 1.425.032.019 1.644.968-1.413.77-3.987-2.259c-1.635-.926-2.188-2.97-1.25-4.565a3.41 3.41 0 0 1 2.32-1.617zm5.388 2.558l2.007 1.181-.039 2.283-2.047 1.115-1.919-1.13V8.803l1.998-1.088zM9.031 1.88a3.44 3.44 0 0 1 2.578 1.148l-.057.032-4.218 2.39a.48.48 0 0 0-.242.416v4.737l-1.479-.871V5.226c0-1.839 1.522-3.346 3.419-3.346zm7.667 3.238c.514.874.581 1.879.268 2.764l-.072-.042-4.219-2.39a.48.48 0 0 0-.464-.004L8.047 7.715V6.144l3.976-2.252c1.64-.929 3.734-.374 4.676 1.226z",
+ check: "M15.377 4.75l.904.863-8.75 9.167-.442.463-.452-.452-2.917-2.917.884-.884 2.464 2.464z",
+ chevron:
+ "M10.003 10.782l3.712-3.712 1.06 1.06-4.773 4.773L5.23 8.131l1.061-1.06z",
+ "chevron-circle":
+ "M10 1a9 9 0 1 1 0 18 9 9 0 1 1 0-18zm0 1.256c-4.277 0-7.744 3.467-7.744 7.744S5.723 17.744 10 17.744s7.744-3.467 7.744-7.744S14.277 2.256 10 2.256zm-.816 3.947l.126.126.279.286c.302.314.603.642.886.969a16.53 16.53 0 0 1 .42.505c.639.802.989 1.398.989 1.911s-.35 1.109-.989 1.911a16.53 16.53 0 0 1-.42.505c-.283.327-.584.655-.886.969l-.279.286-.126.126a.63.63 0 0 1-.888-.008.63.63 0 0 1 .008-.888l.116-.116.263-.27a23.74 23.74 0 0 0 .841-.92 15.29 15.29 0 0 0 .388-.466c.447-.561.715-1.018.715-1.129s-.268-.567-.715-1.129c-.119-.149-.249-.305-.388-.466-.267-.309-.554-.621-.841-.92l-.263-.27-.116-.116a.63.63 0 0 1-.008-.888.63.63 0 0 1 .888-.008z",
+ close: "M3.684 3.684a.63.63 0 0 1 .89 0l5.425 5.427 5.427-5.427a.63.63 0 0 1 .802-.073l.087.073a.63.63 0 0 1 0 .89l-5.427 5.425 5.427 5.427a.63.63 0 0 1 .073.802l-.073.087a.63.63 0 0 1-.89 0l-5.427-5.427-5.425 5.427a.63.63 0 0 1-.802.073l-.087-.073a.63.63 0 0 1 0-.89l5.427-5.427-5.427-5.425a.63.63 0 0 1-.073-.802l.073-.087z",
+ comment:
+ "M17.797 2.599c1.001 1.001 1.152 1.941 1.159 5.795v1.092c-.008 3.854-.158 4.794-1.159 5.795-1.029 1.03-1.995 1.159-6.118 1.159-.449.01-.773.044-1.078.113-.618.142-1.145.365-2.181.88l-.2.1-.227.113-.059.029-.037.018c-1.947.95-2.345 1.078-3.009.595-.531-.395-.671-.987-.575-1.784l.022-.168-.114-.022c-.755-.166-1.379-.459-1.865-.885l-.157-.147C1.198 14.28 1.048 13.339 1.04 9.486v-.754c0-4.137.13-5.103 1.159-6.132C3.2 1.598 4.141 1.448 7.994 1.44h3.671c4.137 0 5.103.13 6.132 1.159zm-5.811.091H8.011c-3.448.007-4.269.134-4.928.793s-.786 1.479-.793 4.928v1.058c.007 3.448.134 4.269.793 4.928.314.314.758.543 1.342.681l.196.041.009-.031.063-.223.02-.07.09-.356c.069-.338.4-.556.738-.487s.556.4.487.738l-.11.439-.134.475-.148.582c-.142.647-.113 1.015-.006 1.095.057.041.412-.074 1.72-.712l.514-.254c1.121-.558 1.713-.808 2.459-.98.397-.09.803-.133 1.343-.145 3.719 0 4.569-.114 5.248-.793.659-.659.786-1.479.793-4.928V8.411c-.007-3.448-.134-4.269-.793-4.928-.639-.639-1.43-.778-4.621-.792l-.306-.001zm1.346 7.916c.345 0 .625.28.625.625s-.28.625-.625.625H6.665c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h6.667zM9.998 6.44c.345 0 .625.28.625.625s-.28.625-.625.625H6.665c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333z",
+ database:
+ "M10.002 1.04c3.911 0 7.135 1.174 7.286 2.991l.006.134v11.667c0 1.893-3.285 3.125-7.292 3.125S2.71 17.725 2.71 15.832V4.165c0-1.893 3.285-3.125 7.292-3.125zm0 12.083a17.49 17.49 0 0 1-2.707-.202l.001 1.244c0 .345-.28.625-.625.625s-.625-.28-.625-.625l-.001-1.502c-.824-.215-1.535-.5-2.086-.845l.001 4.014c0 .868 2.685 1.875 6.042 1.875s6.042-1.007 6.042-1.875l.001-4.014c-1.314.824-3.538 1.305-6.043 1.305zm6.043-7.139c-1.314.824-3.537 1.305-6.043 1.305a17.49 17.49 0 0 1-2.707-.202l.001 1.244c0 .345-.28.625-.625.625s-.625-.28-.625-.625L6.045 6.83c-.824-.215-1.535-.5-2.085-.845l-.001 4.013c.001.869 2.686 1.875 6.043 1.875s6.042-1.007 6.042-1.875h.001V5.985zM10.002 2.29c-3.357 0-6.042 1.007-6.042 1.875S6.644 6.04 10.002 6.04s6.042-1.007 6.042-1.875-2.684-1.875-6.042-1.875z",
+ document:
+ "M16.517 2.199c1.001 1.001 1.151 1.941 1.159 5.795v.754c0 .345-.28.625-.625.625s-.625-.28-.625-.625v-.737c-.007-3.448-.134-4.269-.793-4.928s-1.479-.786-4.928-.793H9.231c-3.448.007-4.269.134-4.928.793s-.786 1.479-.793 4.928v4.377c.006 2.984.106 3.709.614 4.329.113.137.238.263.375.376.641.526 1.393.615 4.635.615.345 0 .625.28.625.625s-.28.625-.625.625c-3.607 0-4.455-.1-5.428-.899-.2-.165-.384-.348-.549-.549-.773-.942-.891-1.767-.898-5.097v-4.08c0-4.137.13-5.103 1.159-6.132C4.42 1.198 5.361 1.048 9.214 1.04h1.171c4.137 0 5.103.13 6.132 1.159zm-1.966 8.841c1.671 0 3.125 1.53 3.125 3.125v2.5c0 .345-.28.625-.625.625s-.625-.28-.625-.625v-2.5c0-.918-.909-1.875-1.875-1.875s-1.875.957-1.875 1.875v2.917c0 .345.28.625.625.625s.625-.28.625-.625v-2.917c0-.345.28-.625.625-.625s.625.28.625.625v2.917c0 1.035-.84 1.875-1.875 1.875s-1.875-.84-1.875-1.875v-2.917c0-1.595 1.454-3.125 3.125-3.125zm-3.333-1.667c.345 0 .625.28.625.625s-.28.625-.625.625h-5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h5zm2.5-4.167c.345 0 .625.28.625.625s-.28.625-.625.625h-7.5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h7.5z",
+ "document-check":
+ "M8.354 1.06c.345.015.613.306.598.651s-.306.613-.651.598c-1-.042-1.963-.012-2.834.064l-.785.086C3.253 2.562 2.3 3.443 2.3 5.804v.825.295l-.001.632-.001.701-.001.4-.001.423v.163l-.004 2.069-.001.91v.201.373.087l.001.555v.142l.001.263.008.945c0 1.33.812 2.721 2.146 2.799 2.742.16 7.29.17 9.284 0 .964-.054 1.976-.712 2.125-1.995.167-1.437.209-2.545.197-3.686l-.002-.166v-.06c0-.345.28-.625.625-.625s.625.28.625.625v.052l.002.161c.013 1.189-.032 2.347-.206 3.843-.233 2-1.794 3.014-3.278 3.097-2.044.175-6.649.164-9.446.001-2.148-.125-3.323-2.138-3.323-4.039l-.008-.946-.001-.264v-.07l-.001-1.289.001-.912.001-.526.003-1.549v-.163l.001-.423.001-.399.001-.7.001-.631v-.149l.001-.97c0-3.061 1.497-4.445 3.495-4.586l.813-.09a23.28 23.28 0 0 1 2.996-.068zm4.128 12.495c.345 0 .625.28.625.625s-.28.625-.625.625H5.815c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h6.667zm-3.333-3.333c.345 0 .625.28.625.625s-.28.625-.625.625H5.815c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333zm5.011-9.167c2.648 0 4.796 2.145 4.796 4.792s-2.147 4.792-4.796 4.792-4.796-2.145-4.796-4.792 2.147-4.792 4.796-4.792zm0 1.25c-1.958 0-3.546 1.586-3.546 3.542s1.587 3.542 3.546 3.542 3.546-1.586 3.546-3.542-1.587-3.542-3.546-3.542zm2.244 2.083c.115.325-.055.683-.38.798-.073.026-.155.065-.244.118-.305.183-.657.503-1.022.919a10.85 10.85 0 0 0-.66.836l-.255.373c-.261.41-.869.379-1.087-.056a5.52 5.52 0 0 0-.514-.842l-.202-.245c-.244-.244-.244-.64 0-.884s.64-.244.884 0a3.8 3.8 0 0 1 .387.466l.054.08.197-.249.257-.304c.444-.505.883-.906 1.32-1.167.156-.093.312-.169.468-.224.325-.115.683.055.798.38z",
+ dots: "M10.005 8.96a1.04 1.04 0 1 1 0 2.083c-.583 0-1.049-.466-1.049-1.042A1.04 1.04 0 0 1 9.998 8.96h.008zm-.006 5a1.04 1.04 0 1 1 0 2.083c-.583 0-1.049-.466-1.049-1.042a1.04 1.04 0 0 1 1.042-1.042h.008zm.013-10a1.04 1.04 0 1 1 0 2.083c-.583 0-1.049-.466-1.049-1.042a1.04 1.04 0 0 1 1.042-1.042h.008z",
+ edit: "M4.998 11.873c.345 0 .625.28.625.625s-.28.625-.625.625H3.123c-.46 0-.833.373-.833.833s.373.833.833.833h7.917c1.151 0 2.083.933 2.083 2.083s-.933 2.083-2.083 2.083H9.165c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h1.875c.46 0 .833-.373.833-.833s-.373-.833-.833-.833H3.123c-1.151 0-2.083-.933-2.083-2.083s.933-2.083 2.083-2.083h1.875zM16.597 1.218l.125.06c.268.143.429.281.94.788l.274.274c.566.57.707.742.845 1.061a2.17 2.17 0 0 1 0 1.719c-.148.343-.3.516-.983 1.199l-4.185 4.185c-1.108 1.108-1.434 1.41-1.914 1.721a3.84 3.84 0 0 1-.453.254c-.537.254-1.079.37-2.112.484l-.916.094-.657.065c-.392.039-.722-.291-.683-.683l.065-.657.094-.916c.114-1.033.23-1.575.484-2.112.311-.657.627-1.019 1.975-2.367l4.32-4.319c.51-.508.671-.645.94-.788l.125-.06a2.17 2.17 0 0 1 1.719 0zm-1.224 1.148l-.033.016c-.12.064-.248.176-.659.585L10.2 7.447c-1.08 1.084-1.339 1.391-1.551 1.84-.179.379-.271.81-.371 1.714l-.075.732-.008.068.069-.006.566-.057.166-.018c.905-.1 1.335-.192 1.714-.371.104-.049.204-.105.306-.172.375-.243.678-.524 1.711-1.557l4.185-4.185c.54-.54.663-.68.719-.811a.92.92 0 0 0 0-.728c-.052-.121-.16-.249-.602-.693l-.237-.237c-.411-.408-.539-.521-.659-.585l-.033-.016a.92.92 0 0 0-.728 0z",
+ exchange:
+ "M5.838 3.143h.017l.034.003.042.004.014.002.015.003.029.008.03.006.013.005.02.007.026.011.024.009.017.01.021.009.016.011.023.013.019.014.023.016.016.014.011.008.018.018.029.027.003.005.012.012c.038.044.07.093.095.147l.031.082.005.016.008.042.008.032v.009l.003.013v.028l.003.042v2.904c0 .345-.28.625-.625.625s-.625-.28-.625-.625V5.076l-.073.07C3.936 6.351 3.206 7.974 3.136 9.727l-.006.278c0 3.797 3.078 6.875 6.875 6.875.519 0 1.031-.058 1.529-.17.337-.076.671.135.748.471s-.135.671-.471.748c-.588.133-1.192.201-1.805.201-4.487 0-8.125-3.638-8.125-8.125 0-2.059.772-3.987 2.102-5.455l.147-.158-1.207.001c-.314 0-.574-.231-.618-.533l-.007-.092c0-.345.28-.625.625-.625h2.917zm4.167-1.263c4.487 0 8.125 3.638 8.125 8.125 0 2.065-.777 3.999-2.115 5.469l-.148.156h1.221c.314 0 .574.231.618.533l.007.092c0 .345-.28.625-.625.625h-2.936l-.018-.001h-.01l-.022-.003-.042-.003-.022-.005-.029-.006-.037-.008-.021-.009-.014-.003-.023-.011-.025-.009-.021-.012-.019-.008-.016-.011-.021-.012-.027-.02-.017-.011-.013-.012-.013-.009-.037-.037-.01-.009-.006-.007-.008-.009-.042-.054-.007-.01a.64.64 0 0 1-.046-.083l-.013-.035-.018-.047-.004-.013-.008-.035-.008-.041-.002-.012-.001-.012-.002-.042-.002-.026v-2.917c0-.345.28-.625.625-.625s.625.28.625.625v1.614l.044-.04c1.235-1.211 1.986-2.859 2.054-4.639l.005-.268c0-3.797-3.078-6.875-6.875-6.875a6.9 6.9 0 0 0-1.528.17c-.337.076-.671-.135-.748-.471s.135-.671.471-.748a8.15 8.15 0 0 1 1.805-.201z",
+ "eye-hide":
+ "M2.94 2.063l15 15c.244.244.244.64 0 .884s-.64.244-.884 0l-2.768-2.767c-1.358.826-2.793 1.283-4.29 1.283-3.415 0-6.275-2.233-8.462-5.3-.395-.554-.496-.748-.496-1.159s.101-.604.496-1.159c.865-1.213 1.911-2.365 3.124-3.296L2.057 2.947c-.244-.244-.244-.64 0-.884s.64-.244.884 0zm-.387 7.509c-.238.334-.264.383-.264.433s.026.099.264.433c1.974 2.768 4.545 4.775 7.444 4.775 1.157 0 2.285-.332 3.378-.947l-1.686-1.685c-.507.353-1.114.549-1.751.549-1.693 0-3.066-1.373-3.066-3.066 0-.637.196-1.245.549-1.752l-1.87-1.87c-1.158.864-2.17 1.967-2.999 3.129zm7.444-6.025c3.415 0 6.275 2.232 8.462 5.3.395.554.496.748.496 1.159s-.101.604-.496 1.159c-.518.726-1.127 1.461-1.823 2.151-.245.243-.641.242-.884-.003s-.242-.641.003-.884a15.49 15.49 0 0 0 1.686-1.989c.238-.334.264-.383.264-.433s-.026-.099-.264-.433c-1.974-2.768-4.545-4.775-7.445-4.775-.661 0-1.314.109-1.958.318-.328.107-.681-.073-.788-.401s.073-.681.401-.788c.766-.249 1.549-.379 2.345-.379zm-1.875 6.518c0 1.003.813 1.816 1.816 1.816a1.81 1.81 0 0 0 .843-.207L8.33 9.221a1.81 1.81 0 0 0-.207.843z",
+ flash: "M9.691 1.575c.841-1.08 2.429-.403 2.429.943v5.794c0 .138.074.221.124.221h2.837c1.194 0 1.785 1.477 1.055 2.414l-5.832 7.486c-.841 1.08-2.429.403-2.429-.943v-5.794c0-.138-.074-.221-.124-.221H4.915c-1.194 0-1.785-1.477-1.055-2.414l5.832-7.486zm1.179.943c0-.214-.122-.266-.193-.175L4.845 9.829c-.122.156-.026.396.069.396h2.837c.777 0 1.374.674 1.374 1.471v5.794c0 .214.122.266.193.175l5.832-7.486c.122-.156.026-.396-.069-.396h-2.837c-.777 0-1.374-.674-1.374-1.471V2.518z",
+ folder: "M16.971 2.199C18 3.229 18.13 4.194 18.13 8.332v3.333c0 4.137-.13 5.103-1.159 6.132-1.001 1.001-1.941 1.152-5.795 1.159H8.834c-3.854-.008-4.794-.158-5.795-1.159s-1.151-1.941-1.159-5.795V8.332c0-4.137.13-5.103 1.159-6.132C4.04 1.198 4.981 1.048 8.834 1.04h2.004c4.137 0 5.103.13 6.132 1.159zm-.091 8.424H3.13v1.363c.007 3.448.134 4.269.793 4.928s1.479.786 4.928.793h2.308c3.448-.007 4.269-.134 4.928-.793.679-.679.793-1.529.793-5.248v-1.042zm-4.375 2.917c.345 0 .625.28.625.625s-.28.625-.625.625h-5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h5zM11.159 2.29H8.851c-3.448.007-4.269.134-4.928.793s-.786 1.479-.793 4.928v1.362h13.75V8.332c0-3.719-.114-4.569-.793-5.248-.639-.639-1.43-.778-4.621-.792l-.306-.001zm1.346 2.916c.345 0 .625.28.625.625s-.28.625-.625.625h-5c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h5z",
+ folders:
+ "M5.865 2a2.31 2.31 0 0 1 1.786.841l1.328 1.621 4.61.001c1.294.004 1.692.04 2.143.249l.085.041a2.69 2.69 0 0 1 1.185 1.165c.25.483.291.84.295 2.192l.001.598c.685.132 1.022.381 1.344.846.618.894.46 1.545-.688 4.355l-.249.609c-.821 2.011-1.078 2.482-1.787 2.952s-1.25.528-3.46.528H5.435c-2.832-.007-3.482-.127-4.079-.99-.303-.439-.42-.819-.324-1.425l.001-9.491c.003-1.376.039-1.741.253-2.231.316-.725.903-1.302 1.64-1.613.5-.211.869-.246 2.281-.249h.657zm8.398 7.795H7.541c-1.91 0-2.353.048-2.761.318s-.617.654-1.326 2.391l-.249.609c-.934 2.288-1.068 2.837-.814 3.205s.827.452 3.345.452h6.975c1.699-.004 2.12-.06 2.509-.318.407-.27.617-.654 1.326-2.391l.249-.609c.934-2.288 1.068-2.837.814-3.205s-.827-.452-3.345-.452zM5.865 3.231h-.648c-1.203.003-1.514.03-1.796.149a1.86 1.86 0 0 0-.984.968c-.121.278-.149.588-.152 1.78l-.001 5.938.009-.021c.821-2.011 1.078-2.482 1.787-2.952.679-.451 1.205-.523 3.192-.528h7.292l1.483.024v-.229c0-1.312-.026-1.626-.159-1.883a1.45 1.45 0 0 0-.638-.628c-.246-.123-.543-.153-1.689-.156H5.83a.62.62 0 0 1-.626-.615.62.62 0 0 1 .626-.615h1.542l-.694-.848c-.17-.207-.413-.34-.678-.374l-.134-.008z",
+ gift: "M6.835 1c1.325 0 2.49.695 3.165 1.748C10.674 1.695 11.84 1 13.165 1h.293c1.149 0 2.081.95 2.081 2.123 0 .78-.264 1.497-.705 2.064l.5-.001c1.076 0 1.325.018 1.694.192a1.76 1.76 0 0 1 .691.57c.255.361.281.596.281 1.54s-.026 1.179-.281 1.539a1.73 1.73 0 0 1-.539.49v2.994c0 3.663-.113 4.519-1.021 5.446S14.411 19 10.821 19H9.179c-3.59 0-4.429-.115-5.338-1.042-.881-.899-1.014-1.731-1.021-5.121l-.001-3.32-.01-.006a1.73 1.73 0 0 1-.528-.484C2.044 8.693 2.005 8.466 2 7.68v-.192c0-.943.026-1.179.281-1.54a1.76 1.76 0 0 1 .691-.57c.345-.162.585-.189 1.49-.192l.705.001c-.442-.567-.705-1.284-.705-2.064C4.462 1.95 5.393 1 6.542 1h.293zM4.05 9.786l.002 2.997c.006 3.014.113 3.728.661 4.286.563.575 1.289.674 4.467.674h.205V9.79H4.462l-.412-.004zm11.9 0l-.412.004h-4.923v7.954h.206c3.179 0 3.904-.099 4.467-.674.545-.556.654-1.267.661-4.252l.002-3.032zm-.617-3.344h.16H4.507c-.709.002-.896.019-1.018.077-.094.044-.165.103-.21.165-.033.047-.049.183-.049.805v.135c.002.507.017.626.048.67.044.063.116.121.21.165.121.057.307.074 1.007.076h10.837c.841 0 1.047-.015 1.178-.077.094-.044.165-.103.209-.165.033-.047.049-.183.049-.805s-.015-.757-.049-.805c-.044-.062-.116-.121-.209-.165-.131-.062-.336-.077-1.178-.077zM6.835 2.256h-.293c-.469 0-.85.388-.85.867 0 1.139.905 2.063 2.022 2.063h1.67l-.001-.338C9.385 3.47 8.321 2.336 6.98 2.26l-.145-.004zm6.623 0h-.293c-1.408 0-2.549 1.165-2.549 2.601v.329h1.67c1.072 0 1.949-.851 2.018-1.927l.004-.136c0-.479-.38-.867-.85-.867z",
+ history:
+ "M9.998 1.04a8.96 8.96 0 0 1 8.958 8.958 8.96 8.96 0 0 1-8.958 8.958c-.345 0-.625-.28-.625-.625s.28-.625.625-.625a7.71 7.71 0 0 0 7.708-7.708A7.71 7.71 0 0 0 9.998 2.29c-3.018 0-5.678 1.751-6.929 4.396l-.085.187h1.181c.314 0 .574.231.618.533l.007.092c0 .345-.28.625-.625.625H2.081c-.422 0-.723-.41-.596-.812C2.65 3.601 6.063 1.04 9.998 1.04zM6.925 17.436a7.41 7.41 0 0 0 .769.301c.328.108.506.461.399.789s-.461.506-.789.399a8.66 8.66 0 0 1-.898-.352c-.314-.144-.452-.514-.308-.828s.514-.452.828-.308zm-2.443-1.775c.236.254.488.493.754.713s.303.614.083.88-.614.303-.88.083c-.308-.255-.6-.531-.873-.825-.235-.253-.22-.648.033-.883s.648-.22.883.033zm-1.653-2.679a8.27 8.27 0 0 0 .399.894c.159.306.039.684-.267.843s-.684.039-.843-.267a9.52 9.52 0 0 1-.459-1.029c-.122-.323.042-.684.365-.805s.684.042.805.365zM9.998 6.04c.345 0 .625.28.625.625V9.74l1.484 1.483c.217.217.241.554.072.797l-.072.087c-.244.244-.64.244-.884 0L9.556 10.44c-.117-.117-.183-.276-.183-.442V6.665c0-.345.28-.625.625-.625zM1.665 9.373c.345 0 .625.28.625.625 0 .261.012.52.035.777.031.344-.222.648-.566.679s-.648-.222-.679-.566c-.027-.294-.04-.591-.04-.89 0-.345.28-.625.625-.625z",
+ "help-circle":
+ "M10 1a9 9 0 1 1 0 18 9 9 0 1 1 0-18zm0 1.256c-4.277 0-7.744 3.467-7.744 7.744S5.723 17.744 10 17.744s7.744-3.467 7.744-7.744S14.277 2.256 10 2.256zm.001 11.093c.462 0 .837.375.837.837s-.375.837-.837.837a.84.84 0 0 1-.845-.837c0-.462.375-.837.837-.837zM10 5.186c1.272 0 2.302 1.031 2.302 2.302 0 .447-.128.876-.365 1.245a5.9 5.9 0 0 1-.307.428l-.277.346c-.543.673-.726.993-.726 1.33v.419a.63.63 0 0 1-.628.628.63.63 0 0 1-.628-.628v-.419c0-.731.279-1.221 1.005-2.119l.262-.327a4.71 4.71 0 0 0 .243-.337 1.04 1.04 0 0 0 .165-.565c0-.578-.469-1.047-1.047-1.047s-1.047.469-1.047 1.047a.63.63 0 0 1-.628.628.63.63 0 0 1-.628-.628c0-1.272 1.031-2.302 2.302-2.302z",
+ envelope:
+ "M12.445 2.53c3.479.085 4.336.229 5.33 1.196.973.946 1.139 1.817 1.207 4.852l.001.063.002.087.001.064v2.419l-.001.064-.002.087-.001.063c-.068 3.035-.234 3.906-1.207 4.852s-1.893 1.11-5.058 1.189l-.272.007c-1.635.04-3.254.04-4.889 0l-.272-.007c-3.165-.078-4.088-.246-5.058-1.189s-1.139-1.817-1.207-4.852l-.001-.063-.002-.086-.001-.064V8.791c.072-3.283.219-4.1 1.212-5.065s1.851-1.111 5.33-1.196h4.889zm5.154 3.728L12.894 8.84c-2.326 1.276-3.462 1.276-5.788 0L2.402 6.258c-.073.588-.107 1.394-.133 2.558v2.367l.001.064.002.086.001.062c.06 2.7.192 3.389.841 4.02s1.383.762 4.2.831l.272.007h4.826l.272-.007c2.817-.07 3.555-.204 4.2-.831s.781-1.32.841-4.02l.001-.063.002-.086.001-.064V8.817l-.001-.064-.002-.086-.001-.063-.128-2.346zM7.587 3.746c-3.11.076-3.809.193-4.472.838a2.12 2.12 0 0 0-.372.465l4.982 2.734c1.942 1.065 2.608 1.065 4.55 0l4.98-2.733c-.1-.174-.221-.321-.37-.465-.663-.645-1.362-.762-4.472-.838a98.85 98.85 0 0 0-4.826 0z",
+ eye: "M10 2.5c3.235 0 6.246 1.833 8.323 5.008.903 1.376.903 3.607.001 4.983C16.246 15.667 13.235 17.5 10 17.5s-6.246-1.833-8.323-5.008c-.903-1.376-.903-3.607-.001-4.983C3.754 4.333 6.765 2.5 10 2.5zm0 1.247c-2.767 0-5.387 1.595-7.243 4.432-.635.967-.635 2.675.001 3.643 1.855 2.836 4.475 4.431 7.242 4.431s5.387-1.595 7.242-4.432c.635-.967.635-2.675-.001-3.643C15.387 5.342 12.767 3.747 10 3.747zm.001 2.659c2.045 0 3.699 1.609 3.699 3.598s-1.654 3.598-3.699 3.598-3.699-1.609-3.699-3.598 1.654-3.598 3.699-3.598zm0 1.247c-1.338 0-2.418 1.051-2.418 2.352s1.08 2.352 2.418 2.352 2.418-1.051 2.418-2.352-1.08-2.352-2.418-2.352z",
+ image: "M17.201 2.802c1.161 1.161 1.334 2.27 1.342 6.849v.7c-.008 4.579-.181 5.688-1.342 6.849s-2.27 1.334-6.849 1.342h-.7c-4.579-.008-5.688-.181-6.849-1.342s-1.334-2.27-1.342-6.849v-.35c0-4.874.153-6.009 1.342-7.199 1.161-1.161 2.27-1.334 6.849-1.342h.35c4.874 0 6.009.153 7.199 1.342zM3.347 12.296c-.206 0-.411.004-.616.015.063 2.553.286 3.338.955 4.007.818.818 1.807.969 5.979.976h.672l1.929-.02c-.591-1.218-1.524-2.301-2.727-3.148-1.739-1.223-3.93-1.873-6.192-1.829zm11.974 1.664c-1.064-.004-2.126.295-3.152.89a8.99 8.99 0 0 1 1.441 2.365c1.554-.109 2.168-.358 2.707-.898.456-.456.705-.966.837-2.052a5.67 5.67 0 0 0-1.833-.305zM10.338 2.71h-.672c-4.172.007-5.162.158-5.979.976-.839.839-.976 1.859-.976 6.315v.336l.003.722-.253.014.875-.028c2.511-.049 4.963.678 6.923 2.057.363.255.705.53 1.025.823 1.288-.806 2.655-1.22 4.04-1.215.647-.001 1.292.091 1.927.274l.044-2.646v-.672c-.007-4.172-.158-5.162-.976-5.979-.796-.796-1.755-.96-5.657-.975l-.323-.001zm3.414 1.666c1.036 0 1.875.839 1.875 1.875s-.839 1.875-1.875 1.875-1.875-.839-1.875-1.875.839-1.875 1.875-1.875zm0 1.25c-.345 0-.625.28-.625.625s.28.625.625.625.625-.28.625-.625-.28-.625-.625-.625z",
+ "image-1":
+ "M18.268 2.336c.672.526.732 1.056.732 3.865v7.598c0 2.809-.06 3.339-.732 3.865-.696.546-1.248.447-4.323-.442a14.23 14.23 0 0 0-7.89 0c-3.076.889-3.627.988-4.323.442-.627-.491-.721-.985-.731-3.333L1 5.919c.005-2.563.083-3.074.732-3.582.696-.546 1.247-.447 4.323.442a14.23 14.23 0 0 0 7.89 0c3.076-.889 3.627-.987 4.323-.442zm-15.75.956c-.198.155-.262.722-.262 2.909v7.598c0 2.187.064 2.754.262 2.909.165.129.771.028 2.86-.569l-.021-.021 1.242-1.289c4.195-4.328 7.214-5.809 11.145-3.864l-.001-5.017c-.005-1.977-.072-2.505-.262-2.654-.173-.135-.832-.018-3.181.661-2.806.811-5.797.811-8.603 0-2.349-.679-3.008-.797-3.181-.661zm5.03 12.341l.398-.059a15.52 15.52 0 0 1 6.356.472c2.349.679 3.008.797 3.181.661.198-.155.262-.722.262-2.909v-1.438c-3.577-2.042-6.163-.879-10.196 3.273zM6.23 5.3c1.04 0 1.884.823 1.884 1.839S7.27 8.978 6.23 8.978s-1.884-.823-1.884-1.839S5.189 5.3 6.23 5.3zm0 1.226a.62.62 0 0 0-.628.613.62.62 0 0 0 .628.613.62.62 0 0 0 .628-.613.62.62 0 0 0-.628-.613z",
+ language:
+ "M17.201 2.802c1.161 1.161 1.334 2.27 1.342 6.849v.7c-.008 4.579-.181 5.688-1.342 6.849s-2.27 1.334-6.849 1.342h-.7c-4.579-.008-5.688-.181-6.849-1.342s-1.334-2.27-1.342-6.849v-.35c0-4.874.153-6.009 1.342-7.199 1.161-1.161 2.27-1.334 6.849-1.342h.35c4.874 0 6.009.153 7.199 1.342zm-6.863-.092h-.672c-4.172.007-5.162.158-5.979.976-.839.839-.976 1.859-.976 6.315v.336c.007 4.172.158 5.162.976 5.979s1.807.969 5.979.976h.672c4.172-.007 5.162-.158 5.979-.976s.969-1.807.976-5.979v-.672c-.007-4.172-.158-5.162-.976-5.979-.796-.796-1.755-.96-5.657-.975l-.323-.001zm-.753 2.5c.345 0 .625.28.625.625v.524h1.875 2.083c.345 0 .625.28.625.625s-.28.625-.625.625h-1.624l-.086.252c-.39 1.061-.984 2.119-1.756 3.175l-.202.269 1.232 1.281c.215.224.231.567.05.808l-.067.076c-.249.239-.644.232-.884-.017l-1.125-1.168-.257.296-1.595 1.641-.435.407c-.254.234-.649.217-.883-.037s-.217-.649.037-.883c.848-.779 1.609-1.556 2.284-2.352l.264-.32-.257.31-.108-.136c-.446-.57-.876-1.187-1.086-1.58l-.061-.122c-.146-.313-.01-.685.302-.831s.685-.01.831.302c.117.25.48.782.877 1.301l.044.056.022-.028c.629-.86 1.126-1.712 1.473-2.553l.057-.148H9.585h-3.75c-.345 0-.625-.28-.625-.625s.28-.625.625-.625H8.96v-.524c0-.314.231-.574.533-.618l.092-.007z",
+ "language-1":
+ "M11.623 1.5c3.539.366 6.07 2.646 7.005 5.283 1.116 5.32-.324 8.502-3.713 10.349-2.052 1.254-7.047 1.303-9.342.236l-.166-.084-3.35 1.174a.71.71 0 0 1-.926-.835l.034-.099L2.4 14.568l-.114-.184C-.911 9.087 2.177 2.136 7.97 1.596l.261-.02.022-.001 3.37-.075zm-.05 1.24l-3.277.078-.218.017C3.1 3.31.469 9.569 3.626 14.153l.191.278-.13.311-.896 2.139 2.468-.865.294-.103.26.17c1.605 1.046 6.655 1.082 8.469-.025 2.929-1.597 4.121-4.232 3.139-8.941-.76-2.132-2.91-4.067-5.848-4.376zm-.907 3.553l-.001.814h2.692v1.244h-.723l-.08.231c-.34.916-.849 1.828-1.505 2.738l-.187.252 1.055 1.104-.912.855-.935-.979-.282.323c-.388.432-.802.858-1.243 1.282l-.449.424-.857-.909c.728-.674 1.383-1.343 1.966-2.03l.266-.324-.242.293-.138-.178c-.363-.473-.704-.97-.884-1.302l-.067-.132 1.141-.519c.098.211.397.654.732 1.097l.012.017.033-.044c.482-.675.871-1.343 1.157-2.004l.079-.198H6.72V7.108h2.69l.001-.814h1.256z",
+ link: "M15.037 2.46a4.85 4.85 0 0 1 0 6.855l-.032.033a4.85 4.85 0 0 1-.801 5.801l-2.388 2.388a4.85 4.85 0 0 1-6.855 0 4.85 4.85 0 0 1 0-6.855l.032-.033a4.85 4.85 0 0 1 .801-5.801L8.181 2.46a4.85 4.85 0 0 1 6.855 0zm-5.971.884L6.677 5.732a3.6 3.6 0 0 0 0 5.087 3.6 3.6 0 0 0 5.087 0l.172-.172c.244-.244.64-.244.884 0s.244.64 0 .884l-.172.172a4.85 4.85 0 0 1-6.855 0l-.041-.042-.053.058a3.6 3.6 0 0 0 5.233 4.934l2.389-2.389a3.6 3.6 0 0 0 0-5.087 3.6 3.6 0 0 0-5.087 0l-.172.172c-.244.244-.64.244-.884 0s-.244-.64 0-.884l.172-.172a4.85 4.85 0 0 1 6.855 0l.039.042.055-.058a3.6 3.6 0 0 0-.145-4.934 3.6 3.6 0 0 0-5.087 0z",
+ "link-1":
+ "M6.408 7.388c.244.244.244.64 0 .884l-2.175 2.175a3.77 3.77 0 0 0 0 5.329 3.77 3.77 0 0 0 5.329 0l2.175-2.174c.244-.244.64-.244.884 0s.244.64 0 .884l-2.175 2.174a5.02 5.02 0 0 1-7.097 0 5.02 5.02 0 0 1 0-7.097l2.175-2.175c.244-.244.64-.244.884 0zM16.66 3.35a5.02 5.02 0 0 1 0 7.097l-2.175 2.175c-.244.244-.64.244-.884 0s-.244-.64 0-.884l2.175-2.175a3.77 3.77 0 0 0 0-5.329 3.77 3.77 0 0 0-5.329 0L8.272 6.408c-.244.244-.64.244-.884 0s-.244-.64 0-.884L9.563 3.35a5.02 5.02 0 0 1 7.097 0zm-4.13 4.13c.244.244.244.64 0 .884L8.364 12.53c-.244.244-.64.244-.884 0s-.244-.64 0-.884l4.167-4.167c.244-.244.64-.244.884 0z",
+ plus: "M10.002 2.71c.345 0 .625.28.625.625l-.001 6.041 6.042.001c.314 0 .574.231.618.533l.007.092c0 .345-.28.625-.625.625l-6.042-.001.001 6.042c0 .314-.231.574-.533.618l-.092.007c-.345 0-.625-.28-.625-.625l-.001-6.042-6.041.001c-.314 0-.574-.231-.618-.533l-.007-.092c0-.345.28-.625.625-.625l6.041-.001.001-6.041c0-.314.231-.574.533-.618l.092-.007z",
+ profile:
+ "M9.999 10.841c2.968 0 5.385 1.767 6.381 4.509.489 1.345-.587 2.65-1.998 2.65H5.618c-1.412 0-2.486-1.304-1.998-2.65.994-2.74 3.413-4.507 6.38-4.507h-.031l.031-.001zm.018 1.262l-.018.002c-2.441 0-4.401 1.432-5.217 3.682-.167.462.234.95.836.95h8.764c.601 0 1.003-.488.836-.948-.818-2.253-2.777-3.684-5.219-3.684h.018zM10 2c.986 0 1.932.399 2.629 1.11s1.089 1.675 1.089 2.68a3.85 3.85 0 0 1-.283 1.45c-.187.46-.461.878-.806 1.229s-.755.631-1.206.821a3.66 3.66 0 0 1-2.846 0c-.451-.19-.861-.47-1.206-.821s-.619-.77-.806-1.229a3.85 3.85 0 0 1-.283-1.45c0-1.005.392-1.969 1.089-2.68S9.013 2 10 2zm0 1.263c-.658 0-1.288.266-1.753.74a2.55 2.55 0 0 0-.726 1.786 2.57 2.57 0 0 0 .189.967 2.53 2.53 0 0 0 .537.82c.23.235.504.421.804.548a2.44 2.44 0 0 0 1.897 0c.301-.127.574-.313.804-.548a2.53 2.53 0 0 0 .537-.82c.125-.306.189-.635.189-.967a2.55 2.55 0 0 0-.726-1.786c-.465-.474-1.095-.74-1.753-.74z",
+ python: "M12.529 2.266a2.29 2.29 0 0 1 .632.632c.347.52.386.903.386 2.523v1.041l1.287.001c1.336.004 1.741.051 2.196.334l.081.052a2.29 2.29 0 0 1 .632.632c.329.492.381.862.386 2.277v.491c-.005 1.415-.057 1.785-.386 2.277a2.29 2.29 0 0 1-.632.632c-.492.329-.863.381-2.278.386h-1.287v1.042c0 1.535-.035 1.96-.334 2.442l-.052.081a2.29 2.29 0 0 1-.632.632c-.52.347-.903.386-2.523.386s-2.004-.039-2.523-.386a2.29 2.29 0 0 1-.632-.632c-.329-.492-.381-.862-.386-2.277v-1.288H5.176c-1.336-.004-1.741-.051-2.196-.334l-.081-.052a2.29 2.29 0 0 1-.632-.632c-.329-.492-.381-.862-.386-2.277v-.246c0-1.62.039-2.004.386-2.523a2.29 2.29 0 0 1 .632-.632c.492-.329.862-.381 2.277-.386l1.288-.001V5.176c.004-1.336.051-1.741.334-2.196l.052-.081a2.29 2.29 0 0 1 .632-.632c.492-.329.862-.381 2.277-.386h.246c1.62 0 2.004.039 2.523.386zM7.714 14.809c.004 1.121.039 1.405.175 1.608a1.04 1.04 0 0 0 .287.287c.216.144.523.176 1.829.176s1.613-.031 1.829-.176a1.04 1.04 0 0 0 .287-.288c.136-.203.171-.487.175-1.608v-1.263l-2.29.001c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h4.802c1.122-.004 1.405-.039 1.609-.175a1.04 1.04 0 0 0 .287-.287c.136-.203.171-.487.175-1.608v-.441c-.004-1.122-.039-1.405-.175-1.608a1.04 1.04 0 0 0-.287-.287c-.203-.136-.487-.172-1.608-.175l-1.261-.001v2.292c0 .345-.28.625-.625.625l-5.208-.001-.001 4.179zm3.126-.02c.345 0 .625.28.625.625 0 .353-.28.633-.625.633s-.625-.28-.625-.625c0-.353.28-.633.625-.633zM5.201 7.714c-1.121.004-1.405.039-1.608.175a1.04 1.04 0 0 0-.287.287c-.136.203-.171.487-.175 1.608v.441c.004 1.121.039 1.405.175 1.608a1.04 1.04 0 0 0 .287.287c.203.136.487.172 1.608.175h1.263l.001-2.291c0-.345.28-.625.625-.625l5.208-.001V7.102v-1.9c-.004-1.121-.039-1.405-.175-1.608a1.04 1.04 0 0 0-.287-.287c-.191-.127-.452-.167-1.408-.174l-.201-.001h-.441c-1.122.004-1.405.039-1.608.175a1.04 1.04 0 0 0-.287.287c-.136.203-.171.487-.175 1.608v1.262h2.293c.345 0 .625.28.625.625s-.28.625-.625.625H5.201zm3.973-3.751c.345 0 .625.28.625.625 0 .354-.28.633-.625.633s-.625-.28-.625-.625c0-.354.28-.633.625-.633z",
+ rocket: "M2.974 13.902a2.39 2.39 0 0 1 2.604.517 2.39 2.39 0 0 1 .518 2.604A2.39 2.39 0 0 1 3.889 18.5H2.99a1.49 1.49 0 0 1-1.49-1.49v-.899a2.39 2.39 0 0 1 1.474-2.208zM16.987 1.505c.202-.017.406.011.596.08s.364.18.507.323.254.316.324.507a1.39 1.39 0 0 1 .081.594c-.242 3.064-1.703 5.603-4.43 8.102l.206-.193.001 2.952a2.34 2.34 0 0 1-.242 1.037l-.086.158a2.34 2.34 0 0 1-.892.861l-2.536 1.383a1.49 1.49 0 0 1-1.474-.026 1.49 1.49 0 0 1-.73-1.281l-.001-1.377-2.937-2.937H4a1.49 1.49 0 0 1-.6-.126l-.138-.069a1.49 1.49 0 0 1-.753-1.269 1.49 1.49 0 0 1 .182-.74l1.382-2.538A2.34 2.34 0 0 1 6.13 5.726h2.951l.066-.07c2.33-2.457 4.71-3.819 7.526-4.122l.315-.029zM4.106 15.019a1.11 1.11 0 0 0-1.142.473 1.11 1.11 0 0 0-.187.618v.899c0 .056.022.111.062.151s.094.062.15.062h.899c.219 0 .434-.066.618-.188a1.11 1.11 0 0 0 .473-1.142 1.11 1.11 0 0 0-.874-.874zm8.889-3.056l-3.406 2.705v1.332c0 .025.004.049.013.072l.015.033c.018.032.044.059.076.078s.068.029.105.03.073-.008.106-.026l2.536-1.383c.168-.092.308-.227.406-.391s.149-.352.149-.543l-.001-1.907zm4.096-9.185c-2.705.213-4.963 1.513-7.261 4.019l.017-.02-3.353 4.223 2.506 2.506 4.223-3.355.244-.227c2.247-2.131 3.458-4.243 3.729-6.729l.027-.288c.001-.017-.001-.034-.007-.051s-.015-.031-.028-.043-.027-.022-.043-.027-.034-.008-.054-.007zM5.33 10.41l2.704-3.406H6.129c-.153 0-.304.033-.442.096l-.101.053c-.165.097-.3.238-.391.405l-1.383 2.538c-.018.033-.027.069-.026.106s.011.073.03.105.046.058.078.076.069.028.106.028H5.33z",
+ search: "M9.165 1.04c4.487 0 8.125 3.638 8.125 8.125 0 2.019-.736 3.865-1.955 5.286l3.438 3.439c.244.244.244.64 0 .884s-.64.244-.884 0l-3.438-3.439c-1.421 1.219-3.268 1.955-5.287 1.955-4.487 0-8.125-3.638-8.125-8.125S4.678 1.04 9.165 1.04zm0 1.25c-3.797 0-6.875 3.078-6.875 6.875s3.078 6.875 6.875 6.875 6.875-3.078 6.875-6.875S12.962 2.29 9.165 2.29z",
+ security:
+ "M9.992 1.04c1.421 0 2.442.379 4.181 1.335l.381.21.372.201c.518.274.92.454 1.312.579 1.162.371 1.351.445 1.605.727.197.219.29.458.371.847l.077.407c1.081 5.993-1.442 11.226-6.73 13.251-.76.291-1.023.36-1.566.36s-.806-.069-1.566-.36C3.14 16.572.615 11.338 1.696 5.346c.141-.783.196-.973.448-1.253s.443-.356 1.605-.727c.393-.125.795-.306 1.313-.58l.371-.2.38-.209C7.55 1.419 8.571 1.04 9.992 1.04zm0 1.25c-1.153 0-2.011.319-3.577 1.181l-.382.21-.387.209c-.578.306-1.042.515-1.518.666-.792.253-1.033.347-1.056.372s-.056.138-.147.639c-.979 5.431 1.256 10.064 5.95 11.862.627.24.769.277 1.119.277s.492-.037 1.119-.277c4.693-1.797 6.927-6.43 5.947-11.861l-.07-.373c-.04-.19-.064-.252-.076-.266-.023-.025-.264-.12-1.056-.372-.475-.151-.939-.36-1.516-.665l-.388-.21-.383-.211c-1.567-.862-2.426-1.181-3.579-1.181zm.002 2.917c2.646 0 4.792 2.145 4.792 4.792S12.64 14.79 9.994 14.79s-4.792-2.145-4.792-4.792 2.145-4.792 4.792-4.792zm0 1.25c-1.956 0-3.542 1.586-3.542 3.542s1.586 3.542 3.542 3.542 3.542-1.586 3.542-3.542-1.586-3.542-3.542-3.542zm2.256 2.083c.115.325-.055.683-.38.798-.073.026-.155.066-.244.118-.305.183-.657.503-1.022.919a10.85 10.85 0 0 0-.66.836 8.85 8.85 0 0 0-.255.373c-.261.41-.869.379-1.087-.056-.136-.272-.261-.422-.361-.489-.012-.008.018.001.086.001-.345 0-.625-.28-.625-.625s.28-.625.625-.625c.259 0 .541.114.813.366l.015.015.252-.318.257-.304c.444-.505.883-.905 1.32-1.167.156-.093.312-.169.468-.224.325-.115.683.055.798.38z",
+ settings:
+ "M13.744 1.945l1.437.816c.559.318.667.394.796.699.132.312.113.42-.089 1.197-.331 1.276.48 2.641 1.781 2.992.76.205.866.243 1.071.511.183.239.211.37.215.872v1.936c-.004.502-.031.633-.214.871-.126.165-.285.262-.499.342-.13.049-.237.08-.573.17-1.301.351-2.111 1.716-1.78 2.992.201.775.22.885.089 1.197-.129.305-.237.382-.796.7l-1.437.816c-.55.312-.671.365-.996.321-.333-.045-.419-.117-.969-.666-.973-.971-2.591-.971-3.564 0-.55.549-.636.621-.968.666-.326.044-.447-.01-.996-.321l-1.437-.816c-.559-.317-.667-.394-.796-.7-.132-.312-.113-.42.089-1.197.331-1.276-.48-2.641-1.781-2.992l-.573-.17c-.214-.08-.373-.176-.499-.341-.183-.239-.211-.369-.214-.871V9.194c0-.639.014-.771.215-1.034.205-.268.311-.306 1.072-.511 1.302-.351 2.113-1.716 1.782-2.992-.202-.777-.22-.885-.089-1.197.129-.305.237-.382.796-.699l1.437-.816c.55-.312.671-.365.997-.321.332.045.418.117.968.666.972.97 2.589.97 3.561 0 .551-.549.636-.621.968-.666.326-.044.447.009.996.321zm-.824.968l-.026.031-.158.158-.074.073c-1.46 1.456-3.867 1.456-5.327 0l-.231-.231-.027-.031-.018.012-.188.107-1.437.816-.193.109-.022.01.015.046.036.136.023.09.027.104c.505 1.945-.708 3.985-2.667 4.513l-.321.087-.043.008.002.024V9v1.968.057l-.002.017.027.008.225.063.112.03c1.958.528 3.171 2.568 2.665 4.513l-.085.33-.015.045.022.011.114.064.079.045 1.437.816.188.107.017.011.028-.03.158-.158.074-.073c1.461-1.458 3.869-1.458 5.33 0l.074.073.158.158.026.03.02-.011.111-.063.077-.044 1.437-.816.193-.109.021-.011-.014-.044-.059-.226-.027-.104c-.506-1.945.706-3.985 2.664-4.513l.337-.094.025-.008v-.017-2.05l.001-.023-.042-.009-.219-.059-.102-.028c-1.958-.528-3.171-2.568-2.665-4.513l.049-.194.036-.136.014-.046-.021-.01-.114-.064-.079-.045-1.437-.816-.188-.107-.019-.012zM9.998 6.458c1.956 0 3.542 1.586 3.542 3.542s-1.586 3.542-3.542 3.542-3.542-1.586-3.542-3.542 1.586-3.542 3.542-3.542zm0 1.25a2.29 2.29 0 1 0 0 4.583 2.29 2.29 0 1 0 0-4.583z",
+ share: "M8.804 1.46c.345-.001.626.279.626.624s-.279.626-.624.626c-3.639.007-4.745.185-5.538.976-.819.818-.971 1.807-.978 5.979v.672c.007 4.172.159 5.161.978 5.979s1.812.969 5.993.977h.674c4.181-.007 5.173-.158 5.993-.976.619-.618.871-1.533.946-3.423.014-.345.304-.613.649-.6s.613.304.6.649c-.086 2.178-.412 3.36-1.312 4.258-1.163 1.16-2.274 1.334-6.862 1.342h-.701c-4.588-.008-5.699-.181-6.862-1.342s-1.337-2.27-1.345-6.85v-.35c0-4.874.153-6.01 1.345-7.2C3.514 1.675 4.799 1.467 8.804 1.46zm4.97 1.667l.15.014c.338.05.63.212.998.508l1.024.893 1.456 1.264c1.062.922 1.306 1.171 1.475 1.649a1.37 1.37 0 0 1 0 .92c-.169.477-.413.727-1.475 1.649l-1.456 1.264-.878.792c-.32.282-.55.444-.817.542a1.41 1.41 0 0 1-.925.019c-.692-.211-.931-.82-.953-1.662l.001-.299.001-.058-.024-.001-.314-.007-.188-.005-.868-.018c-1.099-.013-1.881.042-2.593.21-.784.185-1.407.5-2.602 1.242l-.446.276c-.431.264-.967-.035-.967-.524 0-3.494 1.675-5.918 5.228-6.495.594-.097 1.199-.126 2.023-.119l.605.009.146.003-.001-.043-.003-.151.002-.148c.022-.842.261-1.451.953-1.662.099-.03.199-.049.298-.057l.15-.003zm-.033 1.25c-.014-.002-.026-.001-.051.006-.002.001-.059.145-.068.499a5.89 5.89 0 0 0 .016.538l.02.404c0 .345-.28.625-.625.625-.23 0-.411-.003-.827-.01l-.593-.009c-.759-.007-1.302.02-1.811.103-2.452.399-3.752 1.802-4.089 4.005l-.013.092.192-.113c.779-.452 1.346-.708 2.007-.884l.201-.051c.831-.197 1.704-.258 2.895-.244l.886.019 1.151.02c.345 0 .625.28.625.625 0 .093.001.075-.02.404l-.016.538c.009.354.066.499.068.499.062.019.089.018.128.004.085-.031.211-.12.424-.307l.885-.798 1.456-1.264c.832-.723 1.055-.95 1.116-1.121.006-.017.008-.03.008-.044s-.002-.026-.008-.044c-.06-.171-.283-.398-1.116-1.121l-1.456-1.264-1.385-1.108z",
+ "share-1":
+ "M9.259 2c.34-.001.616.274.616.614s-.274.616-.614.616c-3.377.006-4.401.172-5.13.901-.774.774-.901 1.722-.901 5.868v.379c.008 3.826.151 4.739.901 5.489.774.774 1.722.901 5.867.901h.379c3.825-.008 4.738-.151 5.488-.901.729-.729.895-1.753.901-5.131.001-.34.277-.615.616-.614s.615.277.614.617c-.007 3.738-.201 4.939-1.261 5.999C15.618 17.857 14.556 18 9.999 18h-.405c-4.216-.009-5.248-.176-6.333-1.261-1.09-1.09-1.254-2.127-1.261-6.395V10c0-4.557.143-5.619 1.261-6.738C4.321 2.201 5.522 2.007 9.259 2zm5.999.073c1.178.059 1.853.171 2.197.515.317.317.437.917.499 1.935l.015.263.025 1.963c-.005.34-.284.611-.624.607s-.611-.284-.607-.624l.003-.238v-.477l-.057-1.718-.006-.086-7.048 7.09c-.213.214-.545.239-.785.073l-.085-.071c-.241-.24-.242-.629-.003-.87l7.055-7.096-.093-.006-1.715-.057h-.477l-.237.003c-.34.005-.619-.267-.624-.607s.267-.619.607-.624l1.96.025z",
+ team: "M13.659 12.12l.097.058.856.527c.639.423 1.086.831 1.339 1.317.372.713.235 1.476-.423 2.133-.878.877-1.77 1.345-2.826 1.345H7.297c-1.055 0-1.947-.468-2.826-1.345-.658-.657-.795-1.42-.423-2.133.253-.486.7-.894 1.339-1.317l.477-.298.21-.127.266-.159a6.91 6.91 0 0 1 7.319 0zM7.01 13.214c.016-.01-.703.419-.925.566-.473.313-.783.596-.91.84-.104.2-.077.352.192.621.661.66 1.258.973 1.93.973h5.407c.672 0 1.269-.313 1.93-.973.269-.269.296-.42.192-.621-.127-.244-.437-.527-.91-.84l-.925-.566c-1.829-1.142-4.15-1.142-5.979 0zm8.895-2.998l.094.002c.802.073 1.576.386 2.254.913-.03-.023.471.349.645.493 1.083.893 1.5 1.887.64 2.956-.625.778-1.282 1.207-2.091 1.207a.64.64 0 1 1 0-1.286c.351 0 .694-.224 1.102-.732.28-.348.155-.646-.457-1.15l-.617-.47a3.04 3.04 0 0 0-1.592-.651.64.64 0 0 1-.577-.698.64.64 0 0 1 .597-.584zm-11.214.584a.64.64 0 0 1-.577.698 3.04 3.04 0 0 0-1.592.651 26.62 26.62 0 0 0-.617.47c-.612.504-.736.802-.457 1.15.408.507.751.732 1.102.732a.64.64 0 1 1 0 1.286c-.809 0-1.465-.429-2.091-1.207-.859-1.069-.443-2.063.64-2.956l.645-.493c.678-.528 1.452-.84 2.254-.913a.64.64 0 0 1 .691.582zm10.402-6.585c1.524 0 2.759 1.247 2.759 2.786s-1.235 2.786-2.759 2.786a.64.64 0 1 1 0-1.286c.82 0 1.486-.672 1.486-1.5s-.665-1.5-1.486-1.5a.64.64 0 0 1-.637-.643.64.64 0 0 1 .637-.643zm-10.611 0a.64.64 0 0 1 .637.643.64.64 0 0 1-.637.643c-.82 0-1.486.672-1.486 1.5s.665 1.5 1.486 1.5a.64.64 0 1 1 0 1.286C2.958 9.786 1.723 8.539 1.723 7s1.235-2.786 2.759-2.786zM10 2.5c1.993 0 3.608 1.631 3.608 3.643S11.993 9.786 10 9.786 6.392 8.155 6.392 6.143 8.007 2.5 10 2.5zm0 1.286c-1.289 0-2.335 1.055-2.335 2.357S8.711 8.5 10 8.5s2.335-1.055 2.335-2.357S11.289 3.786 10 3.786z",
+ template:
+ "M16.134 2.199c1.03 1.03 1.159 1.995 1.159 6.132v2.786c0 .948-.018 1.191-.174 1.567-.145.35-.292.534-.849 1.095l-4.219 4.219c-.469.465-.627.594-.918.733a2.31 2.31 0 0 1-.226.094c-.303.107-.505.128-1.167.13h-.518c-3.287-.006-4.102-.122-5.038-.877-.22-.177-.42-.377-.597-.597-.755-.936-.87-1.751-.877-5.038V8.332c0-4.137.13-5.103 1.159-6.132C4.87 1.198 5.811 1.048 9.664 1.04h.338c4.137 0 5.103.13 6.132 1.159zm-5.811.091h-.642c-3.448.007-4.269.134-4.928.793s-.786 1.479-.793 4.928v4.41c.006 2.945.103 3.662.6 4.278.121.15.258.287.409.408.616.497 1.332.594 4.278.6h.455l.437-.007.071-.004.001-.197c0-3.05.093-3.842.836-4.628l.079-.081c.789-.789 1.505-.908 4.402-.915l.501-.001.003-.025.012-.566v-2.95c0-3.719-.114-4.569-.793-5.248-.639-.639-1.43-.778-4.621-.792l-.306-.001zm4.835 10.835l-.106.001c-2.081.018-2.625.129-3.042.546s-.528.961-.546 3.042l-.001.104 3.695-3.694zM10.002 8.54c.345 0 .625.28.625.625s-.28.625-.625.625H6.669c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h3.333zm3.333-3.333c.345 0 .625.28.625.625s-.28.625-.625.625H6.669c-.345 0-.625-.28-.625-.625s.28-.625.625-.625h6.667z",
+ quill: "M17.295 1.35v.625c0 1.198-.269 2.683-.883 3.96-.527 1.097-1.415 1.885-2.451 2.265l-.164.055.797.815c.219.419.239.457.052.786l-.062.108c-1.692 1.66-2.665 2.439-3.764 3.074l-.37.208-.777.422c-1.023.561-3.772 1.359-5.02 1.515a8.76 8.76 0 0 0-.692 3.454H2.71c0-1.477.3-2.835.849-4.076-.017-.122-.025-.263-.029-.42a9.61 9.61 0 0 1 .071-1.196c.09-.832.261-1.891.424-2.669.473-2.261 2.353-4.979 4.326-6.401 2.476-1.784 5.494-2.528 8.319-2.527h.625zm-1.28 1.265l-.088.004c-2.365.119-4.824.816-6.845 2.272-1.729 1.246-3.427 3.7-3.833 5.643l-.301 1.735c.265-.339.551-.665.856-.98.67-.693 1.386-1.28 2.104-1.766.434-.294.777-.491.983-.594l.558 1.118c-.159.079-.454.249-.84.511-.65.44-1.3.974-1.906 1.6-.492.508-.926 1.047-1.296 1.617 1.146-.263 2.759-.758 3.523-1.128l.144-.074.777-.421.345-.194c.892-.516 1.702-1.144 3.022-2.407l.05-.049-1.187-1.215c-.373-.378-.141-.996.352-1.071l.095-.007c1.144-.006 2.21-.672 2.759-1.815.38-.791.609-1.698.706-2.528l.024-.251z",
+ "web-design":
+ "M17.84 10.724a2.71 2.71 0 0 1 .599.599c.444.611.512 1.096.517 3.002v.513c-.005 1.906-.073 2.391-.517 3.002a2.71 2.71 0 0 1-.599.599c-.611.444-1.096.512-3.002.517h-4.423c-2.12 0-2.621-.054-3.259-.517a2.71 2.71 0 0 1-.599-.599c-.444-.611-.512-1.096-.517-3.002v-.257c0-2.12.054-2.621.517-3.259a2.71 2.71 0 0 1 .599-.599c.611-.444 1.096-.512 3.002-.517h4.423c2.12 0 2.621.054 3.259.517zm-3.024.733H10.18c-1.588.004-1.982.056-2.289.278a1.46 1.46 0 0 0-.323.323c-.223.307-.274.701-.278 2.289v.47c.004 1.588.055 1.982.278 2.289a1.46 1.46 0 0 0 .323.323c.307.223.701.274 2.289.278h4.402c1.786 0 2.203-.045 2.524-.278a1.46 1.46 0 0 0 .323-.323c.223-.307.274-.701.278-2.289v-.47c-.004-1.588-.056-1.982-.278-2.289a1.46 1.46 0 0 0-.323-.323c-.292-.212-.663-.269-2.07-.277l-.219-.001zm-.661 1.401l.767.661c.587.506.7.634.7 1.063a.9.9 0 0 1-.059.32c-.099.261-.194.357-.641.743l-.767.661c-.261.225-.656.196-.881-.065s-.196-.656.065-.881l.767-.661.078-.068.054-.048-.056-.05-.076-.066-.767-.661c-.261-.225-.291-.62-.065-.881s.62-.291.881-.065zm-2.435.065c.225.261.196.656-.065.881l-.767.661-.076.066-.057.05.055.048.078.068.767.661c.261.225.291.62.065.881s-.62.291-.881.065l-.767-.661c-.447-.385-.542-.481-.641-.743a.9.9 0 0 1-.059-.32c0-.429.113-.556.7-1.063l.767-.661c.261-.225.656-.196.881.065zm4.413-10.705c1.026 1.043 1.156 2.021 1.156 6.22 0 .345-.28.625-.625.625s-.625-.28-.625-.625l-.05-2.816H2.34L2.29 8.112v.653c.007 3.508.134 4.344.796 5.017.292.297.665.485 1.213.607.337.075.55.408.475.745s-.408.55-.745.475c-.771-.171-1.36-.468-1.834-.95-.998-1.014-1.148-1.966-1.156-5.877v-.343c0-4.199.129-5.177 1.156-6.22 1.001-1.017 1.944-1.17 5.798-1.178h2.004c4.138 0 5.106.132 6.136 1.179zm-5.815.072H8.011c-3.447.007-4.266.136-4.924.805-.305.31-.496.654-.615 1.278h13.386c-.119-.624-.31-.968-.615-1.278-.659-.669-1.477-.798-4.924-.805z",
+ wrench: "M14.664 1.5c.978-.004 1.47 1.178.779 1.869l-2.25 2.25a.84.84 0 1 0 1.187 1.189l2.25-2.249c.691-.691 1.873-.199 1.869.776l-.001 1.264c-.008 3.289-.1 3.757-.767 4.574-.102.124-.217.249-.361.393-.991.99-2.059 1.132-5.824 1.13H11.5l-4.934 4.936a2.97 2.97 0 0 1-4.197 0 2.97 2.97 0 0 1 0-4.197l4.936-4.936V8.16c.006-3.529.166-4.567 1.13-5.532l.393-.361c.817-.667 1.285-.759 4.575-.767l1.261-.001zM7.52 10.041l-4.272 4.273c-.673.673-.673 1.764 0 2.438s1.764.673 2.438 0l4.272-4.271c-1.14-.394-2.044-1.298-2.438-2.439zm-2.903 4.52a.83.83 0 0 1 .829.829.83.83 0 0 1-.829.829.83.83 0 0 1-.837-.829.83.83 0 0 1 .829-.829zm9.691-11.817h-.861c-2.939.007-3.327.075-3.831.487-.088.072-.184.16-.3.277-.641.64-.768 1.599-.766 4.943v.304c.001 1.488 1.208 2.696 2.694 2.696h.585c3.119-.006 4.041-.143 4.663-.766l.277-.3c.412-.504.48-.892.487-3.83v-.863L15.26 7.687c-.779.778-2.02.812-2.839.101l-.109-.102c-.814-.814-.813-2.134.001-2.948l1.995-1.996z",
+ voice: "M17.221 2.822c1.161 1.161 1.334 2.27 1.342 6.849v.7c-.008 4.579-.181 5.688-1.342 6.849s-2.27 1.334-6.849 1.342h-.7c-4.579-.008-5.688-.181-6.849-1.342s-1.334-2.27-1.342-6.849v-.35c0-4.874.153-6.009 1.342-7.199 1.161-1.161 2.27-1.334 6.849-1.342h.35c4.874 0 6.009.153 7.199 1.342zm-6.863-.092h-.672c-4.172.007-5.162.158-5.979.976-.839.839-.976 1.859-.976 6.315v.336c.007 4.172.158 5.162.976 5.979s1.807.969 5.979.976h.672c4.172-.007 5.162-.158 5.979-.976s.969-1.807.976-5.979v-.672c-.007-4.172-.158-5.162-.976-5.979-.796-.796-1.755-.96-5.657-.975l-.323-.001zm-.336 3.333c.345 0 .625.28.625.625v6.667c0 .345-.28.625-.625.625s-.625-.28-.625-.625V6.688c0-.345.28-.625.625-.625zm-2.5 1.667c.345 0 .625.28.625.625v3.333c0 .345-.28.625-.625.625s-.625-.28-.625-.625V8.355c0-.345.28-.625.625-.625zm5 0c.345 0 .625.28.625.625v3.333c0 .345-.28.625-.625.625s-.625-.28-.625-.625V8.355c0-.345.28-.625.625-.625zm-7.5.833c.345 0 .625.28.625.625v1.667c0 .345-.28.625-.625.625s-.625-.28-.625-.625V9.188c0-.345.28-.625.625-.625zm10 0c.345 0 .625.28.625.625v1.667c0 .345-.28.625-.625.625s-.625-.28-.625-.625V9.188c0-.345.28-.625.625-.625z",
+ volume: "M6.941 5.311c2.58-2.681 3.131-3.112 4.203-2.651 1.062.457 1.158 1.162 1.158 4.942v5.13c-.006 3.487-.128 4.163-1.158 4.607-1.072.462-1.623.031-4.203-2.65-.818-.85-1.191-1.007-2.378-1.007-1.628 0-2.015-.041-2.538-.404-.75-.521-1.003-1.285-1.023-2.4L1 10.786v-.194l.003-.262.003-.226v-.208l-.003-.226L1 9.408v-.194l.001-.092c.021-1.115.273-1.879 1.023-2.4.523-.363.91-.404 2.538-.404 1.187 0 1.56-.157 2.378-1.007zm3.714-1.473c-.284-.122-.838.311-2.817 2.368-1.056 1.097-1.753 1.391-3.275 1.391-1.309 0-1.615.032-1.831.182-.331.23-.462.626-.475 1.368l-.001.081v.177l.003.246.003.237v.226l-.003.237-.003.246v.177l.001.081c.014.742.145 1.138.475 1.368.215.15.522.182 1.831.182 1.522 0 2.219.293 3.275 1.391 1.979 2.056 2.533 2.49 2.817 2.368.294-.126.391-.845.391-3.765V7.308c-.007-2.674-.108-3.349-.391-3.471zm3.15 3.098a.62.62 0 0 1 .88.12A4.9 4.9 0 0 1 15.651 10a4.9 4.9 0 0 1-.966 2.944.62.62 0 0 1-.88.12c-.276-.214-.329-.615-.118-.896.455-.607.709-1.366.709-2.169s-.253-1.561-.709-2.169c-.21-.281-.157-.682.118-.896zm2.469-1.667a.62.62 0 0 1 .887.04C18.341 6.62 19 8.264 19 10s-.659 3.38-1.839 4.692a.62.62 0 0 1-.887.04c-.256-.238-.273-.643-.039-.903.973-1.082 1.51-2.42 1.51-3.829s-.536-2.747-1.51-3.829c-.234-.26-.217-.665.039-.903z",
+ zsh: "M16.155 2.795a4.79 4.79 0 0 1 1.06 1.06c.811 1.116.915 2.076.915 6.15s-.104 5.033-.915 6.15a4.79 4.79 0 0 1-1.06 1.06c-1.116.811-2.076.915-6.15.915s-5.033-.104-6.15-.915a4.79 4.79 0 0 1-1.06-1.06c-.787-1.084-.908-2.02-.915-5.798v-.351c0-4.073.104-5.033.915-6.15a4.79 4.79 0 0 1 1.06-1.06c1.084-.787 2.02-.908 5.798-.915h.351c4.073 0 5.033.104 6.15.915zm-5.818.335h-.664c-3.46.006-4.307.112-5.083.676a3.54 3.54 0 0 0-.784.784c-.564.776-.67 1.623-.676 5.083v.664c.006 3.46.112 4.307.676 5.083a3.54 3.54 0 0 0 .784.783c.8.581 1.676.676 5.415.676s4.615-.095 5.415-.676a3.54 3.54 0 0 0 .784-.784c.581-.8.676-1.676.676-5.415s-.095-4.615-.676-5.415a3.54 3.54 0 0 0-.784-.784c-.752-.546-1.571-.663-4.766-.675l-.317-.001zm3.392 2.22c.27.216.313.609.098.878L7.16 14.562c-.216.27-.609.313-.878.098s-.313-.609-.098-.878l6.667-8.333c.216-.27.609-.313.878-.098z",
+};
+
+type IconProps = {
+ className?: string;
+ name: string;
+ fill?: string;
+};
+
+const Icon = ({ className, name, fill }: IconProps) => (
+
+
+
+);
+
+export default Icon;
diff --git a/src/views/AgentChat/neuratalk/components/Image/index.tsx b/src/views/AgentChat/neuratalk/components/Image/index.tsx
new file mode 100644
index 00000000..f4a322d0
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Image/index.tsx
@@ -0,0 +1,18 @@
+import { useState } from "react";
+import { default as NextImage, ImageProps } from "next/image";
+
+const Image = ({ className, ...props }: ImageProps) => {
+ const [loaded, setLoaded] = useState(false);
+
+ return (
+ setLoaded(true)}
+ {...props}
+ />
+ );
+};
+
+export default Image;
diff --git a/src/views/AgentChat/neuratalk/components/LanguageTranslator/index.tsx b/src/views/AgentChat/neuratalk/components/LanguageTranslator/index.tsx
new file mode 100644
index 00000000..d442bd97
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/LanguageTranslator/index.tsx
@@ -0,0 +1,45 @@
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import Button from "@/components/Button";
+
+const LanguageTranslator = () => {
+ return (
+
+
+ Translate this text to frensh:
+
+ Beneath the quiet hum of a late-night city, a single
+ streetlamp flickered like it was holding on to its last
+ breath. Somewhere nearby, the scent of fresh rain clung to
+ the pavement, mixing with the soft sound of footsteps
+ echoing between empty buildings. It was the kind of night
+ where time felt slower, and the world seemed to hold its
+ breath, waiting for something unspoken to happen.
+
+
+
+ Sure here is the text in frensh:
+
+ Sous le doux bourdonnement d'une ville tard dans la
+ nuit, un seul lampadaire vacillait comme s'il
+ s'accrochait à son dernier souffle. Non loin de là,
+ l'odeur de la pluie fraîche s'accrochait au
+ bitume, se mêlant au léger bruit de pas résonnant entre les
+ immeubles vides. C’était le genre de nuit où le temps
+ semblait ralentir, et où le monde retenait son souffle,
+ attendant que quelque chose d’indicible se produise.
+
+
+ Change text language
+
+
+
+ );
+};
+
+export default LanguageTranslator;
diff --git a/src/views/AgentChat/neuratalk/components/Layout/index.tsx b/src/views/AgentChat/neuratalk/components/Layout/index.tsx
new file mode 100644
index 00000000..40514b88
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Layout/index.tsx
@@ -0,0 +1,79 @@
+import { useState } from "react";
+import Sidebar from "@/components/Sidebar";
+import Tools from "@/components/Tools";
+import Header from "@/components/Header";
+import PythonRunner from "@/components/PythonRunner";
+import Calculator from "@/components/Calculator";
+import Browser from "@/components/Browser";
+import WebDesign from "@/components/WebDesign";
+import FileConverter from "@/components/FileConverter";
+import LanguageTranslator from "@/components/LanguageTranslator";
+import ApiIntegrator from "@/components/ApiIntegrator";
+
+type Props = {
+ children: React.ReactNode;
+};
+
+const Layout = ({ children }: Props) => {
+ const [activeId, setActiveId] = useState(null);
+ const [visibleTools, setVisibleTools] = useState(true);
+ const [visibleSidebar, setVisibleSidebar] = useState(false);
+
+ return (
+
+
setVisibleSidebar(false)}
+ onClickNewChat={() => setActiveId(null)}
+ />
+
+
setVisibleSidebar(true)}
+ onToggleTools={() => setVisibleTools(!visibleTools)}
+ />
+ {activeId === "python" ? (
+
+ ) : activeId === "calculator" ? (
+
+ ) : activeId === "browser" ? (
+
+ ) : activeId === "web-design" ? (
+
+ ) : activeId === "exchange" ? (
+
+ ) : activeId === "language" ? (
+
+ ) : activeId === "api" ? (
+
+ ) : (
+ children
+ )}
+
+ setVisibleTools(!visibleTools)}
+ />
+ {
+ setVisibleSidebar(false);
+ setVisibleTools(true);
+ }}
+ >
+
+ );
+};
+
+export default Layout;
diff --git a/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/index.tsx b/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/index.tsx
new file mode 100644
index 00000000..c005510b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/index.tsx
@@ -0,0 +1,105 @@
+import { Swiper, SwiperSlide } from "swiper/react";
+import { items } from "./items";
+import Image from "@/components/Image";
+import { useState } from "react";
+
+import "swiper/css";
+import "swiper/css/effect-fade";
+import { Autoplay } from "swiper/modules";
+
+const SLIDE_DURATION = 3000;
+
+const Slider = ({}) => {
+ const [currentSlide, setCurrentSlide] = useState(0);
+
+ return (
+
+
setCurrentSlide(swiper.activeIndex)}
+ speed={500}
+ >
+ {items.map((item, index) => (
+
+
+
+
+
+
+
+
+ {item.author}
+
+ {index + 1}/{items.length}
+
+
+
+
+
+
+
+
+
+ {item.content}
+
+
+ ))}
+
+
+ );
+};
+
+export default Slider;
diff --git a/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/items.tsx b/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/items.tsx
new file mode 100644
index 00000000..731fb572
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/LayoutLogin/Slider/items.tsx
@@ -0,0 +1,34 @@
+export const items = [
+ {
+ id: 0,
+ author: "Suzana Marie",
+ avatar: "/images/avatar-6.jpg",
+ content:
+ "People with link will be able to view conversations and ideas in this board.Changes you make after creating the link will remain private.",
+ image: "/images/slider-pic-1.png",
+ },
+ {
+ id: 1,
+ author: "Tyson Martine",
+ avatar: "/images/avatar-2.png",
+ content:
+ "My ideas are in a great place. All the content is well organized and it's easy to find what I need.",
+ image: "/images/slider-pic-1.png",
+ },
+ {
+ id: 2,
+ author: "Terrence Jaskolski",
+ avatar: "/images/avatar-3.jpg",
+ content:
+ "I'm amazed at how quickly and easily I can create new ideas with this tool. It's a game-changer!",
+ image: "/images/slider-pic-1.png",
+ },
+ {
+ id: 3,
+ author: "Suzana Marie",
+ avatar: "/images/avatar-6.jpg",
+ content:
+ "People with link will be able to view conversations and ideas in this board.Changes you make after creating the link will remain private.",
+ image: "/images/slider-pic-1.png",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/LayoutLogin/index.tsx b/src/views/AgentChat/neuratalk/components/LayoutLogin/index.tsx
new file mode 100644
index 00000000..3b314ad5
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/LayoutLogin/index.tsx
@@ -0,0 +1,87 @@
+import Link from "next/link";
+import Image from "@/components/Image";
+import Button from "@/components/Button";
+import Icon from "@/components/Icon";
+import Slider from "./Slider";
+
+type Props = {
+ children: React.ReactNode;
+ title: string;
+ description: React.ReactNode;
+};
+
+const LayoutLogin = ({ title, description, children }: Props) => (
+
+
+
+
+
+
+ AI Generative Anything you can imagine
+
+
+ Generate your ideas in to reality fast & quick !
+
+
+
+
+
+
+
+
Website
+
+ Visite Our website
+
+
+
+ LoopiBot.com
+
+
+
+
+
+
+
+
+
+ {title}
+
+
+ {description}
+
+
+ {children}
+
+
+
+ ©LoopiBot.io
+
+
+
+ LoopiBot@chat.io
+
+
+
+
+
+);
+
+export default LayoutLogin;
diff --git a/src/views/AgentChat/neuratalk/components/Modal/index.tsx b/src/views/AgentChat/neuratalk/components/Modal/index.tsx
new file mode 100644
index 00000000..41ae3966
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Modal/index.tsx
@@ -0,0 +1,40 @@
+import {
+ Dialog,
+ DialogPanel,
+ DialogBackdrop,
+ CloseButton,
+} from "@headlessui/react";
+import Icon from "@/components/Icon";
+
+type ModalProps = {
+ classWrapper?: string;
+ open: boolean;
+ onClose: () => void;
+ children: React.ReactNode;
+};
+
+const Modal = ({ classWrapper, open, onClose, children }: ModalProps) => {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+
+
+ );
+};
+
+export default Modal;
diff --git a/src/views/AgentChat/neuratalk/components/ModalPlan/index.tsx b/src/views/AgentChat/neuratalk/components/ModalPlan/index.tsx
new file mode 100644
index 00000000..6504e71b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalPlan/index.tsx
@@ -0,0 +1,104 @@
+import Modal from "@/components/Modal";
+import Button from "@/components/Button";
+import Icon from "@/components/Icon";
+
+import { plans } from "./plans";
+
+type GalleryProps = {
+ open: boolean;
+ onClose: () => void;
+};
+
+const ModalPlan = ({ open, onClose }: GalleryProps) => (
+
+
+
Plans
+
+ Manage your billing and payment details.
+
+
+
+ {plans.map((plan) => (
+
+
+
+
+ {plan.name === "Premium Plan" && (
+
+
+ Most Popular
+
+ )}
+
+
{plan.name}
+
+ {plan.description}
+
+
+ {plan.price}
+
+
{plan.details}
+
+ {plan.name === "Basic Plan"
+ ? "Buy now"
+ : plan.name === "Premium Plan"
+ ? "Switch to this plan"
+ : "Contact Us"}
+ {plan.name !== "Premium Plan" && (
+
+ )}
+
+
+ {plan.features.map((feature, index) => (
+
+ ))}
+
+
+
+ ))}
+
+
+
+ Discard
+
+ Upgrade Membership
+
+
+);
+
+export default ModalPlan;
diff --git a/src/views/AgentChat/neuratalk/components/ModalPlan/plans.tsx b/src/views/AgentChat/neuratalk/components/ModalPlan/plans.tsx
new file mode 100644
index 00000000..7e1661d8
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalPlan/plans.tsx
@@ -0,0 +1,44 @@
+export const plans = [
+ {
+ id: 0,
+ name: "Basic Plan",
+ icon: "profile",
+ description: "per user/email month billed annually",
+ price: "$9.99",
+ details: "one-time payment + Local Taxes",
+ features: [
+ "1 Image generation",
+ "File Sharing",
+ "Limited Integration",
+ "Limited templates",
+ ],
+ },
+ {
+ id: 1,
+ name: "Premium Plan",
+ icon: "rocket",
+ description: "per user/email month billed annually",
+ price: "$19.99",
+ details: "one-time payment + Local Taxes",
+ features: [
+ "30 Image generation",
+ "File Sharing",
+ "10 Integration",
+ "20 templates",
+ ],
+ },
+ {
+ id: 2,
+ name: "Professional Plan",
+ icon: "build",
+ description: "per user/email month billed annually",
+ price: "Custom",
+ details: "one-time payment + Local Taxes",
+ features: [
+ "unlimited Image generation",
+ "File Sharing",
+ "unlimited Integration",
+ "unlimited Integration",
+ ],
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/DataControls/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/DataControls/index.tsx
new file mode 100644
index 00000000..9eff9237
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/DataControls/index.tsx
@@ -0,0 +1,63 @@
+import { useState } from "react";
+import Switch from "@/components/Switch";
+import Button from "@/components/Button";
+
+const DataControls = ({}) => {
+ const [improve, setImprove] = useState(true);
+
+ return (
+
+
+
+
+ Improve the model for everyone
+
+
+ Allow your content to be used to train our models, which
+ makes AI better for you and everyone who uses it. We
+ take steps to protect your privacy.{" "}
+
+ Learn more
+
+
+
+
+
+
+
Export Data
+
+ Export
+
+
+
+
Shared Links
+
+ Manage
+
+
+
+
Archive all chats
+
+ Archive all
+
+
+
+
Delete Account
+
+ Delete Account
+
+
+
+ );
+};
+
+export default DataControls;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/General/UploadImage/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/General/UploadImage/index.tsx
new file mode 100644
index 00000000..a9cc55ec
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/General/UploadImage/index.tsx
@@ -0,0 +1,76 @@
+import { useState, useRef } from "react";
+import Image from "@/components/Image";
+import Button from "@/components/Button";
+import Icon from "@/components/Icon";
+
+const UploadImage = ({}) => {
+ const [preview, setPreview] = useState(
+ "/images/avatar-1.png"
+ );
+ const inputRef = useRef(null);
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const file = e.target.files?.[0];
+ if (file) {
+ const objectUrl = URL.createObjectURL(file);
+ setPreview(objectUrl);
+ }
+ };
+
+ const handleRemove = () => {
+ setPreview(null);
+ };
+
+ return (
+
+
+
+ {preview ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ Upload image
+
+
+
+
+
+
+
+ We only support JPG, JPEG, or ,PNG file. 1MB max.
+
+
+ );
+};
+
+export default UploadImage;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/General/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/General/index.tsx
new file mode 100644
index 00000000..0ad29f02
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/General/index.tsx
@@ -0,0 +1,80 @@
+import { useState } from "react";
+import Field from "@/components/Field";
+import Icon from "@/components/Icon";
+import Button from "@/components/Button";
+import UploadImage from "./UploadImage";
+
+const General = ({}) => {
+ const [fullName, setFullName] = useState("");
+ const [email, setEmail] = useState("");
+ const [phoneNumber, setPhoneNumber] = useState("");
+
+ return (
+
+
+
+
Avatar
+
Update full name
+
+
+
+
+
+
Personal Information
+
+ Edit your personal information
+
+
+
setFullName(e.target.value)}
+ required
+ isSmall
+ />
+ setEmail(e.target.value)}
+ required
+ isSmall
+ />
+
+
+ Add another
+
+
+
+
+
Phone number
+
Update your phone number
+
+
setPhoneNumber(e.target.value)}
+ required
+ isSmall
+ />
+
+
+
+ Discard
+
+
+ Save Changes
+
+
+
+ );
+};
+
+export default General;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/Notifications/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/Notifications/index.tsx
new file mode 100644
index 00000000..6de8b30e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/Notifications/index.tsx
@@ -0,0 +1,34 @@
+import { useState } from "react";
+import Switch from "@/components/Switch";
+
+const Speech = ({}) => {
+ const [responses, setResponses] = useState(true);
+ const [push, setPush] = useState(true);
+ const [email, setEmail] = useState(false);
+
+ return (
+
+
+
+
Responses
+
Ai response Push
+
+
+
+
+
+
+ );
+};
+
+export default Speech;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/Security/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/Security/index.tsx
new file mode 100644
index 00000000..9f192bd7
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/Security/index.tsx
@@ -0,0 +1,47 @@
+import { useState } from "react";
+import Switch from "@/components/Switch";
+import Button from "@/components/Button";
+
+const Security = ({}) => {
+ const [authentication, setAuthentication] = useState(true);
+
+ return (
+
+
+
+
+ Mlti-factor authentication
+
+
+ Require an extra security challenge when logging in. If
+ you are unable to pass this challenge, you will have the
+ option to recover your account via email.
+
+
+
+
+
+
+
Log out of all devices
+
+ Log out of all active sessions across all devices,
+ including your current session. It may take up to 30
+ minutes for other devices to be logged out.
+
+
+
+ Log out all
+
+
+
+ );
+};
+
+export default Security;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/Speech/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/Speech/index.tsx
new file mode 100644
index 00000000..c427596a
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/Speech/index.tsx
@@ -0,0 +1,62 @@
+import { useState } from "react";
+import Button from "@/components/Button";
+import Icon from "@/components/Icon";
+import Select from "@/components/Select";
+
+const voiceOptions = [
+ { id: 1, name: "Default" },
+ { id: 2, name: "Echo" },
+ { id: 3, name: "Tempo" },
+];
+
+const languages = [
+ { id: 1, name: "English" },
+ { id: 2, name: "French" },
+ { id: 3, name: "Spanish" },
+];
+
+const Notifications = ({}) => {
+ const [voice, setVoice] = useState(voiceOptions[0]);
+ const [language, setLanguage] = useState(languages[0]);
+
+ return (
+
+
+
+
Voice
+
Choose your ai voice.
+
+
+
+
+
+
+
+
+
+
+
Main Language
+
+ For best results, select the language you mainly speak.
+
+
+
+
+
+ );
+};
+
+export default Notifications;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/Theme/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/Theme/index.tsx
new file mode 100644
index 00000000..6f8bb9a1
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/Theme/index.tsx
@@ -0,0 +1,97 @@
+import { useTheme } from "next-themes";
+import Image from "@/components/Image";
+
+const Theme = ({}) => {
+ const { theme, setTheme } = useTheme();
+
+ const themes = [
+ {
+ id: 1,
+ name: "Light mode",
+ image: "/images/theme-light.png",
+ value: "light",
+ },
+ {
+ id: 2,
+ name: "Dark mode",
+ image: "/images/theme-dark.png",
+ value: "dark",
+ },
+ {
+ id: 3,
+ name: "System Preference",
+ image: "/images/theme-preference.png",
+ value: "system",
+ },
+ ];
+
+ return (
+
+
Themes
+
+ Choose your style or customize your theme
+
+
+ {themes.map((button) => (
+
setTheme(button.value)}
+ >
+
+
+
+ ))}
+
+
+ );
+};
+
+export default Theme;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/index.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/index.tsx
new file mode 100644
index 00000000..a15f7387
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/index.tsx
@@ -0,0 +1,90 @@
+import { useState } from "react";
+import Modal from "@/components/Modal";
+import Icon from "@/components/Icon";
+import General from "./General";
+import Notifications from "./Notifications";
+import Speech from "./Speech";
+import Theme from "./Theme";
+import Security from "./Security";
+import DataControls from "./DataControls";
+
+import { menu } from "./menu";
+
+type Props = {
+ open: boolean;
+ onClose: () => void;
+};
+
+const Settings = ({ open, onClose }: Props) => {
+ const [activeId, setActiveId] = useState(0);
+
+ return (
+ <>
+
+
+
+ Settings
+
+
+ People with link will be able to view conversations and
+ ideas in this board.Changes you make after creating the
+ link will remain private.
+
+
+
+
+ {menu.map((item) => (
+ setActiveId(item.id)}
+ key={item.id}
+ >
+
+ {item.name}
+
+ ))}
+
+
+ {menu
+ .filter((item) => item.id === activeId)
+ .map((item) => (
+
+
+ {item.name}
+
+ ))}
+ {activeId === 0 &&
}
+ {activeId === 1 &&
}
+ {activeId === 2 &&
}
+ {activeId === 3 &&
}
+ {activeId === 4 &&
}
+ {activeId === 5 &&
}
+
+
+
+ >
+ );
+};
+
+export default Settings;
diff --git a/src/views/AgentChat/neuratalk/components/ModalSettings/menu.tsx b/src/views/AgentChat/neuratalk/components/ModalSettings/menu.tsx
new file mode 100644
index 00000000..748c4a21
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalSettings/menu.tsx
@@ -0,0 +1,32 @@
+export const menu = [
+ {
+ id: 0,
+ name: "General",
+ icon: "folder",
+ },
+ {
+ id: 1,
+ name: "Notifications",
+ icon: "bell",
+ },
+ {
+ id: 2,
+ name: "Speech",
+ icon: "voice",
+ },
+ {
+ id: 3,
+ name: "Theme",
+ icon: "document",
+ },
+ {
+ id: 4,
+ name: "Security",
+ icon: "security",
+ },
+ {
+ id: 5,
+ name: "Data Controls",
+ icon: "database",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/ModalShare/Images/index.tsx b/src/views/AgentChat/neuratalk/components/ModalShare/Images/index.tsx
new file mode 100644
index 00000000..00e1de5b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalShare/Images/index.tsx
@@ -0,0 +1,56 @@
+import { useState } from "react";
+import Image from "@/components/Image";
+
+const tabs = [
+ { id: 0, name: "Generate Images" },
+ { id: 1, name: "3 Media" },
+];
+
+const Images = ({}) => {
+ const [activeTab, setActiveTab] = useState(1);
+
+ return (
+ <>
+
+ {(activeTab === 0
+ ? ["/images/image-5.jpg"]
+ : [
+ "/images/image-6.jpg",
+ "/images/image-5.jpg",
+ "/images/image-7.jpg",
+ ]
+ ).map((image, index) => (
+
+
+
+ ))}
+
+
+
+ {tabs.map((tab) => (
+ setActiveTab(tab.id)}
+ >
+ {tab.name}
+
+ ))}
+
+
+ >
+ );
+};
+
+export default Images;
diff --git a/src/views/AgentChat/neuratalk/components/ModalShare/index.tsx b/src/views/AgentChat/neuratalk/components/ModalShare/index.tsx
new file mode 100644
index 00000000..5ccbf518
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalShare/index.tsx
@@ -0,0 +1,68 @@
+import Modal from "@/components/Modal";
+import Button from "@/components/Button";
+import Images from "./Images";
+
+type Props = {
+ open: boolean;
+ onClose: () => void;
+};
+
+const ModalShare = ({ open, onClose }: Props) => {
+ const link =
+ "Https://AIchat.ai/share/board/2ca927-2028c-2028-20nc-AA2ca927-2028c-2028-20nc-AA";
+
+ const handleCopyCode = async () => {
+ try {
+ await navigator.clipboard.writeText(link);
+ console.log("Code copied to clipboard!");
+ } catch (err) {
+ console.error("Failed to copy code: ", err);
+ }
+ };
+
+ return (
+
+
+ Share Board
+
+ People with link will be able to view conversations and ideas in
+ this board.Changes you make after creating the link will remain
+ private.
+
+
+
+
+ Cancel
+
+
+ Update & Copy Link
+
+
+
+ );
+};
+
+export default ModalShare;
diff --git a/src/views/AgentChat/neuratalk/components/ModalView/index.tsx b/src/views/AgentChat/neuratalk/components/ModalView/index.tsx
new file mode 100644
index 00000000..56bdc05a
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/ModalView/index.tsx
@@ -0,0 +1,64 @@
+import Modal from "@/components/Modal";
+import Image from "@/components/Image";
+import Button from "@/components/Button";
+
+type GalleryProps = {
+ open: boolean;
+ onClose: () => void;
+ image: string;
+};
+
+const ModalView = ({ open, onClose, image }: GalleryProps) => (
+
+
+
+
+
+
+
+ You Are still on the free plan
+
+
+ Upgrade your free plan into premium plan. Get premium Ai
+ features now and generate multiple Images !
+
+
+
+ Go Premium
+
+
+
+
+
+
+
+
+
+ Download Image
+
+
+
+);
+
+export default ModalView;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/HotKeys/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/HotKeys/index.tsx
new file mode 100644
index 00000000..0dce25ea
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/HotKeys/index.tsx
@@ -0,0 +1,53 @@
+import Image from "@/components/Image";
+
+const HotKeys = ({}) => (
+
+
+
+
+
+
+
+
+ To Navigate
+
+
+
+
+);
+
+export default HotKeys;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/index.tsx
new file mode 100644
index 00000000..44a7142c
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/index.tsx
@@ -0,0 +1,75 @@
+import { useState, useRef } from "react";
+import TextareaAutosize from "react-textarea-autosize";
+import { motion } from "framer-motion";
+import { useClickAway } from "react-use";
+import Icon from "@/components/Icon";
+import HotKeys from "./HotKeys";
+
+import { items } from "./items";
+
+const Menu = ({}) => {
+ const [visible, setVisible] = useState(false);
+ const [message, setMessage] = useState("");
+
+ const ref = useRef(null);
+ useClickAway(ref, () => {
+ setVisible(false);
+ });
+
+ return (
+
+
setVisible(!visible)}>
+
+
+ {visible && (
+
+
+
+ {items.map((item, index) => (
+
+
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+ ))}
+
+
+ setMessage(e.target.value)}
+ placeholder="Ask a question about this answer"
+ />
+
+
+ )}
+
+ );
+};
+export default Menu;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/items.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/items.tsx
new file mode 100644
index 00000000..40bd2c34
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Menu/items.tsx
@@ -0,0 +1,18 @@
+export const items = [
+ {
+ title: "Ask",
+ description: "Ask the AI anything (general chat)",
+ },
+ {
+ title: "Summarize",
+ description: "Summarize pasted text or a document",
+ },
+ {
+ title: "/Rewrite",
+ description: "Rewrite a sentence for clarity or tone",
+ },
+ {
+ title: "/Call-api",
+ description: "Call a connected external API and show the result",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Note/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Note/index.tsx
new file mode 100644
index 00000000..5fc7b87e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Note/index.tsx
@@ -0,0 +1,25 @@
+import { useState } from "react";
+import Icon from "@/components/Icon";
+
+const Note = ({}) => {
+ const [isVisible, setIsVisible] = useState(true);
+
+ return isVisible ? (
+
+
+
+
+
+ By select a feature, it will make you goal easily to achieve
+
+
setIsVisible(false)}>
+
+
+
+ ) : null;
+};
+
+export default Note;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Search/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Search/index.tsx
new file mode 100644
index 00000000..f920a884
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Search/index.tsx
@@ -0,0 +1,144 @@
+import { useState, useEffect, useRef } from "react";
+import { motion } from "framer-motion";
+import { FadeLoader } from "react-spinners";
+import { useClickAway } from "react-use";
+import Icon from "@/components/Icon";
+
+import { items } from "./items";
+
+const Search = ({}) => {
+ const [itemStates, setItemStates] = useState<
+ Array<"pending" | "loading" | "active">
+ >(new Array(items.length).fill("pending"));
+
+ const [visible, setVisible] = useState(false);
+
+ const ref = useRef(null);
+ useClickAway(ref, () => {
+ setVisible(false);
+ });
+
+ useEffect(() => {
+ if (!visible) {
+ setItemStates(new Array(items.length).fill("pending"));
+ return;
+ }
+
+ const timeouts: NodeJS.Timeout[] = [];
+
+ const animateItems = () => {
+ items.forEach((_, index) => {
+ const loadingTimeout = setTimeout(() => {
+ setItemStates((prev) => {
+ const newStates = [...prev];
+ newStates[index] = "loading";
+ return newStates;
+ });
+ }, 3000 * index);
+
+ const activeTimeout = setTimeout(() => {
+ setItemStates((prev) => {
+ const newStates = [...prev];
+ newStates[index] = "active";
+ return newStates;
+ });
+ }, 3000 * index + 3000);
+
+ timeouts.push(loadingTimeout, activeTimeout);
+ });
+ };
+
+ animateItems();
+
+ // Cleanup function - очищаємо всі таймери при зміні visible або unmount
+ return () => {
+ timeouts.forEach((timeout) => clearTimeout(timeout));
+ };
+ }, [visible]);
+
+ return (
+
+
setVisible(!visible)}>
+
+
+ {visible && (
+
+
+
+ {items.map((item, index) => {
+ const state = itemStates[index];
+ const isPending = state === "pending";
+ const isLoading = state === "loading";
+ const isActive = state === "active";
+
+ return (
+
+
+ {isLoading ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ {item.title}
+ {isActive && (
+
+ )}
+
+
+ );
+ })}
+
+
+ )}
+
+ );
+};
+export default Search;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Search/items.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Search/items.tsx
new file mode 100644
index 00000000..3292ac4b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Search/items.tsx
@@ -0,0 +1,14 @@
+export const items = [
+ {
+ title: "Searching for examples and definitions",
+ icon: "search",
+ },
+ {
+ title: "Considering Sources",
+ icon: "archive",
+ },
+ {
+ title: "Writing and running query",
+ icon: "quill",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/Speed/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/Speed/index.tsx
new file mode 100644
index 00000000..204ba88d
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/Speed/index.tsx
@@ -0,0 +1,28 @@
+import { useState } from "react";
+import Image from "@/components/Image";
+import { Switch as HeadlessSwitch } from "@headlessui/react";
+
+const Speed = ({}) => {
+ const [checked, setChecked] = useState(false);
+
+ return (
+
+
+
+ Speed
+
+
+ );
+};
+
+export default Speed;
diff --git a/src/views/AgentChat/neuratalk/components/PanelMessage/index.tsx b/src/views/AgentChat/neuratalk/components/PanelMessage/index.tsx
new file mode 100644
index 00000000..bd8aa868
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PanelMessage/index.tsx
@@ -0,0 +1,73 @@
+import { useState } from "react";
+import Link from "next/link";
+import TextareaAutosize from "react-textarea-autosize";
+import Icon from "@/components/Icon";
+import Image from "@/components/Image";
+import Note from "./Note";
+import Speed from "./Speed";
+import Search from "./Search";
+import Menu from "./Menu";
+
+type ButtonProps = {
+ className?: string;
+ icon: string;
+ onClick: () => void;
+};
+
+const Button = ({ className, icon, onClick }: ButtonProps) => {
+ return (
+
+
+
+ );
+};
+
+const PanelMessage = ({}) => {
+ const [message, setMessage] = useState("");
+
+ return (
+
+
+
+
+ setMessage(e.target.value)}
+ placeholder="Write your message ..."
+ />
+
+
+
+
+
+
{}} />
+
+ {}} />
+
+
+
+
+ {}}>
+
+
+
+
+
+ );
+};
+
+export default PanelMessage;
diff --git a/src/views/AgentChat/neuratalk/components/PythonRunner/index.tsx b/src/views/AgentChat/neuratalk/components/PythonRunner/index.tsx
new file mode 100644
index 00000000..5a00a23f
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/PythonRunner/index.tsx
@@ -0,0 +1,61 @@
+import { useState } from "react";
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import CodeEditor from "@/components/CodeEditor";
+
+const PythonRunner = () => {
+ const [isGenerating, setIsGenerating] = useState(false);
+ const [code, setCode] = useState(`# Def
+def is_prime(n):
+ # condition
+ if n <= 1:
+ return False
+ # for
+ for i in range(2, int(n**0.5) + 1):
+ if n % i == 0:
+ return False
+ return True`);
+
+ const handleGenerateCode = async () => {
+ setIsGenerating(true);
+ setTimeout(() => {
+ setCode(`# Def
+def is_prime(n):
+ # condition
+ if n <= 1:
+ return False
+ # for
+ for i in range(2, int(n**0.5) + 1):
+ if n % i == 0:
+ return False
+ return True
+
+# Test the function
+print(is_prime(17)) # True
+print(is_prime(15)) # False`);
+ setIsGenerating(false);
+ }, 2000);
+ };
+
+ return (
+
+
+ Write a Python function that checks if a number is prime.
+
+
+ Sure here is the response:
+
+
+
+ );
+};
+
+export default PythonRunner;
diff --git a/src/views/AgentChat/neuratalk/components/Question/index.tsx b/src/views/AgentChat/neuratalk/components/Question/index.tsx
new file mode 100644
index 00000000..7cbcb0eb
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Question/index.tsx
@@ -0,0 +1,28 @@
+import Image from "@/components/Image";
+
+type Props = {
+ children: React.ReactNode;
+};
+
+const Question = ({ children }: Props) => (
+
+
+
+
+
+
+
James Brown
+
1min ago
+
+ {children}
+
+
+);
+
+export default Question;
diff --git a/src/views/AgentChat/neuratalk/components/Select/index.tsx b/src/views/AgentChat/neuratalk/components/Select/index.tsx
new file mode 100644
index 00000000..4552c157
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Select/index.tsx
@@ -0,0 +1,67 @@
+import {
+ Listbox,
+ ListboxButton,
+ ListboxOption,
+ ListboxOptions,
+} from "@headlessui/react";
+import Icon from "@/components/Icon";
+
+type SelectOption = {
+ id: number;
+ name: string;
+};
+
+type SelectProps = {
+ className?: string;
+ classButton?: string;
+ value: SelectOption;
+ onChange: (value: SelectOption) => void;
+ options: SelectOption[];
+};
+
+const Select = ({
+ className,
+ classButton,
+ value,
+ onChange,
+ options,
+}: SelectProps) => {
+ return (
+
+
+ {value.name}
+
+
+
+ {options.map((option) => (
+
+ {option.name}
+
+ ))}
+
+
+ );
+};
+
+export default Select;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/Button/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/Button/index.tsx
new file mode 100644
index 00000000..08631c6b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/Button/index.tsx
@@ -0,0 +1,24 @@
+import Icon from "@/components/Icon";
+
+type Props = {
+ title: string;
+ icon: string;
+ onClick: () => void;
+};
+
+const Button = ({ title, icon, onClick }: Props) => {
+ return (
+
+
+ {title}
+
+ );
+};
+
+export default Button;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/Folders/folders.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/Folders/folders.tsx
new file mode 100644
index 00000000..df9d0f0d
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/Folders/folders.tsx
@@ -0,0 +1,34 @@
+export const folders = [
+ {
+ id: 0,
+ name: "Business plan",
+ items: [
+ {
+ id: 0,
+ name: "Buiness analysis",
+ type: "analytic",
+ },
+ {
+ id: 1,
+ name: "Journey map",
+ type: "voice",
+ },
+ ],
+ },
+ {
+ id: 1,
+ name: "Images Ideas",
+ items: [
+ {
+ id: 0,
+ name: "Images Generations",
+ type: "image",
+ },
+ {
+ id: 1,
+ name: "3 ideas for gallery",
+ type: "voice",
+ },
+ ],
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/Folders/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/Folders/index.tsx
new file mode 100644
index 00000000..bb5f1d89
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/Folders/index.tsx
@@ -0,0 +1,89 @@
+import { useState } from "react";
+import AnimateHeight from "react-animate-height";
+import Icon from "@/components/Icon";
+import Actions from "@/components/Actions";
+
+const actions = [
+ { name: "Rename", onClick: () => {} },
+ { name: "Delete", onClick: () => {} },
+ { name: "Copy", onClick: () => {} },
+];
+
+import { folders } from "./folders";
+
+const Folders = ({}) => {
+ const [active, setActive] = useState(false);
+
+ return (
+
+
setActive(!active)}
+ >
+
+ Folders
+
+
+
+
+ {folders.map((folder) => (
+
+
+
+ {folder.name}
+
+
+ {folder.items.map((item) => (
+
+ {item.type === "analytic" ? (
+
+
+
+
+
+ ) : item.type === "image" ? (
+
+ ) : (
+
+ )}
+
+ {item.name}
+
+
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+};
+
+export default Folders;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/InvitePeople/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/InvitePeople/index.tsx
new file mode 100644
index 00000000..1aca255b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/InvitePeople/index.tsx
@@ -0,0 +1,31 @@
+import { useState } from "react";
+import Field from "@/components/Field";
+import Button from "@/components/Button";
+
+const InvitePeople = ({}) => {
+ const [email, setEmail] = useState("");
+
+ return (
+ <>
+ Invite people
+
+ Send an invite to your teammates and start collaborating
+ together.
+
+ setEmail(e.target.value)}
+ required
+ />
+
+ Invite
+
+ >
+ );
+};
+
+export default InvitePeople;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/MyWorkspace/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/MyWorkspace/index.tsx
new file mode 100644
index 00000000..24bd2735
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/MyWorkspace/index.tsx
@@ -0,0 +1,50 @@
+import { useState } from "react";
+import {
+ Listbox,
+ ListboxButton,
+ ListboxOption,
+ ListboxOptions,
+} from "@headlessui/react";
+import Icon from "@/components/Icon";
+
+const options = [
+ { id: 1, name: "My Workspace" },
+ { id: 2, name: "Team Workspace" },
+ { id: 3, name: "Sandbox" },
+];
+
+const MyWorkspace = ({}) => {
+ const [value, setValue] = useState(options[0]);
+ return (
+
+
+
+ P
+
+ {value.name}
+
+
+
+ {options.map((option) => (
+
+ {option.name}
+
+ ))}
+
+
+ );
+};
+
+export default MyWorkspace;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/NavLink/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/NavLink/index.tsx
new file mode 100644
index 00000000..dacb8634
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/NavLink/index.tsx
@@ -0,0 +1,38 @@
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import Icon from "@/components/Icon";
+
+type Props = {
+ href: string;
+ title: string;
+ icon: string;
+};
+
+const NavLink = ({ href, title, icon }: Props) => {
+ const pathname = usePathname();
+ const isActive = pathname === href;
+
+ return (
+
+
+ {title}
+ {title === "Templates" && (
+
+ Beta
+
+ )}
+
+ );
+};
+
+export default NavLink;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/Upgrade/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/Upgrade/index.tsx
new file mode 100644
index 00000000..c797e62a
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/Upgrade/index.tsx
@@ -0,0 +1,53 @@
+import { useState } from "react";
+import Image from "@/components/Image";
+import Icon from "@/components/Icon";
+import ModalPlan from "@/components/ModalPlan";
+
+const Upgrade = ({}) => {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+
+
+
+
+
+
+
setOpen(true)}
+ >
+ Upgrade to Premium{" "}
+
+
+
+ Want to reach{" "}
+ more features {" "}
+ and grow much bigger?
+
+
+
+ setOpen(false)} />
+ >
+ );
+};
+
+export default Upgrade;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/User/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/User/index.tsx
new file mode 100644
index 00000000..c058187c
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/User/index.tsx
@@ -0,0 +1,30 @@
+import Link from "next/link";
+import Image from "@/components/Image";
+import Icon from "@/components/Icon";
+
+const User = ({}) => (
+
+
+
+
+
+
Emillia Caitin
+
hey@agency.com
+
+
+
+);
+
+export default User;
diff --git a/src/views/AgentChat/neuratalk/components/Sidebar/index.tsx b/src/views/AgentChat/neuratalk/components/Sidebar/index.tsx
new file mode 100644
index 00000000..4cf991a2
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Sidebar/index.tsx
@@ -0,0 +1,131 @@
+import { useState } from "react";
+import Link from "next/link";
+import Icon from "@/components/Icon";
+import Modal from "@/components/Modal";
+import ModalShare from "@/components/ModalShare";
+import ModalSettings from "@/components/ModalSettings";
+import NavLink from "./NavLink";
+import MyWorkspace from "./MyWorkspace";
+import Upgrade from "./Upgrade";
+import Button from "./Button";
+import User from "./User";
+import Folders from "./Folders";
+import InvitePeople from "./InvitePeople";
+
+type Props = {
+ visible: boolean;
+ onClose: () => void;
+ onClickNewChat: () => void;
+};
+
+const Sidebar = ({ visible, onClose, onClickNewChat }: Props) => {
+ const [open, setOpen] = useState(false);
+ const [openModalShare, setOpenModalShare] = useState(false);
+ const [openModalInvite, setOpenModalInvite] = useState(false);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ Chat With AI
+
+
+
+ Today
+
+
+
+
+ mental health problems
+
+
+
+
+
setOpenModalShare(true)}
+ />
+
+
+
+
+
+ {}}
+ />
+ setOpenModalInvite(true)}
+ />
+ setOpen(true)}
+ />
+
+
+
+
+ setOpen(false)} />
+ setOpenModalShare(false)}
+ />
+ setOpenModalInvite(false)}
+ >
+
+
+ >
+ );
+};
+
+export default Sidebar;
diff --git a/src/views/AgentChat/neuratalk/components/SoloImage/index.tsx b/src/views/AgentChat/neuratalk/components/SoloImage/index.tsx
new file mode 100644
index 00000000..2d36d371
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/SoloImage/index.tsx
@@ -0,0 +1,28 @@
+import { useState } from "react";
+import Image from "@/components/Image";
+import ModalView from "@/components/ModalView";
+
+const SoloImage = ({}) => {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}>
+
+
+ setOpen(false)}
+ image="/images/image-1.jpg"
+ />
+ >
+ );
+};
+
+export default SoloImage;
diff --git a/src/views/AgentChat/neuratalk/components/Switch/index.tsx b/src/views/AgentChat/neuratalk/components/Switch/index.tsx
new file mode 100644
index 00000000..cb3174c4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Switch/index.tsx
@@ -0,0 +1,28 @@
+import { Switch as HeadlessSwitch } from "@headlessui/react";
+
+type SwitchProps = {
+ className?: string;
+ checked: boolean;
+ onChange: (checked: boolean) => void;
+ isSmall?: boolean;
+};
+
+const Switch = ({ className, checked, onChange, isSmall }: SwitchProps) => (
+
+
+
+);
+
+export default Switch;
diff --git a/src/views/AgentChat/neuratalk/components/Tabs/index.tsx b/src/views/AgentChat/neuratalk/components/Tabs/index.tsx
new file mode 100644
index 00000000..5141567e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Tabs/index.tsx
@@ -0,0 +1,44 @@
+type TabItem = {
+ id: number;
+ name: string;
+ onClick?: () => void;
+};
+
+type Props = {
+ className?: string;
+ items: TabItem[];
+ value: TabItem;
+ setValue: (value: TabItem) => void;
+};
+
+const Tabs = ({ className, items, value, setValue }: Props) => {
+ return (
+
+
+
+ {items.map((item) => (
+
{
+ setValue(item);
+ item.onClick?.();
+ }}
+ >
+ {item.name}
+
+ ))}
+
+
+ );
+};
+
+export default Tabs;
diff --git a/src/views/AgentChat/neuratalk/components/Test/index.tsx b/src/views/AgentChat/neuratalk/components/Test/index.tsx
new file mode 100644
index 00000000..d00b2011
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Test/index.tsx
@@ -0,0 +1,3 @@
+const Test = ({}) =>
;
+
+export default Test;
diff --git a/src/views/AgentChat/neuratalk/components/Tools/Group/index.tsx b/src/views/AgentChat/neuratalk/components/Tools/Group/index.tsx
new file mode 100644
index 00000000..b10d4b51
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Tools/Group/index.tsx
@@ -0,0 +1,60 @@
+import Icon from "@/components/Icon";
+import Switch from "@/components/Switch";
+
+type Props = {
+ group: {
+ id: string;
+ title: string;
+ items: {
+ id: string;
+ title: string;
+ description: string;
+ icon: string;
+ }[];
+ };
+ activeId: string | null;
+ setActiveId: (id: string | null) => void;
+};
+
+const Group = ({ group, activeId, setActiveId }: Props) => {
+ return (
+
+
+ {group.title}
+
+
+ {group.items.map((item) => (
+
+
+
+
{item.title}
+
{
+ setActiveId(
+ activeId === item.id ? null : item.id
+ );
+ }}
+ />
+
+
+ {item.description}
+
+
+ ))}
+
+
+ );
+};
+
+export default Group;
diff --git a/src/views/AgentChat/neuratalk/components/Tools/index.tsx b/src/views/AgentChat/neuratalk/components/Tools/index.tsx
new file mode 100644
index 00000000..447cfc98
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Tools/index.tsx
@@ -0,0 +1,61 @@
+import { useState } from "react";
+import Icon from "@/components/Icon";
+import Tabs from "@/components/Tabs";
+import Group from "./Group";
+
+import { menu } from "./menu";
+
+type Props = {
+ activeId: string | null;
+ setActiveId: (id: string | null) => void;
+ visible: boolean;
+ onClose: () => void;
+};
+
+const tabs = [
+ { id: 0, name: "Tools" },
+ { id: 1, name: "Files" },
+];
+
+const Tools = ({ activeId, setActiveId, visible, onClose }: Props) => {
+ const [tab, setTab] = useState(tabs[0]);
+
+ return (
+
+
+
+
+ {menu.map((group) => (
+
+ ))}
+
+
+ );
+};
+
+export default Tools;
diff --git a/src/views/AgentChat/neuratalk/components/Tools/menu.tsx b/src/views/AgentChat/neuratalk/components/Tools/menu.tsx
new file mode 100644
index 00000000..b2373e05
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/Tools/menu.tsx
@@ -0,0 +1,63 @@
+export const menu = [
+ {
+ id: "basic",
+ title: "Basic Tools",
+ items: [
+ {
+ id: "python",
+ title: "Python Runner",
+ description:
+ "Execute Python scripts directly for quick calculations or automation.",
+ icon: "python",
+ },
+ {
+ id: "calculator",
+ title: "Calculator",
+ description:
+ "Perform simple to complex mathematical operations effortlessly.",
+ icon: "calculator",
+ },
+ {
+ id: "browser",
+ title: "Web Search",
+ description:
+ "Find information online with instant AI-powered search capabilities.",
+ icon: "browser",
+ },
+ {
+ id: "web-design",
+ title: "URL Scraper",
+ description:
+ "Extract and organize data from websites with ease.",
+ icon: "web-design",
+ },
+ ],
+ },
+ {
+ id: "advanced",
+ title: "Advanced Tools",
+ items: [
+ {
+ id: "exchange",
+ title: "File Converter",
+ description:
+ "Execute Python scripts directly for quick calculations or automation.",
+ icon: "exchange",
+ },
+ {
+ id: "language",
+ title: "Language Translator",
+ description:
+ "Perform simple to complex mathematical operations effortlessly.",
+ icon: "language",
+ },
+ {
+ id: "api",
+ title: "API Integrator",
+ description:
+ "Perform simple to complex mathematical operations effortlessly.",
+ icon: "api",
+ },
+ ],
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/VoiceChat/index.tsx b/src/views/AgentChat/neuratalk/components/VoiceChat/index.tsx
new file mode 100644
index 00000000..af1756b5
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/VoiceChat/index.tsx
@@ -0,0 +1,161 @@
+import { useRef, useState } from "react";
+import { Swiper, SwiperSlide } from "swiper/react";
+import type { Swiper as SwiperType } from "swiper";
+import Image from "@/components/Image";
+import Icon from "@/components/Icon";
+import Button from "@/components/Button";
+import "swiper/css";
+import "swiper/css/navigation";
+
+import { Navigation } from "swiper/modules";
+
+import { items } from "./items";
+
+const VoiceChat = ({}) => {
+ const swiperRef = useRef(null);
+ const [isBeginning, setIsBeginning] = useState(false);
+ const [isEnd, setIsEnd] = useState(false);
+ const [isListening, setIsListening] = useState(false);
+
+ const handlePrev = () => {
+ if (swiperRef.current) {
+ swiperRef.current.slidePrev();
+ }
+ };
+
+ const handleNext = () => {
+ if (swiperRef.current) {
+ swiperRef.current.slideNext();
+ }
+ };
+
+ const handleSlideChange = (swiper: SwiperType) => {
+ setIsBeginning(swiper.isBeginning);
+ setIsEnd(swiper.isEnd);
+ };
+
+ return isListening ? (
+ <>
+
+
+ I’m listing now...
+
+
+ "I’ve been trying to log into my account, but every
+ time I enter my credentials, I get an error message saying
+ 'Invalid Password.' I’m 100% sure I’m using the
+ correct password since it worked just fine yesterday.{" "}
+
+ To resolve this, I tried the 'Forgot Password'
+ option, but I haven’t received any password reset email
+ yet (I’ve checked my spam/junk folders too)."
+
+
+
+
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+
+ Choose a voice
+
+
+
+
{
+ swiperRef.current = swiper;
+ setIsBeginning(swiper.isBeginning);
+ setIsEnd(swiper.isEnd);
+ }}
+ onSlideChange={handleSlideChange}
+ breakpoints={{
+ 768: {
+ spaceBetween: 38,
+ },
+ }}
+ >
+ {items.map((item) => (
+ setIsListening(true)}
+ >
+
+ {item.title}
+
+
+ {item.description}
+
+
+ ))}
+
+
+ {!isBeginning && (
+
+
+
+ )}
+ {!isEnd && (
+
+
+
+ )}
+
+
+
+
+
+
+ Start new chat
+
+
+ Cancel
+
+
+ >
+ );
+};
+
+export default VoiceChat;
diff --git a/src/views/AgentChat/neuratalk/components/VoiceChat/items.tsx b/src/views/AgentChat/neuratalk/components/VoiceChat/items.tsx
new file mode 100644
index 00000000..64fb5f53
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/VoiceChat/items.tsx
@@ -0,0 +1,17 @@
+export const items = [
+ {
+ id: 0,
+ title: "Aurora",
+ description: "Bright and clear, lighting up your interactions.",
+ },
+ {
+ id: 1,
+ title: "Echo",
+ description: "Reflective and precise, amplifying your questions.",
+ },
+ {
+ id: 2,
+ title: "Tempo",
+ description: "Rhythmic and steady, keeping you on track.",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/WebDesign/content.tsx b/src/views/AgentChat/neuratalk/components/WebDesign/content.tsx
new file mode 100644
index 00000000..d7c5cfaa
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/WebDesign/content.tsx
@@ -0,0 +1,42 @@
+export const content = [
+ {
+ id: 0,
+ avatar: "/images/avatar-3.jpg",
+ title: "Supervision Skills in Safeguarding",
+ description:
+ "This self-paced online course in supervision skills in safeguarding will help you improved you understanding of....",
+ person: "Terrance Jaskolski",
+ email: "Terrance23@yahoo.com",
+ time: "1 day ago",
+ },
+ {
+ id: 1,
+ avatar: "/images/avatar-3.jpg",
+ title: "Supervision Skills in Safeguarding",
+ description:
+ "This self-paced online course in supervision skills in safeguarding will help you improved you understanding of....",
+ person: "Terrance Jaskolski",
+ email: "Terrance23@yahoo.com",
+ time: "1 day ago",
+ },
+ {
+ id: 2,
+ avatar: "/images/avatar-3.jpg",
+ title: "Supervision Skills in Safeguarding",
+ description:
+ "This self-paced online course in supervision skills in safeguarding will help you improved you understanding of....",
+ person: "Terrance Jaskolski",
+ email: "Terrance23@yahoo.com",
+ time: "1 day ago",
+ },
+ {
+ id: 3,
+ avatar: "/images/avatar-3.jpg",
+ title: "Supervision Skills in Safeguarding",
+ description:
+ "This self-paced online course in supervision skills in safeguarding will help you improved you understanding of....",
+ person: "Terrance Jaskolski",
+ email: "Terrance23@yahoo.com",
+ time: "1 day ago",
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/components/WebDesign/index.tsx b/src/views/AgentChat/neuratalk/components/WebDesign/index.tsx
new file mode 100644
index 00000000..deee1d41
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/components/WebDesign/index.tsx
@@ -0,0 +1,77 @@
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import Image from "@/components/Image";
+
+import { content } from "./content";
+
+const WebDesign = () => {
+ return (
+
+
+ Scrape this URL and give me all the links:{" "}
+
+ https://example.com
+
+
+
+
+ If you're searching for the most beautiful websites
+ built with Webflow, there are several standout examples that
+ showcase the platform's capabilities in design,
+ interactivity, and storytelling. Here are some notable ones:
+
+
+ {content.map((item, index) => (
+
+
+ Article #{index + 1}
+
+
+ {item.title}
+
+
+ {item.description}
+
+ See more
+
+
+
+
+
+
+
+
+ {item.person}
+
+
+ {item.email}
+
+
+
+ {item.time}
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default WebDesign;
diff --git a/src/views/AgentChat/neuratalk/eslint.config.mjs b/src/views/AgentChat/neuratalk/eslint.config.mjs
new file mode 100644
index 00000000..719cea2b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/eslint.config.mjs
@@ -0,0 +1,25 @@
+import { dirname } from "path";
+import { fileURLToPath } from "url";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+});
+
+const eslintConfig = [
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
+ {
+ ignores: [
+ "node_modules/**",
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ ],
+ },
+];
+
+export default eslintConfig;
diff --git a/src/views/AgentChat/neuratalk/hooks/useAuth.tsx b/src/views/AgentChat/neuratalk/hooks/useAuth.tsx
new file mode 100644
index 00000000..ef27e3fb
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/hooks/useAuth.tsx
@@ -0,0 +1,49 @@
+// hooks/useAuth.tsx - React Hook 封装认证逻辑
+'use client';
+
+import { useState, useEffect } from 'react';
+import { checkAuth, AuthInfo } from '../lib/auth';
+
+export function useAuth() {
+ const [authInfo, setAuthInfo] = useState({
+ isAuthenticated: false,
+ });
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ // 组件挂载时检查认证状态
+ const verifyAuth = async () => {
+ try {
+ const info = await checkAuth();
+ setAuthInfo(info);
+ } catch (error) {
+ console.error('Auth verification failed:', error);
+ setAuthInfo({
+ isAuthenticated: false,
+ message: '认证检查失败',
+ });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ verifyAuth();
+
+ // 可选:定期检查认证状态
+ const interval = setInterval(verifyAuth, 5 * 60 * 1000); // 每5分钟
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return {
+ ...authInfo,
+ loading,
+ refresh: async () => {
+ setLoading(true);
+ const info = await checkAuth();
+ setAuthInfo(info);
+ setLoading(false);
+ return info;
+ },
+ };
+}
\ No newline at end of file
diff --git a/src/views/AgentChat/neuratalk/lib/auth.ts b/src/views/AgentChat/neuratalk/lib/auth.ts
new file mode 100644
index 00000000..cc5d7af4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/lib/auth.ts
@@ -0,0 +1,103 @@
+// lib/auth.ts - 简化版认证工具
+// 用于在 Next.js 中获取主应用的登录信息
+
+export interface User {
+ id: string;
+ username: string;
+ email: string;
+ subscription_tier: string;
+ avatar?: string;
+}
+
+export interface AuthInfo {
+ isAuthenticated: boolean;
+ user?: User;
+ canAccessChat?: boolean;
+ message?: string;
+}
+
+/**
+ * 客户端检查认证状态
+ * 直接调用 Flask 后端的 session 接口
+ */
+export async function checkAuth(): Promise {
+ try {
+ // 调用主应用的 session 检查接口
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/auth/session`, {
+ credentials: 'include', // 重要:携带 Cookie
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ if (!response.ok) {
+ return { isAuthenticated: false };
+ }
+
+ const data = await response.json();
+
+ // 检查是否登录
+ if (!data.isAuthenticated || !data.user) {
+ return {
+ isAuthenticated: false,
+ message: '请先登录'
+ };
+ }
+
+ // 检查订阅权限
+ const canAccessChat = ['premium', 'pro', 'enterprise'].includes(
+ data.user.subscription_tier?.toLowerCase()
+ );
+
+ return {
+ isAuthenticated: true,
+ user: data.user,
+ canAccessChat,
+ message: canAccessChat ? undefined : '需要订阅才能使用 AI 助手功能'
+ };
+ } catch (error) {
+ console.error('Auth check failed:', error);
+ return {
+ isAuthenticated: false,
+ message: '认证服务暂时不可用'
+ };
+ }
+}
+
+/**
+ * 调用 MCP API
+ * 自动携带认证信息
+ */
+export async function callMCPApi(endpoint: string, options: RequestInit = {}) {
+ const url = `${process.env.NEXT_PUBLIC_API_URL}${endpoint}`;
+
+ const response = await fetch(url, {
+ ...options,
+ credentials: 'include', // 携带 Cookie
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers,
+ },
+ });
+
+ if (response.status === 401) {
+ // 未登录,跳转到主应用登录页
+ window.location.href = `${process.env.NEXT_PUBLIC_MAIN_APP_URL}/auth/sign-in?redirect=/chat`;
+ throw new Error('Unauthorized');
+ }
+
+ if (response.status === 403) {
+ // 无权限,跳转到订阅页
+ window.location.href = `${process.env.NEXT_PUBLIC_MAIN_APP_URL}/subscription?feature=ai-chat`;
+ throw new Error('Subscription required');
+ }
+
+ return response;
+}
+
+/**
+ * 登出(跳转到主应用的登出接口)
+ */
+export function logout() {
+ window.location.href = `${process.env.NEXT_PUBLIC_MAIN_APP_URL}/api/auth/logout?redirect=/`;
+}
\ No newline at end of file
diff --git a/src/views/AgentChat/neuratalk/next.config.ts b/src/views/AgentChat/neuratalk/next.config.ts
new file mode 100644
index 00000000..af197f9f
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/next.config.ts
@@ -0,0 +1,42 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ // 配置基础路径为 /ai-chat
+ basePath: '/ai-chat',
+
+ // 配置资源前缀
+ assetPrefix: '/ai-chat/',
+
+ // 启用严格模式
+ reactStrictMode: true,
+
+ // 生产环境优化
+ poweredByHeader: false,
+
+ // 环境变量
+ env: {
+ // 这些会在构建时被替换
+ NEXT_PUBLIC_BASE_PATH: '/ai-chat',
+ },
+
+ // 重写规则 - 将 API 请求代理到后端
+ async rewrites() {
+ return [
+ {
+ source: '/api/:path*',
+ destination: 'http://localhost:5001/api/:path*',
+ },
+ {
+ source: '/mcp/:path*',
+ destination: 'http://localhost:8900/:path*',
+ },
+ ];
+ },
+
+ // 配置允许的域名(用于 Next.js Image 组件)
+ images: {
+ domains: ['valuefrontier.cn', 'localhost'],
+ },
+};
+
+export default nextConfig;
diff --git a/src/views/AgentChat/neuratalk/package.json b/src/views/AgentChat/neuratalk/package.json
new file mode 100644
index 00000000..4c1ed77b
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "neuratalk",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "eslint"
+ },
+ "dependencies": {
+ "@headlessui/react": "^2.2.8",
+ "@monaco-editor/react": "^4.7.0",
+ "framer-motion": "^12.23.22",
+ "millify": "^6.1.0",
+ "monaco-editor": "^0.53.0",
+ "next": "15.5.3",
+ "next-themes": "^0.4.6",
+ "react": "19.1.0",
+ "react-animate-height": "^3.2.3",
+ "react-dom": "19.1.0",
+ "react-spinners": "^0.17.0",
+ "react-textarea-autosize": "^8.5.9",
+ "react-use": "^17.6.0",
+ "recharts": "^3.2.1",
+ "swiper": "^12.0.2",
+ "tailwind-scrollbar": "^4.0.2"
+ },
+ "devDependencies": {
+ "@eslint/eslintrc": "^3",
+ "@tailwindcss/postcss": "^4",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "eslint": "^9",
+ "eslint-config-next": "15.5.3",
+ "tailwindcss": "^4",
+ "typescript": "^5"
+ }
+}
diff --git a/src/views/AgentChat/neuratalk/postcss.config.mjs b/src/views/AgentChat/neuratalk/postcss.config.mjs
new file mode 100644
index 00000000..c7bcb4b1
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/postcss.config.mjs
@@ -0,0 +1,5 @@
+const config = {
+ plugins: ["@tailwindcss/postcss"],
+};
+
+export default config;
diff --git a/src/views/AgentChat/neuratalk/public/fb-og-image.png b/src/views/AgentChat/neuratalk/public/fb-og-image.png
new file mode 100644
index 00000000..d9e0d6bb
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fb-og-image.png differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/InterDisplay-Medium.woff2 b/src/views/AgentChat/neuratalk/public/fonts/InterDisplay-Medium.woff2
new file mode 100644
index 00000000..f6157fae
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/InterDisplay-Medium.woff2 differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff
new file mode 100644
index 00000000..9ecd349a
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff2 b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff2
new file mode 100644
index 00000000..a3cea6bf
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Bold.woff2 differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff
new file mode 100644
index 00000000..655ed4d3
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff2 b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff2
new file mode 100644
index 00000000..e07088ab
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Light.woff2 differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff
new file mode 100644
index 00000000..26a4d200
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff2 b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff2
new file mode 100644
index 00000000..e02fbdfc
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Medium.woff2 differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff
new file mode 100644
index 00000000..66c3144b
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff differ
diff --git a/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff2 b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff2
new file mode 100644
index 00000000..76408470
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/fonts/Satoshi-Regular.woff2 differ
diff --git a/src/views/AgentChat/neuratalk/public/images/ai-image.svg b/src/views/AgentChat/neuratalk/public/images/ai-image.svg
new file mode 100644
index 00000000..1076f11e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/ai-image.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/ai-programming.svg b/src/views/AgentChat/neuratalk/public/images/ai-programming.svg
new file mode 100644
index 00000000..90d11111
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/ai-programming.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/ai-search.svg b/src/views/AgentChat/neuratalk/public/images/ai-search.svg
new file mode 100644
index 00000000..bfb4f19e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/ai-search.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/ai-voice.png b/src/views/AgentChat/neuratalk/public/images/ai-voice.png
new file mode 100644
index 00000000..caaf5a3b
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/ai-voice.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/auth-pic.jpg b/src/views/AgentChat/neuratalk/public/images/auth-pic.jpg
new file mode 100644
index 00000000..527b30b5
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/auth-pic.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-1.png b/src/views/AgentChat/neuratalk/public/images/avatar-1.png
new file mode 100644
index 00000000..51dd0f64
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-1.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-2.png b/src/views/AgentChat/neuratalk/public/images/avatar-2.png
new file mode 100644
index 00000000..ed1bdeaf
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-2.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-3.jpg b/src/views/AgentChat/neuratalk/public/images/avatar-3.jpg
new file mode 100644
index 00000000..4727b644
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-3.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-4.jpg b/src/views/AgentChat/neuratalk/public/images/avatar-4.jpg
new file mode 100644
index 00000000..6dadab6e
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-4.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-5.jpg b/src/views/AgentChat/neuratalk/public/images/avatar-5.jpg
new file mode 100644
index 00000000..b6472222
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-5.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-6.jpg b/src/views/AgentChat/neuratalk/public/images/avatar-6.jpg
new file mode 100644
index 00000000..47ba59ff
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/avatar-6.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/avatar-chat.svg b/src/views/AgentChat/neuratalk/public/images/avatar-chat.svg
new file mode 100644
index 00000000..e7605038
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/avatar-chat.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/bg-toggle.png b/src/views/AgentChat/neuratalk/public/images/bg-toggle.png
new file mode 100644
index 00000000..3bab2f9f
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/bg-toggle.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/browser-pic-1.jpg b/src/views/AgentChat/neuratalk/public/images/browser-pic-1.jpg
new file mode 100644
index 00000000..9254cba5
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/browser-pic-1.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/browser-pic-2.jpg b/src/views/AgentChat/neuratalk/public/images/browser-pic-2.jpg
new file mode 100644
index 00000000..e6aded76
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/browser-pic-2.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/code.svg b/src/views/AgentChat/neuratalk/public/images/code.svg
new file mode 100644
index 00000000..dbaff940
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/code.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/doc-type.svg b/src/views/AgentChat/neuratalk/public/images/doc-type.svg
new file mode 100644
index 00000000..f2b4382a
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/doc-type.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/document-pic-1.jpg b/src/views/AgentChat/neuratalk/public/images/document-pic-1.jpg
new file mode 100644
index 00000000..7807c67a
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/document-pic-1.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/document-pic-2.jpg b/src/views/AgentChat/neuratalk/public/images/document-pic-2.jpg
new file mode 100644
index 00000000..6c7fdf58
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/document-pic-2.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/document-pic-3.jpg b/src/views/AgentChat/neuratalk/public/images/document-pic-3.jpg
new file mode 100644
index 00000000..a0a10236
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/document-pic-3.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/document-validation.svg b/src/views/AgentChat/neuratalk/public/images/document-validation.svg
new file mode 100644
index 00000000..7315c09e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/document-validation.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/download.svg b/src/views/AgentChat/neuratalk/public/images/download.svg
new file mode 100644
index 00000000..57eeeafe
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/download.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/google.svg b/src/views/AgentChat/neuratalk/public/images/google.svg
new file mode 100644
index 00000000..b92beabc
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/google.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/image-1.jpg b/src/views/AgentChat/neuratalk/public/images/image-1.jpg
new file mode 100644
index 00000000..69219368
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-1.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-2.jpg b/src/views/AgentChat/neuratalk/public/images/image-2.jpg
new file mode 100644
index 00000000..c6f7c6ec
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-2.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-3.jpg b/src/views/AgentChat/neuratalk/public/images/image-3.jpg
new file mode 100644
index 00000000..6a0f5454
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-3.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-4.jpg b/src/views/AgentChat/neuratalk/public/images/image-4.jpg
new file mode 100644
index 00000000..d9cee3fc
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-4.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-5.jpg b/src/views/AgentChat/neuratalk/public/images/image-5.jpg
new file mode 100644
index 00000000..14c25a96
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-5.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-6.jpg b/src/views/AgentChat/neuratalk/public/images/image-6.jpg
new file mode 100644
index 00000000..87e84f4d
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-6.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/image-7.jpg b/src/views/AgentChat/neuratalk/public/images/image-7.jpg
new file mode 100644
index 00000000..1f3e7140
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/image-7.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/key-square-arrow-down.svg b/src/views/AgentChat/neuratalk/public/images/key-square-arrow-down.svg
new file mode 100644
index 00000000..88d00bca
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/key-square-arrow-down.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/key-square-enter.svg b/src/views/AgentChat/neuratalk/public/images/key-square-enter.svg
new file mode 100644
index 00000000..5839c6a6
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/key-square-enter.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/license.svg b/src/views/AgentChat/neuratalk/public/images/license.svg
new file mode 100644
index 00000000..68b153b4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/license.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/logo-auth.svg b/src/views/AgentChat/neuratalk/public/images/logo-auth.svg
new file mode 100644
index 00000000..85a96318
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/logo-auth.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/pie-chart.svg b/src/views/AgentChat/neuratalk/public/images/pie-chart.svg
new file mode 100644
index 00000000..3862f743
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/pie-chart.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/sent.svg b/src/views/AgentChat/neuratalk/public/images/sent.svg
new file mode 100644
index 00000000..b2066eb0
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/sent.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/slider-pic-1.png b/src/views/AgentChat/neuratalk/public/images/slider-pic-1.png
new file mode 100644
index 00000000..c3bfc053
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/slider-pic-1.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/stars-white.svg b/src/views/AgentChat/neuratalk/public/images/stars-white.svg
new file mode 100644
index 00000000..c6d7a2cc
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/stars-white.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/stars.svg b/src/views/AgentChat/neuratalk/public/images/stars.svg
new file mode 100644
index 00000000..43435ee4
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/stars.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-1.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-1.jpg
new file mode 100644
index 00000000..92fa9f77
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-1.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-2.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-2.jpg
new file mode 100644
index 00000000..ee66a3f9
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-2.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-3.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-3.jpg
new file mode 100644
index 00000000..e05d944f
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-3.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-4.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-4.jpg
new file mode 100644
index 00000000..66d4f6d1
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-4.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-5.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-5.jpg
new file mode 100644
index 00000000..857bcaa7
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-5.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-6.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-6.jpg
new file mode 100644
index 00000000..974c1b1f
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-6.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-7.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-7.jpg
new file mode 100644
index 00000000..9fb294db
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-7.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/templates-pic-8.jpg b/src/views/AgentChat/neuratalk/public/images/templates-pic-8.jpg
new file mode 100644
index 00000000..0e4e9c8e
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/templates-pic-8.jpg differ
diff --git a/src/views/AgentChat/neuratalk/public/images/theme-dark.png b/src/views/AgentChat/neuratalk/public/images/theme-dark.png
new file mode 100644
index 00000000..db31e9d1
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/theme-dark.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/theme-light.png b/src/views/AgentChat/neuratalk/public/images/theme-light.png
new file mode 100644
index 00000000..fa3d48f8
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/theme-light.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/theme-preference.png b/src/views/AgentChat/neuratalk/public/images/theme-preference.png
new file mode 100644
index 00000000..0fb3487e
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/theme-preference.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/trash.svg b/src/views/AgentChat/neuratalk/public/images/trash.svg
new file mode 100644
index 00000000..c60f174e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/trash.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/images/upgrade-pic-dark.png b/src/views/AgentChat/neuratalk/public/images/upgrade-pic-dark.png
new file mode 100644
index 00000000..dfe259d6
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/upgrade-pic-dark.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/upgrade-pic-light.png b/src/views/AgentChat/neuratalk/public/images/upgrade-pic-light.png
new file mode 100644
index 00000000..5184b11e
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/images/upgrade-pic-light.png differ
diff --git a/src/views/AgentChat/neuratalk/public/images/xls-type.svg b/src/views/AgentChat/neuratalk/public/images/xls-type.svg
new file mode 100644
index 00000000..d916351c
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/public/images/xls-type.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AgentChat/neuratalk/public/linkedin-og-image.png b/src/views/AgentChat/neuratalk/public/linkedin-og-image.png
new file mode 100644
index 00000000..761975c4
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/linkedin-og-image.png differ
diff --git a/src/views/AgentChat/neuratalk/public/pinterest-og-image.png b/src/views/AgentChat/neuratalk/public/pinterest-og-image.png
new file mode 100644
index 00000000..10f2a707
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/pinterest-og-image.png differ
diff --git a/src/views/AgentChat/neuratalk/public/twitter-card.png b/src/views/AgentChat/neuratalk/public/twitter-card.png
new file mode 100644
index 00000000..b8e4a0bf
Binary files /dev/null and b/src/views/AgentChat/neuratalk/public/twitter-card.png differ
diff --git a/src/views/AgentChat/neuratalk/services/mcp-real.ts b/src/views/AgentChat/neuratalk/services/mcp-real.ts
new file mode 100644
index 00000000..586b339a
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/services/mcp-real.ts
@@ -0,0 +1,277 @@
+// services/mcp-real.ts - 对接真实的 MCP 服务器接口
+import { checkAuth } from '../lib/auth';
+
+// ========== 类型定义 ==========
+export interface ChatMessage {
+ role: 'user' | 'assistant' | 'system';
+ content: string;
+ timestamp?: string;
+}
+
+export interface Tool {
+ name: string;
+ description: string;
+ input_schema: {
+ type: string;
+ properties: Record;
+ required?: string[];
+ };
+}
+
+export interface ToolCallRequest {
+ tool: string;
+ arguments: Record;
+}
+
+export interface ToolCallResponse {
+ tool: string;
+ result: any;
+ error?: string;
+ execution_time?: number;
+}
+
+// ========== MCP 服务类 ==========
+export class MCPService {
+ // 使用相对路径,通过 Nginx 代理访问
+ private baseUrl = '/mcp';
+ private chatHistory: ChatMessage[] = [];
+
+ /**
+ * 获取可用工具列表
+ */
+ async getTools(): Promise {
+ try {
+ const response = await fetch(`${this.baseUrl}/tools`, {
+ method: 'GET',
+ credentials: 'include',
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to get tools: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return data.tools || [];
+ } catch (error) {
+ console.error('Failed to get tools:', error);
+ return [];
+ }
+ }
+
+ /**
+ * 调用特定工具
+ */
+ async callTool(toolName: string, args: Record): Promise {
+ try {
+ const response = await fetch(`${this.baseUrl}/tools/call`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify({
+ tool: toolName,
+ arguments: args,
+ }),
+ });
+
+ if (!response.ok) {
+ const error = await response.text();
+ throw new Error(`Tool call failed: ${error}`);
+ }
+
+ return await response.json();
+ } catch (error) {
+ console.error('Tool call error:', error);
+ throw error;
+ }
+ }
+
+ /**
+ * 发送聊天消息(非流式)
+ */
+ async sendMessage(message: string): Promise {
+ // 添加用户消息到历史
+ this.chatHistory.push({
+ role: 'user',
+ content: message,
+ timestamp: new Date().toISOString(),
+ });
+
+ try {
+ const response = await fetch(`${this.baseUrl}/chat`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify({
+ messages: this.chatHistory,
+ stream: false,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Chat failed: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+
+ // 添加助手回复到历史
+ if (data.response) {
+ this.chatHistory.push({
+ role: 'assistant',
+ content: data.response,
+ timestamp: new Date().toISOString(),
+ });
+ }
+
+ return data.response || data.message || '抱歉,没有收到有效的回复';
+ } catch (error) {
+ console.error('Send message error:', error);
+ throw error;
+ }
+ }
+
+ /**
+ * 发送聊天消息(流式响应)
+ */
+ async *streamMessage(message: string): AsyncGenerator {
+ // 添加用户消息到历史
+ this.chatHistory.push({
+ role: 'user',
+ content: message,
+ timestamp: new Date().toISOString(),
+ });
+
+ try {
+ const response = await fetch(`${this.baseUrl}/chat`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify({
+ messages: this.chatHistory,
+ stream: true,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Stream failed: ${response.statusText}`);
+ }
+
+ // 处理 SSE 流
+ const reader = response.body?.getReader();
+ const decoder = new TextDecoder();
+
+ if (!reader) {
+ throw new Error('No response body');
+ }
+
+ let buffer = '';
+ let fullResponse = '';
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split('\n');
+
+ // 保留最后一行(可能不完整)
+ buffer = lines.pop() || '';
+
+ for (const line of lines) {
+ if (line.startsWith('data: ')) {
+ const data = line.slice(6).trim();
+
+ if (data === '[DONE]') {
+ // 流结束,保存完整回复到历史
+ if (fullResponse) {
+ this.chatHistory.push({
+ role: 'assistant',
+ content: fullResponse,
+ timestamp: new Date().toISOString(),
+ });
+ }
+ return;
+ }
+
+ try {
+ const parsed = JSON.parse(data);
+ const content = parsed.content || parsed.delta?.content || '';
+ fullResponse += content;
+ yield content;
+ } catch (e) {
+ // 如果不是 JSON,直接输出
+ fullResponse += data;
+ yield data;
+ }
+ }
+ }
+ }
+ } catch (error) {
+ console.error('Stream message error:', error);
+ throw error;
+ }
+ }
+
+ /**
+ * 清空聊天历史
+ */
+ clearHistory() {
+ this.chatHistory = [];
+ }
+
+ /**
+ * 获取聊天历史
+ */
+ getHistory(): ChatMessage[] {
+ return this.chatHistory;
+ }
+
+ /**
+ * 执行代码(通过 code_interpreter 工具)
+ */
+ async executeCode(code: string, language: string = 'python'): Promise {
+ return this.callTool('code_interpreter', {
+ code,
+ language,
+ });
+ }
+
+ /**
+ * 文件操作工具封装
+ */
+ async readFile(path: string): Promise {
+ const result = await this.callTool('read_file', { path });
+ return result.result?.content || '';
+ }
+
+ async writeFile(path: string, content: string): Promise {
+ await this.callTool('write_file', { path, content });
+ }
+
+ async listDirectory(path: string = '.'): Promise {
+ const result = await this.callTool('list_directory', { path });
+ return result.result?.files || [];
+ }
+
+ /**
+ * 搜索工具封装
+ */
+ async search(query: string): Promise {
+ return this.callTool('search', { query });
+ }
+
+ /**
+ * 创建文件工具
+ */
+ async createFile(path: string, content: string): Promise {
+ await this.callTool('create_file', { path, content });
+ }
+}
+
+// 导出单例
+export const mcpService = new MCPService();
\ No newline at end of file
diff --git a/src/views/AgentChat/neuratalk/services/mcp.ts b/src/views/AgentChat/neuratalk/services/mcp.ts
new file mode 100644
index 00000000..b3ea4c06
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/services/mcp.ts
@@ -0,0 +1,138 @@
+// services/mcp.ts - MCP API 调用服务
+import { callMCPApi } from '../lib/auth';
+
+export interface ChatMessage {
+ role: 'user' | 'assistant' | 'system';
+ content: string;
+ timestamp?: string;
+ tools?: any[];
+}
+
+export interface ChatSession {
+ id: string;
+ messages: ChatMessage[];
+ createdAt: string;
+ updatedAt: string;
+}
+
+export class MCPService {
+ /**
+ * 发送聊天消息到 MCP
+ */
+ async sendMessage(message: string, sessionId?: string): Promise {
+ const response = await callMCPApi('/api/mcp/chat', {
+ method: 'POST',
+ body: JSON.stringify({
+ message,
+ sessionId: sessionId || this.generateSessionId(),
+ model: 'claude-3-opus', // 或其他模型
+ }),
+ });
+
+ return response.json();
+ }
+
+ /**
+ * 流式发送消息(SSE)
+ */
+ async *streamMessage(message: string, sessionId?: string) {
+ const response = await callMCPApi('/api/mcp/chat/stream', {
+ method: 'POST',
+ body: JSON.stringify({
+ message,
+ sessionId: sessionId || this.generateSessionId(),
+ stream: true,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error('Stream request failed');
+ }
+
+ const reader = response.body?.getReader();
+ const decoder = new TextDecoder();
+
+ if (!reader) {
+ throw new Error('No response body');
+ }
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const chunk = decoder.decode(value);
+ const lines = chunk.split('\n');
+
+ for (const line of lines) {
+ if (line.startsWith('data: ')) {
+ const data = line.slice(6);
+ if (data === '[DONE]') {
+ return;
+ }
+ try {
+ yield JSON.parse(data);
+ } catch (e) {
+ console.error('Failed to parse SSE data:', e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取可用的 MCP 工具列表
+ */
+ async getAvailableTools(): Promise {
+ const response = await callMCPApi('/api/mcp/tools');
+ return response.json();
+ }
+
+ /**
+ * 执行代码
+ */
+ async executeCode(code: string, language: string = 'python'): Promise {
+ const response = await callMCPApi('/api/mcp/execute', {
+ method: 'POST',
+ body: JSON.stringify({
+ code,
+ language,
+ }),
+ });
+
+ return response.json();
+ }
+
+ /**
+ * 生成代码
+ */
+ async generateCode(prompt: string, language: string = 'python'): Promise {
+ const response = await callMCPApi('/api/mcp/generate-code', {
+ method: 'POST',
+ body: JSON.stringify({
+ prompt,
+ language,
+ }),
+ });
+
+ return response.json();
+ }
+
+ /**
+ * 获取聊天历史
+ */
+ async getChatHistory(sessionId?: string): Promise {
+ const params = sessionId ? `?sessionId=${sessionId}` : '';
+ const response = await callMCPApi(`/api/mcp/history${params}`);
+ return response.json();
+ }
+
+ /**
+ * 生成会话 ID
+ */
+ private generateSessionId(): string {
+ return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ }
+}
+
+// 导出单例
+export const mcpService = new MCPService();
\ No newline at end of file
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/CheckEmailPage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/CheckEmailPage/index.tsx
new file mode 100644
index 00000000..ccd9d571
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/CheckEmailPage/index.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+
+const CheckEmailPage = () => {
+ return (
+
+ We sent a verification link to Martin@gmail.com
+ >
+ }
+ >
+ <>
+
+ Enter the code Manually
+
+
+
+ Back to login page
+
+
+ >
+
+ );
+};
+
+export default CheckEmailPage;
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/EnterCodePage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/EnterCodePage/index.tsx
new file mode 100644
index 00000000..490106cc
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/EnterCodePage/index.tsx
@@ -0,0 +1,76 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+import Field from "@/components/Field";
+
+const EnterCodePage = () => {
+ const [number1, setNumber1] = useState("");
+ const [number2, setNumber2] = useState("");
+ const [number3, setNumber3] = useState("");
+ const [number4, setNumber4] = useState("");
+
+ return (
+
+ We sent a verification link to Martin@gmail.com
+ >
+ }
+ >
+
+
+ setNumber1(e.target.value)}
+ required
+ />
+ setNumber2(e.target.value)}
+ required
+ />
+ setNumber3(e.target.value)}
+ required
+ />
+ setNumber4(e.target.value)}
+ required
+ />
+
+
+ Continue
+
+
+
+ Back to login page
+
+
+
+
+ );
+};
+
+export default EnterCodePage;
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/ForgotPasswordPage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/ForgotPasswordPage/index.tsx
new file mode 100644
index 00000000..7326e760
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/ForgotPasswordPage/index.tsx
@@ -0,0 +1,67 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+import Image from "@/components/Image";
+import Field from "@/components/Field";
+
+const ForgotPasswordPage = () => {
+ const [email, setEmail] = useState("");
+
+ return (
+ Lost Your Key? Reset Your Password and Regain Control!>
+ }
+ >
+
+
+
+ Continue with Google
+
+
+ Or
+
+
+ setEmail(e.target.value)}
+ required
+ />
+
+ Reset Password
+
+
+
+
+ Back to login page
+
+
+
+
+ );
+};
+
+export default ForgotPasswordPage;
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/ResetPasswordPage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/ResetPasswordPage/index.tsx
new file mode 100644
index 00000000..a161445d
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/ResetPasswordPage/index.tsx
@@ -0,0 +1,58 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+import Field from "@/components/Field";
+
+const ResetPasswordPage = () => {
+ const [newPassword, setNewPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState("");
+
+ return (
+ Lost Your Key? Reset Your Password and Regain Control!>
+ }
+ >
+
+
+ setNewPassword(e.target.value)}
+ required
+ />
+ setConfirmPassword(e.target.value)}
+ required
+ />
+
+ Reset Password
+
+
+
+
+ Forgotten Password?
+
+
+
+
+ );
+};
+
+export default ResetPasswordPage;
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/SignInPage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/SignInPage/index.tsx
new file mode 100644
index 00000000..d14ca7e3
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/SignInPage/index.tsx
@@ -0,0 +1,81 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+import Image from "@/components/Image";
+import Field from "@/components/Field";
+
+const SignInPage = () => {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+
+ return (
+
+ Don’t have an account?{" "}
+
+ Sign up
+ {" "}
+ here
+ >
+ }
+ >
+
+
+
+ Continue with Google
+
+
+ Or
+
+
+ setEmail(e.target.value)}
+ required
+ />
+ setPassword(e.target.value)}
+ required
+ />
+
+ Login
+
+
+
+
+ Forgotten Password?
+
+
+
+
+ );
+};
+
+export default SignInPage;
diff --git a/src/views/AgentChat/neuratalk/templates/Auth/SignUpPage/index.tsx b/src/views/AgentChat/neuratalk/templates/Auth/SignUpPage/index.tsx
new file mode 100644
index 00000000..1a7cf69f
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/Auth/SignUpPage/index.tsx
@@ -0,0 +1,88 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import LayoutLogin from "@/components/LayoutLogin";
+import Button from "@/components/Button";
+import Image from "@/components/Image";
+import Field from "@/components/Field";
+
+const SignUpPage = () => {
+ const [fullName, setFullName] = useState("");
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+
+ return (
+
+ Already have an account?{" "}
+
+ Sign in
+ {" "}
+ here
+ >
+ }
+ >
+
+
+
+ Continue with Google
+
+
+ Or
+
+
+ setFullName(e.target.value)}
+ required
+ />
+ setEmail(e.target.value)}
+ required
+ />
+ setPassword(e.target.value)}
+ required
+ />
+
+ Create account
+
+
+
+
+ Forgotten Password?
+
+
+
+
+ );
+};
+
+export default SignUpPage;
diff --git a/src/views/AgentChat/neuratalk/templates/DataAnalyticsPage/index.tsx b/src/views/AgentChat/neuratalk/templates/DataAnalyticsPage/index.tsx
new file mode 100644
index 00000000..319fa78e
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/DataAnalyticsPage/index.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import Layout from "@/components/Layout";
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import Chart from "@/components/Chart";
+import Button from "@/components/Button";
+
+const DataAnalyticsPage = () => {
+ return (
+
+
+
+ What’s the trend of Bitcoin between oct 16 and oct 22
+
+
+
+
+ Sure here is the chart of the bitcoin
+
+
+
+
+ Send to data team
+
+
+
+ You can change the date by choosing the filter and
+ see more charts.
+
+
+
+
+
+ );
+};
+
+export default DataAnalyticsPage;
diff --git a/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/content.tsx b/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/content.tsx
new file mode 100644
index 00000000..fa4efe38
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/content.tsx
@@ -0,0 +1,41 @@
+export const content = (
+ <>
+ non-disclosure agreement
+ Please read these instructions carefully.
+
+ This is a Figma template provided as a guide for the Assessment Task
+ documentation submission. This is an individual submission; each
+ group member must produce and submit their own version. Group
+ members can share co-produced assets from the project.
+
+
+ We suggest that groups work collaboratively on their Figma Group
+ Project Template, with each member working on their own individual
+ version using this template.
+
+
+ This template was created based on our Unit’s visual style. You are
+ expected to design your own layouts and visual style to suit your
+ proposal. Templates that were shared in class should also be
+ re-styled (where possible) to suit your overall design proposal and
+ style.
+
+
+ Use the A4 Frames as a scaling guide, and understand what font sizes
+ you should be working at.
+
+
+ Pro tip: When scaling down your wireframes, use the Scale tool (‘K’
+ shortcut) to reduce your grouped elements uniformly.
+
+
+ Alternatively, right click on a wireframe/element and Copy/Paste As{" "}
+ {">"} Copy as PNG – you can then paste and scale the image to your
+ liking.
+
+
+ Note: check and adjust font sizes and other properties when scaling
+ components in Figma.
+
+ >
+);
diff --git a/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/index.tsx b/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/index.tsx
new file mode 100644
index 00000000..9a626e45
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/DocumentGenerationPage/index.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useState } from "react";
+import Layout from "@/components/Layout";
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import Article from "@/components/Article";
+import EditorArticle from "@/components/EditorArticle";
+
+import { content } from "./content";
+
+const DocumentGenerationPage = () => {
+ const [isEditing, setIsEditing] = useState(false);
+
+ return (
+
+ {isEditing ? (
+ setIsEditing(false)}
+ />
+ ) : (
+
+
+ generate Document for “non-disclosure agreement”.
+
+
+
+
+ Here’s a simple example of HTML code for a
+ contact form:
+
+
setIsEditing(true)}
+ />
+
+ This code creates a simple, styled contact form
+ that includes fields for a name, email, and
+ message, along with a "Send Message"
+ button. You can further customize the form or
+ integrate it into your website as needed.
+
+
+
+
+ )}
+
+ );
+};
+
+export default DocumentGenerationPage;
diff --git a/src/views/AgentChat/neuratalk/templates/DocumentsPage/content.tsx b/src/views/AgentChat/neuratalk/templates/DocumentsPage/content.tsx
new file mode 100644
index 00000000..b5deb3fd
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/DocumentsPage/content.tsx
@@ -0,0 +1,105 @@
+export const content = [
+ {
+ id: 0,
+ title: "Previous 7 days",
+ counter: "03",
+ items: [
+ {
+ id: 0,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-1.jpg",
+ avatars: [
+ "/images/avatar-3.jpg",
+ "/images/avatar-4.jpg",
+ "/images/avatar-5.jpg",
+ ],
+ },
+ {
+ id: 1,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-2.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-4.jpg"],
+ },
+ {
+ id: 2,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-3.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-5.jpg"],
+ },
+ ],
+ },
+ {
+ id: 1,
+ title: "Previous 14 days",
+ counter: "06",
+ items: [
+ {
+ id: 0,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-1.jpg",
+ avatars: [
+ "/images/avatar-3.jpg",
+ "/images/avatar-4.jpg",
+ "/images/avatar-5.jpg",
+ ],
+ },
+ {
+ id: 1,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-2.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-4.jpg"],
+ },
+ {
+ id: 2,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-3.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-5.jpg"],
+ },
+ {
+ id: 3,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-1.jpg",
+ avatars: [
+ "/images/avatar-3.jpg",
+ "/images/avatar-4.jpg",
+ "/images/avatar-5.jpg",
+ ],
+ },
+ {
+ id: 4,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-2.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-4.jpg"],
+ },
+ {
+ id: 5,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-3.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-5.jpg"],
+ },
+ ],
+ },
+ {
+ id: 2,
+ title: "Previous 30 days",
+ counter: "02",
+ items: [
+ {
+ id: 0,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-1.jpg",
+ avatars: [
+ "/images/avatar-3.jpg",
+ "/images/avatar-4.jpg",
+ "/images/avatar-5.jpg",
+ ],
+ },
+ {
+ id: 1,
+ title: "2025 Product Rollout Plan",
+ image: "/images/document-pic-2.jpg",
+ avatars: ["/images/avatar-3.jpg", "/images/avatar-4.jpg"],
+ },
+ ],
+ },
+];
diff --git a/src/views/AgentChat/neuratalk/templates/DocumentsPage/index.tsx b/src/views/AgentChat/neuratalk/templates/DocumentsPage/index.tsx
new file mode 100644
index 00000000..f334616f
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/DocumentsPage/index.tsx
@@ -0,0 +1,85 @@
+"use client";
+
+import Layout from "@/components/Layout";
+import Chat from "@/components/Chat";
+import Image from "@/components/Image";
+import Icon from "@/components/Icon";
+
+import { content } from "./content";
+
+const DocumentsPage = () => {
+ return (
+
+
+ Documents
+
+ 20
+
+
+ }
+ >
+
+ {content.map((item) => (
+
+
+
+ {item.title}
+
+
+ {item.counter}
+
+
+
+ {item.items.map((item) => (
+
+
+
+
+
+
+
+ {item.title}
+
+
+ {item.avatars.map((avatar) => (
+
+ ))}
+
+
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+};
+
+export default DocumentsPage;
diff --git a/src/views/AgentChat/neuratalk/templates/GenerateCodePage/index.tsx b/src/views/AgentChat/neuratalk/templates/GenerateCodePage/index.tsx
new file mode 100644
index 00000000..0d8423af
--- /dev/null
+++ b/src/views/AgentChat/neuratalk/templates/GenerateCodePage/index.tsx
@@ -0,0 +1,94 @@
+"use client";
+
+import { useState } from "react";
+import Layout from "@/components/Layout";
+import Chat from "@/components/Chat";
+import Question from "@/components/Question";
+import Answer from "@/components/Answer";
+import CodeEditor from "@/components/CodeEditor";
+
+const GenerateCodePage = () => {
+ const [isGenerating, setIsGenerating] = useState(false);
+ const [code, setCode] = useState(`
+
+
+
+
+ Contact Form
+