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 ? ( - - ) : ( - - ); - })} - - - - ); -}); - -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减去导航栏高度,避免内容被遮挡 */} - - - - - {/* 左侧会话列表 */} - - - {/* 侧边栏头部 */} - - - - - - - - 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(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" }} - /> - - - - - - {/* 右侧配置面板 */} - - - - {/* 模型选择 */} - - - - - 选择模型 - - - - {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} - - - - - - - {/* 全选按钮 */} - - - {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 ( - - {/* 左侧会话列表 */} - - - {/* 侧边栏头部 */} - - - - {/* 搜索框 */} - - - - - 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(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 ( - - {/* 左侧会话列表 */} - - - {/* 侧边栏头部 */} - - - - {/* 搜索框 */} - - - - - 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(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 ( - - {/* 背景装饰 - 黄金光晕效果 */} - - - - {/* 左侧会话列表 */} - - - {/* 侧边栏头部 */} - - - - - - - - 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(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" - /> - - - - - - {/* 右侧配置面板 */} - - - - {/* 模型选择 */} - - - - - 选择模型 - - - - {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} - - - - - - - {/* 全选按钮 */} - - - {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) => ( +
+
+ Avatar +
+
+
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 +
+ + +
+
+ {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} + +
+ {item.title} +
+ + +
+
+
+ ))} +
+
+
+ ); +}; + +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:

+
    +
  1. + Derivative of x³ is:
    +     → 3x² +
  2. +
  3. + Derivative of 2x² is:
    +     → 2 × 2x = 4x +
  4. +
  5. + Derivative of constant -7 is:
    +     → 0 +
  6. +
+
+

🎯 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
+
+ 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" + /> + +
+ + {/* 快捷操作 */} +
+ + + +
+
+
+
+ ); +} + +// 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} + +
+
+ +
+ {onGenerate && ( +
+ +
+ )} +
+ ); +}; + +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 ( +
+
+ + +
+
+ {content} + {isTextSelected && ( +
+ + + + +
+ )} +
+
+ ); +}; + +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" && ( + + )} +
+
+ ); +}; + +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 ..... +
+
+
+
+
+ File +
+
Docment res.XLS
+
+
+
+
+
+
80%
+
+
+
+ ); +}; + +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) => ( +
+
+ File +
+
{name}
+
+
PDF
+
+
{size}
+
+
+); + +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 && ( +
+
+ +
+ Generating... +
+
+
+ )} +
+ 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 ( + <> + + + 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(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. +
+ +
+
+ ); +}; + +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)} + /> + +
+ ); +}; + +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} +
+
+
+ {item.author} +
+ {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 +
+
+ +
+
+
+ + + +
+ {title} +
+
+ {description} +
+
+ {children} +
+
+
+ ©LoopiBot.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.features.map((feature, index) => ( +
+ + + + {feature} +
+ ))} +
+
+
+ ))} +
+
+ + +
+
+); + +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.{" "} + +
+
+ +
+
+
Export Data
+ +
+
+
Shared Links
+ +
+
+
Archive all chats
+ +
+
+
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 ? ( + avatar + ) : ( + + )} +
+
+ + +
+ +
+
+ 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 + /> + +
+
+
+
Phone number
+
Update your phone number
+
+ setPhoneNumber(e.target.value)} + required + isSmall + /> +
+
+ + +
+
+ ); +}; + +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
+
+ +
+
+
+
Push
+
+ +
+
+
+
Email
+
+ +
+
+ ); +}; + +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. +
+
+ +
+
+ ); +}; + +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.
+
+
+ + +
+
+ ); +}; + +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)} + > +
+
+ +
+
+
+
+ + + +
+
{button.name}
+
+
+ ))} +
+
+ ); +}; + +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) => ( + + ))} +
+
+ {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) => ( +
+ Image +
+ ))} +
+
+
+ {tabs.map((tab) => ( + + ))} +
+
+ + ); +}; + +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. +
+
+
{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 ! +
+
+ +
+
+ + +
+
+); + +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 +
+
+
+ +
+ To Select +
+
+
+ +
+ To Close +
+
+); + +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 ( +
+ + {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 +
+ +
+ ) : 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 ( +
+ + {visible && ( + +
+
+
+ +
+ Results +
+ +
+
+ {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 + + 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) => ( +
+
+ Avatar +
+
+
+
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 ( + + ); +}; + +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 + /> + + + ); +}; + +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 ( + <> +
+
+ Upgrade + Upgrade +
+
+
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 = ({}) => ( + +
+ 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 +
+ + + +
+ +
+
+
+ +
+ 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) => ( + + ))} +
+
+ ); +}; + +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 ( +
+
+ +
Tools
+ +
+ +
+ {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)." + +
+
+
+ AI Voice +
+ + ) : ( + <> +
+
+ AI Voice +
+
+ 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 && ( + + )} +
+
+
+
+
+ + +
+ + ); +}; + +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 + +
+
+
+ Avatar +
+
+
+ {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 + + } + > + <> + +
+ + 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 + /> +
+ +
+ + 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! + } + > +
+ +
+ Or +
+
+ setEmail(e.target.value)} + required + /> + +
+
+ + 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 + /> + +
+
+ + 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 + + } + > +
+ +
+ Or +
+
+ setEmail(e.target.value)} + required + /> + setPassword(e.target.value)} + required + /> + +
+
+ + 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 + + } + > +
+ +
+ Or +
+
+ setFullName(e.target.value)} + required + /> + setEmail(e.target.value)} + required + /> + setPassword(e.target.value)} + required + /> + +
+
+ + 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 +
+ +
+ +
+
+ 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) => ( + 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 +