Files
users/app/api/ai-chat/route.ts

316 lines
10 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* AI 智能助手 API
* 支持自然语言查询用户数据
*/
import { NextRequest, NextResponse } from "next/server"
import { getMongoClient, intelligentSearch, queryFullProfile, getDatabaseStats } from "@/lib/mongodb"
// 消息类型
interface ChatMessage {
role: "user" | "assistant" | "system"
content: string
timestamp?: string
data?: any
}
// 解析用户意图
function parseIntent(message: string): { type: string; query?: string; params?: any } {
const msg = message.trim().toLowerCase()
// 查询手机号
const phoneMatch = message.match(/(?:查|查询|搜索|找)?[:\s]*(\+?86)?1[3-9]\d{9}/g)
if (phoneMatch) {
const phone = phoneMatch[0].replace(/[查询搜索找::\s]/g, '').replace(/^\+?86/, '')
return { type: "query_phone", query: phone }
}
// 查询 QQ
const qqMatch = message.match(/(?:qq|QQ)[:\s]*(\d{5,11})|(\d{5,11})\s*(?:qq|QQ)/i)
if (qqMatch) {
return { type: "query_qq", query: qqMatch[1] || qqMatch[2] }
}
// 系统状态
if (msg.includes("状态") || msg.includes("统计") || msg.includes("总量")) {
return { type: "system_status" }
}
// RFM 分析
if (msg.includes("rfm") || msg.includes("估值") || msg.includes("价值")) {
return { type: "rfm_analysis" }
}
// 高价值用户
if (msg.includes("高价值") || msg.includes("top") || msg.includes("排行")) {
const limitMatch = msg.match(/(\d+)/)
return { type: "high_value_users", params: { limit: limitMatch ? parseInt(limitMatch[1]) : 10 } }
}
// 帮助
if (msg.includes("帮助") || msg.includes("help") || msg === "?") {
return { type: "help" }
}
// 通用搜索
return { type: "search", query: message }
}
// 格式化用户数据
function formatUserData(user: any): string {
if (!user) return "未找到用户信息"
const lines: string[] = []
if (user.name) lines.push(`👤 姓名: ${user.name}`)
if (user.phone_masked) lines.push(`📱 手机: ${user.phone_masked}`)
if (user.qq) lines.push(`💬 QQ: ${user.qq}`)
if (user.gender) lines.push(`⚧ 性别: ${user.gender}`)
if (user.age_range) lines.push(`📅 年龄段: ${user.age_range}`)
if (user.province || user.city) lines.push(`📍 地区: ${user.province || ''}${user.city || ''}`)
if (user.evaluation_score || user.user_evaluation_score) {
lines.push(`⭐ 估值分: ${user.evaluation_score || user.user_evaluation_score}`)
}
if (user.user_level) lines.push(`🏆 等级: ${user.user_level}`)
if (user.carrier) lines.push(`📶 运营商: ${user.carrier}`)
if (user.tags && user.tags.length > 0) lines.push(`🏷️ 标签: ${user.tags.join(', ')}`)
return lines.join('\n')
}
// 处理 AI 聊天
async function processChat(message: string): Promise<ChatMessage> {
const startTime = Date.now()
const intent = parseIntent(message)
try {
switch (intent.type) {
case "query_phone": {
const result = await queryFullProfile(intent.query!)
if (result.valuation || result.qqPhone) {
const user = {
...result.valuation,
qq: result.qqPhone?.qq,
carrier: result.qqPhone?.运营商
}
return {
role: "assistant",
content: `🎯 手机号 ${intent.query} 查询结果:\n\n${formatUserData(user)}\n\n⏱ 查询耗时: ${Date.now() - startTime}ms`,
data: result
}
} else {
return {
role: "assistant",
content: `❌ 未找到手机号 ${intent.query} 的相关信息\n\n💡 提示: 请检查手机号是否正确11位数字`
}
}
}
case "query_qq": {
const client = await getMongoClient()
const qqDb = client.db("KR_腾讯")
let qqDoc = await qqDb.collection("QQ+手机").findOne({ qq: intent.query })
if (!qqDoc) {
qqDoc = await qqDb.collection("QQ+手机").findOne({ qq: parseInt(intent.query!) })
}
if (qqDoc) {
const phone = qqDoc.phone || qqDoc.
let userInfo = `🎯 QQ ${intent.query} 查询结果:\n\n`
userInfo += `💬 QQ: ${qqDoc.qq}\n`
userInfo += `📱 手机: ${phone ? phone.toString().replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '未知'}\n`
userInfo += `📊 QQ评分: ${qqDoc.QQ号评分 || 'N/A'}\n`
userInfo += `📊 手机评分: ${qqDoc. || 'N/A'}\n`
userInfo += `📍 地区: ${qqDoc. || ''}${qqDoc. || ''}\n`
userInfo += `📶 运营商: ${qqDoc. || 'N/A'}\n`
userInfo += `\n⏱ 查询耗时: ${Date.now() - startTime}ms`
return {
role: "assistant",
content: userInfo,
data: qqDoc
}
} else {
return {
role: "assistant",
content: `❌ 未找到 QQ ${intent.query} 的相关信息`
}
}
}
case "system_status": {
const stats = await getDatabaseStats()
return {
role: "assistant",
content: `📊 神射手系统状态\n\n` +
`🟢 连接状态: ${stats.connected ? '正常' : '异常'}\n` +
`📁 数据库数: ${stats.databases?.length || 0}\n` +
`📄 总记录数: ${(stats.totalDocuments / 1e8).toFixed(2)} 亿条\n` +
`💾 总数据量: ${(stats.totalSize / 1e9).toFixed(2)} GB\n` +
`⏱️ 响应延迟: ${stats.latency}ms`,
data: stats
}
}
case "rfm_analysis": {
const client = await getMongoClient()
const db = client.db("KR")
const pipeline = [
{ $group: { _id: "$user_level", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]
const results = await db.collection("用户估值").aggregate(pipeline).toArray()
let content = `📈 RFM 用户分布统计\n\n`
let total = 0
results.forEach(r => {
const level = r._id || '未分级'
content += `${level}: ${(r.count / 10000).toFixed(1)}\n`
total += r.count
})
content += `\n📊 总用户数: ${(total / 10000).toFixed(1)}`
content += `\n⏱ 统计耗时: ${Date.now() - startTime}ms`
return {
role: "assistant",
content,
data: results
}
}
case "high_value_users": {
const limit = intent.params?.limit || 10
const client = await getMongoClient()
const db = client.db("KR")
const users = await db.collection("用户估值")
.find({ user_evaluation_score: { $exists: true } })
.sort({ user_evaluation_score: -1 })
.limit(limit)
.toArray()
let content = `🏆 高价值用户 TOP${limit}\n\n`
users.forEach((u, i) => {
const phone = u.phone?.replace(/(\+?86)?(\d{3})\d{4}(\d{4})/, '$2****$3') || '***'
content += `${i + 1}. ${u.name || '未知'} (${phone}) - 估值: ${u.user_evaluation_score}\n`
})
content += `\n⏱ 查询耗时: ${Date.now() - startTime}ms`
return {
role: "assistant",
content,
data: users
}
}
case "help": {
return {
role: "assistant",
content: `🎯 神射手 AI 助手使用指南\n\n` +
`📱 查询手机号:\n "查 13800138000" 或 "13800138000"\n\n` +
`💬 查询 QQ:\n "28533368 qq" 或 "qq 28533368"\n\n` +
`📊 系统状态:\n "系统状态" 或 "统计"\n\n` +
`📈 RFM 分析:\n "RFM分析" 或 "用户估值"\n\n` +
`🏆 高价值用户:\n "高价值用户 TOP10"\n\n` +
`💡 数据覆盖: 20亿+用户207GB数据`
}
}
case "search":
default: {
// 尝试智能搜索
const result = await intelligentSearch(intent.query || message, { limit: 5 })
if (result.total > 0) {
let content = `🔍 搜索结果 (共${result.total}条)\n\n`
result.users.slice(0, 5).forEach((u, i) => {
content += `${i + 1}. ${u.name || '未知'} - ${u.city || ''} - 估值: ${u.user_evaluation_score || 'N/A'}\n`
})
content += `\n⏱ 查询耗时: ${Date.now() - startTime}ms`
return {
role: "assistant",
content,
data: result
}
} else {
return {
role: "assistant",
content: `🤔 我不太理解 "${message}"\n\n` +
`💡 你可以尝试:\n` +
`- 查询手机号: "查 13800138000"\n` +
`- 查询QQ: "28533368 qq"\n` +
`- 输入 "帮助" 查看更多功能`
}
}
}
}
} catch (error: any) {
console.error("AI Chat 错误:", error)
return {
role: "assistant",
content: `⚠️ 查询出错: ${error.message}\n\n请稍后重试或检查数据库连接`
}
}
}
/**
* POST /api/ai-chat
* AI 对话接口
*/
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { message, history = [] } = body
if (!message || !message.trim()) {
return NextResponse.json({
success: false,
error: "消息不能为空"
}, { status: 400 })
}
const response = await processChat(message)
response.timestamp = new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" })
return NextResponse.json({
success: true,
response
})
} catch (error: any) {
console.error("AI Chat API 错误:", error)
return NextResponse.json({
success: false,
error: error.message,
response: {
role: "assistant",
content: `⚠️ 服务暂时不可用: ${error.message}`,
timestamp: new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" })
}
}, { status: 500 })
}
}
/**
* GET /api/ai-chat
* 获取 AI 助手状态
*/
export async function GET() {
try {
const stats = await getDatabaseStats()
return NextResponse.json({
status: "online",
model: "神射手 AI v1.0",
capabilities: ["用户查询", "QQ查询", "RFM分析", "智能搜索"],
database: {
connected: stats.connected,
totalUsers: stats.totalDocuments,
latency: stats.latency
}
})
} catch (error: any) {
return NextResponse.json({
status: "degraded",
error: error.message
})
}
}