0.0.0.5
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
import type { FamilyMember } from "@/types/family"
|
||||
|
||||
/**
|
||||
* AI 辅助功能配置
|
||||
*/
|
||||
export interface AIConfig {
|
||||
provider: "openai" | "custom" | "browser"
|
||||
apiKey?: string
|
||||
apiEndpoint?: string
|
||||
model?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 AI 配置
|
||||
*/
|
||||
export function getAIConfig(): AIConfig | null {
|
||||
if (typeof window === "undefined") return null
|
||||
|
||||
const config = localStorage.getItem("ai-config")
|
||||
return config ? JSON.parse(config) : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存 AI 配置
|
||||
*/
|
||||
export function saveAIConfig(config: AIConfig): void {
|
||||
if (typeof window === "undefined") return
|
||||
|
||||
localStorage.setItem("ai-config", JSON.stringify(config))
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成成员简介
|
||||
*/
|
||||
export async function generateBio(member: Partial<FamilyMember>): Promise<string> {
|
||||
const config = getAIConfig()
|
||||
|
||||
if (!config) {
|
||||
throw new Error("请先配置 AI 服务")
|
||||
}
|
||||
|
||||
const prompt = `请根据以下信息生成一段简洁的人物简介(100字以内):
|
||||
|
||||
姓名:${member.fullName || "未知"}
|
||||
性别:${member.gender === "male" ? "男" : member.gender === "female" ? "女" : "未知"}
|
||||
出生日期:${member.birthDate || "未知"}
|
||||
${member.deathDate ? `逝世日期:${member.deathDate}` : ""}
|
||||
籍贯:${member.ancestralHome || "未知"}
|
||||
${member.courtesyName ? `字:${member.courtesyName}` : ""}
|
||||
${member.artName ? `号:${member.artName}` : ""}
|
||||
|
||||
请用第三人称,简洁专业的语言描述。`
|
||||
|
||||
return await callAI(prompt, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析家族关系
|
||||
*/
|
||||
export async function analyzeRelationship(
|
||||
member1: FamilyMember,
|
||||
member2: FamilyMember,
|
||||
allMembers: FamilyMember[]
|
||||
): Promise<string> {
|
||||
const config = getAIConfig()
|
||||
|
||||
if (!config) {
|
||||
throw new Error("请先配置 AI 服务")
|
||||
}
|
||||
|
||||
const prompt = `请分析以下两位家族成员的关系:
|
||||
|
||||
成员A:${member1.fullName},第${member1.generation}世
|
||||
成员B:${member2.fullName},第${member2.generation}世
|
||||
|
||||
家族成员总数:${allMembers.length}人
|
||||
|
||||
请分析他们可能的关系(如:兄弟、堂兄弟、叔侄等),并给出理由。`
|
||||
|
||||
return await callAI(prompt, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能推荐字辈
|
||||
*/
|
||||
export async function suggestGenerationName(
|
||||
generation: number,
|
||||
existingNames: string[]
|
||||
): Promise<string[]> {
|
||||
const config = getAIConfig()
|
||||
|
||||
if (!config) {
|
||||
throw new Error("请先配置 AI 服务")
|
||||
}
|
||||
|
||||
const prompt = `请为家族第${generation}世推荐5个合适的字辈用字。
|
||||
|
||||
已使用的字辈:${existingNames.join("、")}
|
||||
|
||||
要求:
|
||||
1. 符合中国传统字辈命名习惯
|
||||
2. 寓意吉祥、积极向上
|
||||
3. 避免与已有字辈重复
|
||||
4. 只返回5个汉字,用逗号分隔`
|
||||
|
||||
const response = await callAI(prompt, config)
|
||||
return response.split(/[,,、]/).map(s => s.trim()).filter(Boolean).slice(0, 5)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成家族故事标题
|
||||
*/
|
||||
export async function generateStoryTitle(content: string): Promise<string> {
|
||||
const config = getAIConfig()
|
||||
|
||||
if (!config) {
|
||||
throw new Error("请先配置 AI 服务")
|
||||
}
|
||||
|
||||
const prompt = `请为以下家族故事生成一个简洁有吸引力的标题(10字以内):
|
||||
|
||||
${content.substring(0, 200)}...
|
||||
|
||||
只返回标题,不要其他内容。`
|
||||
|
||||
return await callAI(prompt, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能数据校验
|
||||
*/
|
||||
export async function validateMemberData(member: Partial<FamilyMember>): Promise<{
|
||||
valid: boolean
|
||||
issues: string[]
|
||||
suggestions: string[]
|
||||
}> {
|
||||
const config = getAIConfig()
|
||||
|
||||
if (!config) {
|
||||
return {
|
||||
valid: true,
|
||||
issues: [],
|
||||
suggestions: []
|
||||
}
|
||||
}
|
||||
|
||||
const prompt = `请检查以下家族成员信息是否合理:
|
||||
|
||||
姓名:${member.fullName || "未填写"}
|
||||
性别:${member.gender || "未填写"}
|
||||
出生日期:${member.birthDate || "未填写"}
|
||||
逝世日期:${member.deathDate || "未填写"}
|
||||
世代:${member.generation || "未填写"}
|
||||
|
||||
请指出可能存在的问题和改进建议。以JSON格式返回:
|
||||
{
|
||||
"valid": true/false,
|
||||
"issues": ["问题1", "问题2"],
|
||||
"suggestions": ["建议1", "建议2"]
|
||||
}`
|
||||
|
||||
try {
|
||||
const response = await callAI(prompt, config)
|
||||
return JSON.parse(response)
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: true,
|
||||
issues: [],
|
||||
suggestions: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 AI API
|
||||
*/
|
||||
async function callAI(prompt: string, config: AIConfig): Promise<string> {
|
||||
if (config.provider === "browser") {
|
||||
// 使用浏览器内置 AI(如果支持)
|
||||
if ("ai" in window && "languageModel" in (window as any).ai) {
|
||||
try {
|
||||
const session = await (window as any).ai.languageModel.create()
|
||||
const result = await session.prompt(prompt)
|
||||
return result
|
||||
} catch (error) {
|
||||
throw new Error("浏览器 AI 不可用")
|
||||
}
|
||||
} else {
|
||||
throw new Error("浏览器不支持内置 AI")
|
||||
}
|
||||
}
|
||||
|
||||
if (config.provider === "openai") {
|
||||
// 调用 OpenAI API
|
||||
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${config.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: config.model || "gpt-3.5-turbo",
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: "你是一个专业的家谱管理助手,帮助用户整理和分析家族信息。"
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: prompt
|
||||
}
|
||||
],
|
||||
temperature: 0.7,
|
||||
max_tokens: 500,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API 调用失败: ${response.statusText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data.choices[0].message.content.trim()
|
||||
}
|
||||
|
||||
if (config.provider === "custom") {
|
||||
// 调用自定义 API
|
||||
const response = await fetch(config.apiEndpoint!, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(config.apiKey ? { "Authorization": `Bearer ${config.apiKey}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({ prompt }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API 调用失败: ${response.statusText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return data.response || data.result || data.text || ""
|
||||
}
|
||||
|
||||
throw new Error("不支持的 AI 提供商")
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 AI 是否可用
|
||||
*/
|
||||
export function isAIAvailable(): boolean {
|
||||
const config = getAIConfig()
|
||||
if (!config) return false
|
||||
|
||||
if (config.provider === "browser") {
|
||||
return typeof window !== "undefined" && "ai" in window
|
||||
}
|
||||
|
||||
if (config.provider === "openai") {
|
||||
return !!config.apiKey
|
||||
}
|
||||
|
||||
if (config.provider === "custom") {
|
||||
return !!config.apiEndpoint
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user