Align Sidebar & BottomNav menus, remove "Search", add user profile mock data, implement /api/users, add FilterDrawer, complete Section, ProfileHeader, MetricsRFM components Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { NextResponse } from "next/server"
|
||
import { analyzeUser, type AnalyzeInput } from "@/services/rfm-engine"
|
||
import { generateText } from "ai"
|
||
import { openai } from "@ai-sdk/openai"
|
||
|
||
/**
|
||
* 可选 AI 标签增强:
|
||
* - 使用 AI SDK (generateText + openai("gpt-4o")),符合统一标准 [^1]
|
||
* - 无 OPENAI_API_KEY 时自动跳过,保持稳定
|
||
*/
|
||
async function aiTagging(chat_logs?: string[]) {
|
||
const text = (chat_logs ?? []).slice(0, 8).join("。")
|
||
if (!text) return null
|
||
if (!process.env.OPENAI_API_KEY) return null
|
||
try {
|
||
const { text: out } = await generateText({
|
||
model: openai("gpt-4o"),
|
||
system:
|
||
"请根据用户聊天片段输出JSON,字段:emotion(积极|中性|消极), intent(弱意图|中等意图|强意图), behavior(数组,中文标签最多3个)。只输出JSON。",
|
||
prompt: `聊天片段:${text}`,
|
||
// @ts-expect-error ai sdk typings are flexible in Next.js
|
||
maxTokens: 200,
|
||
})
|
||
const json = JSON.parse(out.trim())
|
||
return json
|
||
} catch {
|
||
return null
|
||
}
|
||
}
|
||
|
||
export async function POST(req: Request) {
|
||
try {
|
||
const body = await req.json()
|
||
const inputs: AnalyzeInput[] = Array.isArray(body) ? body : [body]
|
||
const useAI = (Array.isArray(body) ? (body as any).useAI : (body as any)?.useAI) ?? false
|
||
|
||
const results = []
|
||
for (const input of inputs) {
|
||
const base = analyzeUser(input)
|
||
if (useAI) {
|
||
const ai = await aiTagging(input.chat_logs)
|
||
if (ai) {
|
||
base.tags.emotion = ai.emotion ?? base.tags.emotion
|
||
base.tags.intent = ai.intent ?? base.tags.intent
|
||
if (Array.isArray(ai.behavior)) {
|
||
base.tags.behavior = Array.from(new Set([...(base.tags.behavior ?? []), ...ai.behavior]))
|
||
}
|
||
}
|
||
}
|
||
results.push(base)
|
||
}
|
||
return NextResponse.json({ success: true, data: results })
|
||
} catch (e: any) {
|
||
return NextResponse.json({ success: false, error: e?.message || "Invalid input" }, { status: 400 })
|
||
}
|
||
}
|