update pay ui

This commit is contained in:
2025-12-11 14:48:00 +08:00
parent d6e567ba8a
commit 736886fd40
5 changed files with 165 additions and 12 deletions

4
app.py
View File

@@ -13448,8 +13448,8 @@ def get_concept_stocks(concept_id):
if stock_codes:
try:
ch_client = Client(
host='127.0.0.1',
port=9000,
host='222.128.1.157',
port=18000,
user='default',
password='Zzl33818!',
database='stock'

View File

@@ -61,6 +61,11 @@ HTTP_CLIENT = httpx.AsyncClient(timeout=60.0)
# 模型配置字典(支持动态切换)
MODEL_CONFIGS = {
"deepseek": {
"api_key": "sk-7363bdb28d7d4bf0aa68eb9449f8f063",
"base_url": "https://api.deepseek.com",
"model": "deepseek-chat", # 默认模型
},
"kimi-k2": {
"api_key": "sk-TzB4VYJfCoXGcGrGMiewukVRzjuDsbVCkaZXi2LvkS8s60E5",
"base_url": "https://api.moonshot.cn/v1",
@@ -88,8 +93,8 @@ MODEL_CONFIGS = {
},
}
# 保持向后兼容的配置(默认使用 kimi-k2-thinking
KIMI_CONFIG = MODEL_CONFIGS["kimi-k2-thinking"]
# 保持向后兼容的配置(默认使用 deepseek
KIMI_CONFIG = MODEL_CONFIGS["deepseek"]
DEEPMONEY_CONFIG = MODEL_CONFIGS["deepmoney"]
# ==================== MCP协议数据模型 ====================
@@ -166,7 +171,7 @@ class AgentChatRequest(BaseModel):
user_avatar: Optional[str] = None # 用户头像URL
subscription_type: Optional[str] = None # 用户订阅类型free/pro/max
session_id: Optional[str] = None # 会话ID如果为空则创建新会话
model: Optional[str] = "kimi-k2-thinking" # 选择的模型kimi-k2, kimi-k2-thinking, glm-4.6, deepmoney, gemini-3
model: Optional[str] = "deepseek" # 选择的模型(deepseek, kimi-k2, kimi-k2-thinking, glm-4.6, deepmoney, gemini-3
tools: Optional[List[str]] = None # 选择的工具列表工具名称数组如果为None则使用全部工具
# ==================== MCP工具定义 ====================
@@ -3100,8 +3105,8 @@ async def agent_chat_stream(chat_request: AgentChatRequest, request: Request):
logger.info(f"[工具过滤] 使用全部 {len(tools)} 个工具")
# ==================== 动态模型选择 ====================
selected_model = chat_request.model or "kimi-k2-thinking"
model_config = MODEL_CONFIGS.get(selected_model, MODEL_CONFIGS["kimi-k2-thinking"])
selected_model = chat_request.model or "deepseek"
model_config = MODEL_CONFIGS.get(selected_model, MODEL_CONFIGS["deepseek"])
logger.info(f"[模型选择] 使用模型: {selected_model} ({model_config['model']})")
# 返回流式响应

View File

@@ -25,6 +25,13 @@ export interface ModelConfig {
* 包含所有可供用户选择的 AI 模型
*/
export const AVAILABLE_MODELS: ModelConfig[] = [
{
id: 'deepseek',
name: 'DeepSeek',
description: '高性能对话模型,响应迅速',
icon: React.createElement(Zap, { className: 'w-5 h-5' }),
color: 'blue',
},
{
id: 'kimi-k2-thinking',
name: 'Kimi K2 Thinking',
@@ -37,7 +44,7 @@ export const AVAILABLE_MODELS: ModelConfig[] = [
name: 'Kimi K2',
description: '快速响应模型,适合简单查询',
icon: React.createElement(Zap, { className: 'w-5 h-5' }),
color: 'blue',
color: 'cyan',
},
{
id: 'deepmoney',
@@ -51,7 +58,7 @@ export const AVAILABLE_MODELS: ModelConfig[] = [
/**
* 默认选中的模型 ID
*/
export const DEFAULT_MODEL_ID = 'kimi-k2-thinking';
export const DEFAULT_MODEL_ID = 'deepseek';
/**
* 根据 ID 查找模型配置

View File

@@ -4,10 +4,11 @@
// 支持两种模式:单一聊天模式 & 投研会议室模式
import React, { useState } from 'react';
import { Box, Flex, useToast, HStack, Button, Tooltip } from '@chakra-ui/react';
import { Box, Flex, useToast, HStack, Button, Tooltip, VStack, Text, Icon } from '@chakra-ui/react';
import { motion, AnimatePresence } from 'framer-motion';
import { MessageSquare, Users } from 'lucide-react';
import { MessageSquare, Users, Crown, Lock } from 'lucide-react';
import { useAuth } from '@contexts/AuthContext';
import { useSubscription } from '@hooks/useSubscription';
// 常量配置 - 从 TypeScript 模块导入
import { DEFAULT_MODEL_ID } from './constants/models';
@@ -47,8 +48,12 @@ const ChatMode = {
* - 投研会议室模式:多 AI 角色协作讨论投资议题
*/
const AgentChat = () => {
const { user } = useAuth();
const { user, isAuthenticated } = useAuth();
const toast = useToast();
const { hasSubscriptionLevel, openSubscriptionModal } = useSubscription();
// ==================== MAX 权限检查 ====================
const isMaxUser = user?.subscription_type === 'max' || hasSubscriptionLevel('max');
// ==================== 聊天模式状态 ====================
const [chatMode, setChatMode] = useState(ChatMode.SINGLE);
@@ -105,6 +110,142 @@ const AgentChat = () => {
const inputRef = React.useRef(null);
// ==================== 渲染组件 ====================
// 非 MAX 用户显示升级提示
if (!isMaxUser) {
return (
<Flex
h="100%"
bg="gray.900"
align="center"
justify="center"
direction="column"
position="relative"
overflow="hidden"
>
{/* 背景装饰 */}
<Box
position="absolute"
top="20%"
left="10%"
w="400px"
h="400px"
bg="purple.500"
filter="blur(150px)"
opacity="0.15"
borderRadius="full"
/>
<Box
position="absolute"
bottom="20%"
right="10%"
w="350px"
h="350px"
bg="pink.500"
filter="blur(150px)"
opacity="0.1"
borderRadius="full"
/>
{/* 升级提示卡片 */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<VStack
spacing={6}
p={10}
bg="rgba(17, 24, 39, 0.8)"
backdropFilter="blur(20px)"
borderRadius="2xl"
border="1px solid"
borderColor="rgba(255, 255, 255, 0.1)"
boxShadow="0 25px 50px -12px rgba(0, 0, 0, 0.5)"
maxW="500px"
textAlign="center"
>
{/* 图标 */}
<Box
p={4}
bg="linear-gradient(135deg, rgba(168, 85, 247, 0.2), rgba(236, 72, 153, 0.2))"
borderRadius="full"
border="1px solid"
borderColor="rgba(168, 85, 247, 0.3)"
>
<Icon as={Crown} boxSize={12} color="purple.400" />
</Box>
{/* 标题 */}
<VStack spacing={2}>
<Text
fontSize="2xl"
fontWeight="bold"
bgGradient="linear(to-r, purple.300, pink.300)"
bgClip="text"
>
价小前投研 AI
</Text>
<HStack spacing={2}>
<Icon as={Lock} boxSize={4} color="gray.400" />
<Text color="gray.400" fontSize="md">
Max 旗舰版专属功能
</Text>
</HStack>
</VStack>
{/* 描述 */}
<Text color="gray.300" fontSize="md" lineHeight="tall">
AI 投研助手是 Max 旗舰版用户的专属功能
提供智能股票分析投研会议室多模型对话等高级功能
升级到 Max 版即可解锁全部 AI 能力
</Text>
{/* 功能列表 */}
<VStack spacing={2} align="start" w="100%">
{[
'智能投研助手:一对一 AI 对话分析',
'投研会议室:多 AI 角色协作讨论',
'多模型选择DeepSeek、Kimi 等',
'专业工具:股票查询、新闻搜索、财务分析',
].map((feature, idx) => (
<HStack key={idx} spacing={3} color="gray.300">
<Box w={2} h={2} bg="purple.400" borderRadius="full" />
<Text fontSize="sm">{feature}</Text>
</HStack>
))}
</VStack>
{/* 升级按钮 */}
<motion.div whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} style={{ width: '100%' }}>
<Button
w="100%"
size="lg"
bgGradient="linear(to-r, purple.500, pink.500)"
color="white"
_hover={{
bgGradient: 'linear(to-r, purple.600, pink.600)',
boxShadow: '0 10px 40px rgba(168, 85, 247, 0.4)',
}}
leftIcon={<Crown className="w-5 h-5" />}
onClick={openSubscriptionModal}
>
升级到 Max 旗舰版
</Button>
</motion.div>
{/* 当前订阅状态 */}
{isAuthenticated && user && (
<Text color="gray.500" fontSize="sm">
当前订阅{user.subscription_type === 'pro' ? 'Pro 专业版' : '免费版'}
</Text>
)}
</VStack>
</motion.div>
</Flex>
);
}
return (
<Flex h="100%" position="relative" bg="gray.900" direction="column">
{/* 模式切换栏 */}