1356 lines
35 KiB
Markdown
1356 lines
35 KiB
Markdown
# 🌐 多语言AI驱动资讯系统设计方案
|
||
|
||
## 📋 项目概述
|
||
|
||
### 项目愿景
|
||
构建一个基于AI技术的多语言资讯系统,能够自动化处理内容采集、翻译、分类、推荐等核心功能,为全球用户提供个性化的多语言资讯服务。
|
||
|
||
### 核心特色
|
||
- **AI驱动**: 全流程AI自动化处理
|
||
- **多语言支持**: 基于现有i18n架构扩展
|
||
- **智能推荐**: 个性化内容推荐
|
||
- **实时处理**: 流式内容处理和翻译
|
||
- **跨平台**: uni-app-x统一开发
|
||
|
||
## 🏗️ 系统架构设计
|
||
|
||
### 1. 整体架构图
|
||
|
||
```mermaid
|
||
graph TB
|
||
A[用户客户端] --> B[API网关]
|
||
B --> C[认证服务]
|
||
B --> D[内容服务]
|
||
B --> E[AI处理服务]
|
||
B --> F[推荐服务]
|
||
|
||
D --> G[内容管理系统]
|
||
D --> H[多语言管理]
|
||
|
||
E --> I[OpenAI/Claude API]
|
||
E --> J[翻译服务]
|
||
E --> K[内容分析]
|
||
E --> L[图像识别]
|
||
|
||
F --> M[推荐算法]
|
||
F --> N[用户画像]
|
||
|
||
G --> O[PostgreSQL]
|
||
H --> O
|
||
N --> O
|
||
|
||
P[Redis缓存] --> B
|
||
Q[消息队列] --> E
|
||
```
|
||
|
||
### 2. 技术栈选择
|
||
|
||
**前端技术栈**
|
||
- uni-app-x (跨平台开发)
|
||
- Vue 3 + TypeScript
|
||
- 现有ak-i18n多语言框架
|
||
- Pinia状态管理
|
||
|
||
**后端技术栈**
|
||
- Supabase (PostgreSQL + 实时数据库)
|
||
- Node.js + Fastify
|
||
- Redis (缓存和会话)
|
||
- Kafka (消息队列)
|
||
|
||
**AI服务集成**
|
||
- OpenAI GPT-4/Claude (内容生成和分析)
|
||
- Google Translate API (机器翻译)
|
||
- 百度AI/腾讯AI (中文优化)
|
||
- Stability AI (图像生成)
|
||
|
||
## 🎯 核心功能模块
|
||
|
||
### 1. AI内容采集模块
|
||
|
||
**功能描述**
|
||
- 智能网络爬虫
|
||
- RSS源监控
|
||
- 社交媒体监听
|
||
- 官方API集成
|
||
|
||
**AI应用**
|
||
```typescript
|
||
// AI内容采集服务
|
||
export class AIContentCollectorService {
|
||
async collectNews(sources: NewsSource[]): Promise<RawContent[]> {
|
||
const contents = await this.crawlSources(sources)
|
||
|
||
// AI内容质量评估
|
||
const qualityScores = await this.aiQualityAssessment(contents)
|
||
|
||
// AI去重检测
|
||
const uniqueContents = await this.aiDeduplication(contents)
|
||
|
||
return uniqueContents.filter((_, index) => qualityScores[index] > 0.7)
|
||
}
|
||
|
||
private async aiQualityAssessment(contents: RawContent[]): Promise<number[]> {
|
||
const prompt = `
|
||
评估以下新闻内容的质量(0-1分),考虑:
|
||
1. 内容完整性
|
||
2. 信息准确性
|
||
3. 时效性
|
||
4. 可读性
|
||
|
||
内容: ${JSON.stringify(contents)}
|
||
`
|
||
|
||
const response = await this.openaiClient.chat.completions.create({
|
||
model: "gpt-4",
|
||
messages: [{ role: "user", content: prompt }]
|
||
})
|
||
|
||
return JSON.parse(response.choices[0].message.content)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. AI多语言翻译模块
|
||
|
||
**功能描述**
|
||
- 智能语言检测
|
||
- 上下文感知翻译
|
||
- 专业术语处理
|
||
- 翻译质量评估
|
||
|
||
**数据库设计**
|
||
```sql
|
||
-- 扩展现有语言表
|
||
ALTER TABLE public.ak_languages ADD COLUMN ai_translation_enabled BOOLEAN DEFAULT true;
|
||
ALTER TABLE public.ak_languages ADD COLUMN translation_quality_threshold FLOAT DEFAULT 0.8;
|
||
|
||
-- 内容翻译表
|
||
CREATE TABLE public.ak_content_translations (
|
||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
content_id uuid REFERENCES public.ak_contents(id) ON DELETE CASCADE,
|
||
language_id uuid REFERENCES public.ak_languages(id) ON DELETE CASCADE,
|
||
original_text TEXT NOT NULL,
|
||
translated_text TEXT NOT NULL,
|
||
translation_method VARCHAR(32) DEFAULT 'ai', -- 'ai', 'human', 'hybrid'
|
||
quality_score FLOAT,
|
||
ai_confidence FLOAT,
|
||
human_verified BOOLEAN DEFAULT false,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||
UNIQUE(content_id, language_id)
|
||
);
|
||
|
||
-- AI翻译日志表
|
||
CREATE TABLE public.ak_ai_translation_logs (
|
||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
content_id uuid REFERENCES public.ak_contents(id),
|
||
source_language VARCHAR(10),
|
||
target_language VARCHAR(10),
|
||
ai_provider VARCHAR(32), -- 'openai', 'google', 'baidu'
|
||
tokens_used INTEGER,
|
||
processing_time_ms INTEGER,
|
||
error_message TEXT,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||
);
|
||
```
|
||
|
||
**AI翻译服务**
|
||
```typescript
|
||
export class AITranslationService {
|
||
async translateContent(
|
||
content: Content,
|
||
targetLanguages: string[]
|
||
): Promise<Translation[]> {
|
||
const results: Translation[] = []
|
||
|
||
for (const lang of targetLanguages) {
|
||
try {
|
||
// 选择最佳翻译策略
|
||
const strategy = await this.selectTranslationStrategy(content, lang)
|
||
|
||
let translation: string
|
||
|
||
switch (strategy) {
|
||
case 'gpt4':
|
||
translation = await this.gpt4Translate(content, lang)
|
||
break
|
||
case 'google':
|
||
translation = await this.googleTranslate(content, lang)
|
||
break
|
||
case 'hybrid':
|
||
translation = await this.hybridTranslate(content, lang)
|
||
break
|
||
}
|
||
|
||
// AI质量评估
|
||
const qualityScore = await this.assessTranslationQuality(
|
||
content.text,
|
||
translation,
|
||
lang
|
||
)
|
||
|
||
results.push({
|
||
language: lang,
|
||
text: translation,
|
||
qualityScore,
|
||
strategy
|
||
})
|
||
|
||
} catch (error) {
|
||
console.error(`Translation failed for ${lang}:`, error)
|
||
}
|
||
}
|
||
|
||
return results
|
||
}
|
||
|
||
private async selectTranslationStrategy(
|
||
content: Content,
|
||
targetLang: string
|
||
): Promise<TranslationStrategy> {
|
||
// AI决策翻译策略
|
||
const prompt = `
|
||
选择最佳翻译策略:
|
||
内容类型: ${content.category}
|
||
文本长度: ${content.text.length}
|
||
目标语言: ${targetLang}
|
||
专业术语密度: ${await this.calculateTermDensity(content.text)}
|
||
|
||
策略选项: gpt4(高质量), google(速度快), hybrid(平衡)
|
||
返回最佳策略:
|
||
`
|
||
|
||
const response = await this.openaiClient.chat.completions.create({
|
||
model: "gpt-3.5-turbo",
|
||
messages: [{ role: "user", content: prompt }]
|
||
})
|
||
|
||
return response.choices[0].message.content as TranslationStrategy
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. AI内容分类与标签模块
|
||
|
||
**功能描述**
|
||
- 智能内容分类
|
||
- 自动标签生成
|
||
- 情感分析
|
||
- 关键词提取
|
||
|
||
**数据库设计**
|
||
```sql
|
||
-- 内容分类表
|
||
CREATE TABLE public.ak_content_categories (
|
||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
name_key VARCHAR(64) NOT NULL, -- i18n key
|
||
parent_id uuid REFERENCES public.ak_content_categories(id),
|
||
ai_keywords TEXT[], -- AI分类关键词
|
||
confidence_threshold FLOAT DEFAULT 0.8,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||
);
|
||
|
||
-- AI生成的标签表
|
||
CREATE TABLE public.ak_ai_tags (
|
||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
content_id uuid REFERENCES public.ak_contents(id) ON DELETE CASCADE,
|
||
tag_name VARCHAR(128) NOT NULL,
|
||
confidence_score FLOAT NOT NULL,
|
||
tag_type VARCHAR(32) DEFAULT 'topic', -- 'topic', 'entity', 'emotion', 'keyword'
|
||
ai_provider VARCHAR(32),
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||
);
|
||
|
||
-- 内容分析结果表
|
||
CREATE TABLE public.ak_content_analysis (
|
||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
content_id uuid REFERENCES public.ak_contents(id) ON DELETE CASCADE,
|
||
category_id uuid REFERENCES public.ak_content_categories(id),
|
||
sentiment_score FLOAT, -- -1 to 1
|
||
readability_score FLOAT, -- 0 to 1
|
||
credibility_score FLOAT, -- 0 to 1
|
||
keywords JSONB,
|
||
entities JSONB,
|
||
summary TEXT,
|
||
ai_processed_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||
);
|
||
```
|
||
|
||
### 4. AI个性化推荐模块
|
||
|
||
**功能描述**
|
||
- 用户行为分析
|
||
- 内容相似度计算
|
||
- 个性化推荐算法
|
||
- 实时推荐调整
|
||
|
||
**推荐算法实现**
|
||
```typescript
|
||
export class AIRecommendationService {
|
||
async generateRecommendations(
|
||
userId: string,
|
||
language: string,
|
||
limit: number = 20
|
||
): Promise<RecommendedContent[]> {
|
||
|
||
// 1. 获取用户画像
|
||
const userProfile = await this.getUserProfile(userId)
|
||
|
||
// 2. AI分析用户兴趣
|
||
const interests = await this.analyzeUserInterests(userProfile)
|
||
|
||
// 3. 内容匹配
|
||
const candidates = await this.getContentCandidates(language, interests)
|
||
|
||
// 4. AI排序
|
||
const rankedContents = await this.aiRankContents(candidates, userProfile)
|
||
|
||
return rankedContents.slice(0, limit)
|
||
}
|
||
|
||
private async aiRankContents(
|
||
contents: Content[],
|
||
userProfile: UserProfile
|
||
): Promise<RecommendedContent[]> {
|
||
const prompt = `
|
||
根据用户画像为内容排序:
|
||
|
||
用户画像:
|
||
- 兴趣领域: ${userProfile.interests.join(', ')}
|
||
- 阅读习惯: ${userProfile.readingHabits}
|
||
- 互动偏好: ${userProfile.interactionPreferences}
|
||
|
||
内容列表: ${JSON.stringify(contents.map(c => ({
|
||
id: c.id,
|
||
title: c.title,
|
||
category: c.category,
|
||
tags: c.tags,
|
||
publishedAt: c.publishedAt
|
||
})))}
|
||
|
||
请返回按推荐优先级排序的内容ID数组,并说明推荐理由。
|
||
`
|
||
|
||
const response = await this.openaiClient.chat.completions.create({
|
||
model: "gpt-4",
|
||
messages: [{ role: "user", content: prompt }],
|
||
response_format: { type: "json_object" }
|
||
})
|
||
|
||
const rankings = JSON.parse(response.choices[0].message.content)
|
||
|
||
return rankings.recommendations.map((rec: any) => ({
|
||
contentId: rec.contentId,
|
||
score: rec.score,
|
||
reason: rec.reason
|
||
}))
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. AI聊天助手模块
|
||
|
||
**功能描述**
|
||
- 多语言对话支持
|
||
- 内容问答
|
||
- 智能搜索助手
|
||
- 个性化建议
|
||
|
||
**实现代码**
|
||
```typescript
|
||
export class AIChatAssistantService {
|
||
async processUserMessage(
|
||
userId: string,
|
||
message: string,
|
||
language: string
|
||
): Promise<ChatResponse> {
|
||
|
||
// 1. 意图识别
|
||
const intent = await this.recognizeIntent(message, language)
|
||
|
||
// 2. 根据意图处理
|
||
switch (intent.type) {
|
||
case 'search':
|
||
return await this.handleSearchQuery(message, language)
|
||
case 'recommend':
|
||
return await this.handleRecommendation(userId, message, language)
|
||
case 'question':
|
||
return await this.handleQuestion(message, language)
|
||
default:
|
||
return await this.handleGeneralChat(message, language)
|
||
}
|
||
}
|
||
|
||
private async handleSearchQuery(
|
||
query: string,
|
||
language: string
|
||
): Promise<ChatResponse> {
|
||
// AI增强搜索
|
||
const enhancedQuery = await this.enhanceSearchQuery(query, language)
|
||
const results = await this.searchContent(enhancedQuery, language)
|
||
|
||
const response = await this.openaiClient.chat.completions.create({
|
||
model: "gpt-4",
|
||
messages: [
|
||
{
|
||
role: "system",
|
||
content: `你是一个资讯助手,用${language}回复用户。基于搜索结果提供有用的总结。`
|
||
},
|
||
{
|
||
role: "user",
|
||
content: `
|
||
用户搜索: ${query}
|
||
搜索结果: ${JSON.stringify(results)}
|
||
|
||
请提供有用的总结和推荐阅读。
|
||
`
|
||
}
|
||
]
|
||
})
|
||
|
||
return {
|
||
message: response.choices[0].message.content,
|
||
type: 'search_results',
|
||
data: results
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🔧 技术实现细节
|
||
|
||
### 1. AI服务集成配置
|
||
|
||
**环境变量配置**
|
||
```typescript
|
||
// config/ai-config.ts
|
||
export const aiConfig = {
|
||
openai: {
|
||
apiKey: process.env.OPENAI_API_KEY,
|
||
organization: process.env.OPENAI_ORG_ID,
|
||
defaultModel: 'gpt-4',
|
||
maxTokens: 4000
|
||
},
|
||
google: {
|
||
apiKey: process.env.GOOGLE_TRANSLATE_API_KEY,
|
||
projectId: process.env.GOOGLE_PROJECT_ID
|
||
},
|
||
baidu: {
|
||
appId: process.env.BAIDU_APP_ID,
|
||
apiKey: process.env.BAIDU_API_KEY,
|
||
secretKey: process.env.BAIDU_SECRET_KEY
|
||
}
|
||
}
|
||
```
|
||
|
||
**AI服务适配器**
|
||
```typescript
|
||
// services/ai-adapter.ts
|
||
export class AIServiceAdapter {
|
||
private openaiClient: OpenAI
|
||
private googleTranslate: any
|
||
private baiduClient: any
|
||
|
||
constructor() {
|
||
this.openaiClient = new OpenAI(aiConfig.openai)
|
||
this.googleTranslate = new GoogleTranslate(aiConfig.google)
|
||
this.baiduClient = new BaiduAI(aiConfig.baidu)
|
||
}
|
||
|
||
async generateContent(prompt: string, options?: AIOptions): Promise<string> {
|
||
try {
|
||
const response = await this.openaiClient.chat.completions.create({
|
||
model: options?.model || aiConfig.openai.defaultModel,
|
||
messages: [{ role: "user", content: prompt }],
|
||
max_tokens: options?.maxTokens || aiConfig.openai.maxTokens
|
||
})
|
||
|
||
return response.choices[0].message.content
|
||
} catch (error) {
|
||
console.error('AI content generation failed:', error)
|
||
throw new AIServiceError('Content generation failed', error)
|
||
}
|
||
}
|
||
|
||
async translateText(
|
||
text: string,
|
||
targetLang: string,
|
||
sourceLang?: string
|
||
): Promise<TranslationResult> {
|
||
// 智能选择翻译服务
|
||
const service = this.selectTranslationService(text, targetLang)
|
||
|
||
switch (service) {
|
||
case 'openai':
|
||
return await this.openaiTranslate(text, targetLang, sourceLang)
|
||
case 'google':
|
||
return await this.googleTranslateText(text, targetLang, sourceLang)
|
||
case 'baidu':
|
||
return await this.baiduTranslate(text, targetLang, sourceLang)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 数据流管道设计
|
||
|
||
**内容处理管道**
|
||
```typescript
|
||
// pipelines/content-pipeline.ts
|
||
export class ContentProcessingPipeline {
|
||
private steps: PipelineStep[] = [
|
||
new ContentValidationStep(),
|
||
new AIQualityAssessmentStep(),
|
||
new LanguageDetectionStep(),
|
||
new ContentAnalysisStep(),
|
||
new TranslationStep(),
|
||
new CategoryClassificationStep(),
|
||
new TagGenerationStep(),
|
||
new IndexingStep()
|
||
]
|
||
|
||
async process(rawContent: RawContent): Promise<ProcessedContent> {
|
||
let content = rawContent as any
|
||
|
||
for (const step of this.steps) {
|
||
try {
|
||
content = await step.execute(content)
|
||
await this.logStepCompletion(step.name, content.id)
|
||
} catch (error) {
|
||
await this.handleStepError(step.name, content.id, error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
return content as ProcessedContent
|
||
}
|
||
}
|
||
|
||
// 具体处理步骤
|
||
export class AIQualityAssessmentStep implements PipelineStep {
|
||
async execute(content: Content): Promise<Content> {
|
||
const qualityScore = await this.aiService.assessContentQuality(content)
|
||
|
||
if (qualityScore < 0.6) {
|
||
throw new QualityThresholdError('Content quality below threshold')
|
||
}
|
||
|
||
return {
|
||
...content,
|
||
qualityScore,
|
||
qualityAssessedAt: new Date()
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 多语言扩展实现
|
||
|
||
**扩展现有i18n系统**
|
||
```typescript
|
||
// i18n/ai-i18n-extension.ts
|
||
export class AIi18nExtension {
|
||
private translator: AITranslationService
|
||
|
||
constructor(private i18n: typeof import('@/uni_modules/ak-i18n')) {
|
||
this.translator = new AITranslationService()
|
||
}
|
||
|
||
// AI智能翻译缺失的键值
|
||
async autoTranslateMissingKeys(
|
||
targetLanguage: string,
|
||
sourceLanguage: string = 'zh-CN'
|
||
): Promise<void> {
|
||
const sourceMessages = this.i18n.global.getLocaleMessage(sourceLanguage)
|
||
const targetMessages = this.i18n.global.getLocaleMessage(targetLanguage)
|
||
|
||
const missingKeys = this.findMissingKeys(sourceMessages, targetMessages)
|
||
|
||
if (missingKeys.length > 0) {
|
||
const translations = await this.translator.translateKeys(
|
||
missingKeys,
|
||
sourceLanguage,
|
||
targetLanguage
|
||
)
|
||
|
||
// 合并翻译结果
|
||
this.i18n.global.mergeLocaleMessage(targetLanguage, translations)
|
||
|
||
// 保存到数据库
|
||
await this.saveTranslationsToDatabase(translations, targetLanguage)
|
||
}
|
||
}
|
||
|
||
// AI内容本地化
|
||
async localizeContent(
|
||
content: Content,
|
||
targetLanguage: string
|
||
): Promise<LocalizedContent> {
|
||
const translatedContent = await this.translator.translateContent(
|
||
content,
|
||
[targetLanguage]
|
||
)
|
||
|
||
// AI文化适应性调整
|
||
const culturallyAdapted = await this.adaptToCulture(
|
||
translatedContent[0],
|
||
targetLanguage
|
||
)
|
||
|
||
return culturallyAdapted
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📱 前端实现
|
||
|
||
### 1. AI聊天组件
|
||
```vue
|
||
<!-- components/ai-chat/AIChatComponent.vue -->
|
||
<template>
|
||
<view class="ai-chat-container">
|
||
<!-- 消息列表 -->
|
||
<scroll-view class="messages-list" :scroll-top="scrollTop">
|
||
<view
|
||
v-for="message in messages"
|
||
:key="message.id"
|
||
class="message-item"
|
||
:class="{ 'user-message': message.isUser, 'ai-message': !message.isUser }"
|
||
>
|
||
<view class="message-content">
|
||
<text class="message-text">{{ message.content }}</text>
|
||
<text class="message-time">{{ formatTime(message.timestamp) }}</text>
|
||
</view>
|
||
|
||
<!-- AI消息额外功能 -->
|
||
<view v-if="!message.isUser && message.actions" class="message-actions">
|
||
<button
|
||
v-for="action in message.actions"
|
||
:key="action.id"
|
||
@click="handleAction(action)"
|
||
class="action-btn"
|
||
>
|
||
{{ $t(action.labelKey) }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 输入区域 -->
|
||
<view class="input-area">
|
||
<input
|
||
v-model="inputText"
|
||
:placeholder="$t('ai.chat.inputPlaceholder')"
|
||
@confirm="sendMessage"
|
||
class="chat-input"
|
||
/>
|
||
<button @click="sendMessage" class="send-btn" :disabled="!inputText.trim()">
|
||
<text class="send-icon">{{ sending ? '⏳' : '📤' }}</text>
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 语言切换 -->
|
||
<view class="language-selector">
|
||
<picker
|
||
:value="currentLanguageIndex"
|
||
:range="languageOptions"
|
||
@change="onLanguageChange"
|
||
>
|
||
<view class="language-picker">
|
||
🌐 {{ currentLanguage.nativeName }}
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, computed, nextTick } from 'vue'
|
||
import { useI18n } from '@/uni_modules/ak-i18n'
|
||
import { AIChatService } from '@/services/ai-chat-service'
|
||
|
||
const { t, locale } = useI18n()
|
||
const chatService = new AIChatService()
|
||
|
||
// 响应式数据
|
||
const messages = ref<ChatMessage[]>([])
|
||
const inputText = ref('')
|
||
const sending = ref(false)
|
||
const scrollTop = ref(0)
|
||
|
||
// 多语言支持
|
||
const languages = ref([
|
||
{ code: 'zh-CN', nativeName: '简体中文' },
|
||
{ code: 'en-US', nativeName: 'English' },
|
||
{ code: 'ja-JP', nativeName: '日本語' },
|
||
{ code: 'ko-KR', nativeName: '한국어' }
|
||
])
|
||
|
||
const currentLanguageIndex = computed(() => {
|
||
return languages.value.findIndex(lang => lang.code === locale.value)
|
||
})
|
||
|
||
const currentLanguage = computed(() => {
|
||
return languages.value[currentLanguageIndex.value] || languages.value[0]
|
||
})
|
||
|
||
const languageOptions = computed(() => {
|
||
return languages.value.map(lang => lang.nativeName)
|
||
})
|
||
|
||
// 发送消息
|
||
const sendMessage = async () => {
|
||
if (!inputText.value.trim() || sending.value) return
|
||
|
||
const userMessage: ChatMessage = {
|
||
id: Date.now().toString(),
|
||
content: inputText.value,
|
||
isUser: true,
|
||
timestamp: new Date()
|
||
}
|
||
|
||
messages.value.push(userMessage)
|
||
|
||
const currentInput = inputText.value
|
||
inputText.value = ''
|
||
sending.value = true
|
||
|
||
try {
|
||
const response = await chatService.sendMessage(
|
||
currentInput,
|
||
locale.value
|
||
)
|
||
|
||
const aiMessage: ChatMessage = {
|
||
id: (Date.now() + 1).toString(),
|
||
content: response.message,
|
||
isUser: false,
|
||
timestamp: new Date(),
|
||
actions: response.actions
|
||
}
|
||
|
||
messages.value.push(aiMessage)
|
||
|
||
} catch (error) {
|
||
console.error('AI chat error:', error)
|
||
|
||
const errorMessage: ChatMessage = {
|
||
id: (Date.now() + 1).toString(),
|
||
content: t('ai.chat.errorMessage'),
|
||
isUser: false,
|
||
timestamp: new Date(),
|
||
isError: true
|
||
}
|
||
|
||
messages.value.push(errorMessage)
|
||
} finally {
|
||
sending.value = false
|
||
await nextTick()
|
||
scrollToBottom()
|
||
}
|
||
}
|
||
|
||
// 处理AI消息的行动按钮
|
||
const handleAction = async (action: MessageAction) => {
|
||
switch (action.type) {
|
||
case 'search':
|
||
await handleSearchAction(action.data)
|
||
break
|
||
case 'recommend':
|
||
await handleRecommendAction(action.data)
|
||
break
|
||
case 'translate':
|
||
await handleTranslateAction(action.data)
|
||
break
|
||
}
|
||
}
|
||
|
||
// 语言切换
|
||
const onLanguageChange = (e: any) => {
|
||
const selectedLang = languages.value[e.detail.value[0]]
|
||
locale.value = selectedLang.code
|
||
|
||
// 通知AI切换语言
|
||
chatService.setLanguage(selectedLang.code)
|
||
|
||
// 添加语言切换消息
|
||
const switchMessage: ChatMessage = {
|
||
id: Date.now().toString(),
|
||
content: t('ai.chat.languageSwitched', { language: selectedLang.nativeName }),
|
||
isUser: false,
|
||
timestamp: new Date(),
|
||
isSystem: true
|
||
}
|
||
|
||
messages.value.push(switchMessage)
|
||
}
|
||
|
||
// 滚动到底部
|
||
const scrollToBottom = () => {
|
||
scrollTop.value = messages.value.length * 100
|
||
}
|
||
|
||
// 初始化
|
||
onMounted(() => {
|
||
const welcomeMessage: ChatMessage = {
|
||
id: '0',
|
||
content: t('ai.chat.welcomeMessage'),
|
||
isUser: false,
|
||
timestamp: new Date(),
|
||
isSystem: true
|
||
}
|
||
|
||
messages.value.push(welcomeMessage)
|
||
})
|
||
</script>
|
||
```
|
||
|
||
### 2. 多语言内容组件
|
||
```vue
|
||
<!-- components/content/MultilingualContentCard.vue -->
|
||
<template>
|
||
<view class="content-card">
|
||
<!-- 语言标识 -->
|
||
<view class="language-indicator">
|
||
<text class="language-code">{{ currentContentLanguage }}</text>
|
||
<view v-if="availableLanguages.length > 1" class="language-options">
|
||
<button
|
||
v-for="lang in availableLanguages"
|
||
:key="lang"
|
||
@click="switchContentLanguage(lang)"
|
||
class="lang-btn"
|
||
:class="{ active: lang === currentContentLanguage }"
|
||
>
|
||
{{ getLanguageName(lang) }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容标题 -->
|
||
<text class="content-title">{{ currentContent.title }}</text>
|
||
|
||
<!-- 内容摘要 -->
|
||
<text class="content-summary">{{ currentContent.summary }}</text>
|
||
|
||
<!-- AI生成的标签 -->
|
||
<view class="tags-container">
|
||
<view
|
||
v-for="tag in currentContent.aiTags"
|
||
:key="tag.id"
|
||
class="tag-item"
|
||
:class="`tag-${tag.type}`"
|
||
>
|
||
<text class="tag-text">{{ tag.name }}</text>
|
||
<text class="tag-confidence">{{ Math.round(tag.confidence * 100) }}%</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 翻译质量指示器 -->
|
||
<view v-if="isTranslated" class="translation-info">
|
||
<view class="quality-indicator">
|
||
<text class="quality-label">{{ $t('content.translationQuality') }}:</text>
|
||
<view class="quality-bar">
|
||
<view
|
||
class="quality-fill"
|
||
:style="{ width: (currentContent.translationQuality * 100) + '%' }"
|
||
></view>
|
||
</view>
|
||
<text class="quality-score">{{ Math.round(currentContent.translationQuality * 100) }}%</text>
|
||
</view>
|
||
|
||
<button @click="requestHumanReview" class="review-btn">
|
||
{{ $t('content.requestHumanReview') }}
|
||
</button>
|
||
</view>
|
||
|
||
<!-- AI推荐理由 -->
|
||
<view v-if="recommendationReason" class="recommendation-reason">
|
||
<text class="reason-label">{{ $t('content.recommendedBecause') }}:</text>
|
||
<text class="reason-text">{{ recommendationReason }}</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, computed, watch } from 'vue'
|
||
import { useI18n } from '@/uni_modules/ak-i18n'
|
||
import type { MultilingualContent, AITag } from '@/types/content'
|
||
|
||
interface Props {
|
||
content: MultilingualContent
|
||
recommendationReason?: string
|
||
}
|
||
|
||
const props = defineProps<Props>()
|
||
const { t, locale } = useI18n()
|
||
|
||
// 当前显示的语言
|
||
const currentContentLanguage = ref(locale.value)
|
||
|
||
// 可用的语言版本
|
||
const availableLanguages = computed(() => {
|
||
return Object.keys(props.content.translations || {})
|
||
})
|
||
|
||
// 当前语言的内容
|
||
const currentContent = computed(() => {
|
||
const translation = props.content.translations?.[currentContentLanguage.value]
|
||
|
||
return {
|
||
title: translation?.title || props.content.originalTitle,
|
||
summary: translation?.summary || props.content.originalSummary,
|
||
translationQuality: translation?.qualityScore || 1,
|
||
aiTags: translation?.aiTags || props.content.originalTags
|
||
}
|
||
})
|
||
|
||
// 是否为翻译内容
|
||
const isTranslated = computed(() => {
|
||
return currentContentLanguage.value !== props.content.originalLanguage
|
||
})
|
||
|
||
// 切换内容语言
|
||
const switchContentLanguage = (lang: string) => {
|
||
currentContentLanguage.value = lang
|
||
}
|
||
|
||
// 获取语言名称
|
||
const getLanguageName = (langCode: string): string => {
|
||
const langMap = {
|
||
'zh-CN': '中文',
|
||
'en-US': 'English',
|
||
'ja-JP': '日本語',
|
||
'ko-KR': '한국어'
|
||
} as UTSJSONObject
|
||
|
||
return langMap.getString(langCode) || langCode
|
||
}
|
||
|
||
// 请求人工审核
|
||
const requestHumanReview = () => {
|
||
// 实现人工审核请求逻辑
|
||
uni.showToast({
|
||
title: t('content.reviewRequestSent'),
|
||
icon: 'success'
|
||
})
|
||
}
|
||
|
||
// 监听系统语言变化
|
||
watch(locale, (newLocale) => {
|
||
if (availableLanguages.value.includes(newLocale)) {
|
||
currentContentLanguage.value = newLocale
|
||
}
|
||
})
|
||
</script>
|
||
```
|
||
|
||
## 🚀 部署和运维
|
||
|
||
### 1. 容器化部署
|
||
|
||
**Docker配置**
|
||
```dockerfile
|
||
# Dockerfile
|
||
FROM node:18-alpine
|
||
|
||
WORKDIR /app
|
||
|
||
# 安装依赖
|
||
COPY package*.json ./
|
||
RUN npm ci --only=production
|
||
|
||
# 复制源代码
|
||
COPY . .
|
||
|
||
# 构建应用
|
||
RUN npm run build
|
||
|
||
# 暴露端口
|
||
EXPOSE 3000
|
||
|
||
# 启动命令
|
||
CMD ["npm", "start"]
|
||
```
|
||
|
||
**Docker Compose配置**
|
||
```yaml
|
||
# docker-compose.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
app:
|
||
build: .
|
||
ports:
|
||
- "3000:3000"
|
||
environment:
|
||
- NODE_ENV=production
|
||
- DATABASE_URL=${DATABASE_URL}
|
||
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||
- REDIS_URL=${REDIS_URL}
|
||
depends_on:
|
||
- redis
|
||
- postgres
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
ports:
|
||
- "6379:6379"
|
||
|
||
postgres:
|
||
image: postgres:15-alpine
|
||
environment:
|
||
- POSTGRES_DB=ai_news_system
|
||
- POSTGRES_USER=${DB_USER}
|
||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||
volumes:
|
||
- postgres_data:/var/lib/postgresql/data
|
||
|
||
nginx:
|
||
image: nginx:alpine
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
volumes:
|
||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||
- ./ssl:/etc/nginx/ssl
|
||
depends_on:
|
||
- app
|
||
|
||
volumes:
|
||
postgres_data:
|
||
```
|
||
|
||
### 2. 监控和日志
|
||
|
||
**监控配置**
|
||
```typescript
|
||
// monitoring/ai-metrics.ts
|
||
export class AIMetricsCollector {
|
||
private prometheus: any
|
||
|
||
constructor() {
|
||
this.prometheus = require('prom-client')
|
||
this.setupMetrics()
|
||
}
|
||
|
||
private setupMetrics() {
|
||
// AI API调用次数
|
||
this.aiApiCallsTotal = new this.prometheus.Counter({
|
||
name: 'ai_api_calls_total',
|
||
help: 'Total number of AI API calls',
|
||
labelNames: ['provider', 'model', 'function']
|
||
})
|
||
|
||
// AI响应时间
|
||
this.aiResponseTime = new this.prometheus.Histogram({
|
||
name: 'ai_response_duration_seconds',
|
||
help: 'AI API response time in seconds',
|
||
labelNames: ['provider', 'model']
|
||
})
|
||
|
||
// 翻译质量分数
|
||
this.translationQuality = new this.prometheus.Gauge({
|
||
name: 'translation_quality_score',
|
||
help: 'Average translation quality score',
|
||
labelNames: ['source_lang', 'target_lang', 'provider']
|
||
})
|
||
|
||
// 内容处理队列长度
|
||
this.queueLength = new this.prometheus.Gauge({
|
||
name: 'content_processing_queue_length',
|
||
help: 'Number of items in content processing queue'
|
||
})
|
||
}
|
||
|
||
recordAICall(provider: string, model: string, func: string, duration: number) {
|
||
this.aiApiCallsTotal.inc({ provider, model, function: func })
|
||
this.aiResponseTime.observe({ provider, model }, duration)
|
||
}
|
||
|
||
recordTranslationQuality(
|
||
sourceLang: string,
|
||
targetLang: string,
|
||
provider: string,
|
||
score: number
|
||
) {
|
||
this.translationQuality.set({
|
||
source_lang: sourceLang,
|
||
target_lang: targetLang,
|
||
provider
|
||
}, score)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 性能优化
|
||
|
||
**缓存策略**
|
||
```typescript
|
||
// cache/ai-cache-manager.ts
|
||
export class AICacheManager {
|
||
private redis: Redis
|
||
|
||
constructor() {
|
||
this.redis = new Redis(process.env.REDIS_URL)
|
||
}
|
||
|
||
// 翻译结果缓存
|
||
async getCachedTranslation(
|
||
text: string,
|
||
sourceLang: string,
|
||
targetLang: string
|
||
): Promise<string | null> {
|
||
const key = this.generateTranslationKey(text, sourceLang, targetLang)
|
||
return await this.redis.get(key)
|
||
}
|
||
|
||
async setCachedTranslation(
|
||
text: string,
|
||
sourceLang: string,
|
||
targetLang: string,
|
||
translation: string,
|
||
ttl: number = 86400 // 24小时
|
||
): Promise<void> {
|
||
const key = this.generateTranslationKey(text, sourceLang, targetLang)
|
||
await this.redis.setex(key, ttl, translation)
|
||
}
|
||
|
||
// AI分析结果缓存
|
||
async getCachedAnalysis(contentHash: string): Promise<ContentAnalysis | null> {
|
||
const key = `analysis:${contentHash}`
|
||
const cached = await this.redis.get(key)
|
||
return cached ? JSON.parse(cached) : null
|
||
}
|
||
|
||
async setCachedAnalysis(
|
||
contentHash: string,
|
||
analysis: ContentAnalysis,
|
||
ttl: number = 3600 // 1小时
|
||
): Promise<void> {
|
||
const key = `analysis:${contentHash}`
|
||
await this.redis.setex(key, ttl, JSON.stringify(analysis))
|
||
}
|
||
|
||
private generateTranslationKey(
|
||
text: string,
|
||
sourceLang: string,
|
||
targetLang: string
|
||
): string {
|
||
const hash = this.calculateHash(text)
|
||
return `translation:${hash}:${sourceLang}:${targetLang}`
|
||
}
|
||
|
||
private calculateHash(text: string): string {
|
||
return require('crypto')
|
||
.createHash('md5')
|
||
.update(text)
|
||
.digest('hex')
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📊 成本控制和优化
|
||
|
||
### 1. AI API成本控制
|
||
|
||
```typescript
|
||
// cost-control/ai-cost-manager.ts
|
||
export class AICostManager {
|
||
private costLimits = {
|
||
daily: 1000, // 每日$1000限额
|
||
monthly: 25000, // 每月$25000限额
|
||
perUser: 50 // 每用户每月$50限额
|
||
}
|
||
|
||
async checkCostLimit(
|
||
userId: string,
|
||
provider: string,
|
||
estimatedCost: number
|
||
): Promise<boolean> {
|
||
const usage = await this.getCurrentUsage(userId, provider)
|
||
|
||
// 检查各种限额
|
||
if (usage.daily + estimatedCost > this.costLimits.daily) {
|
||
throw new CostLimitExceededError('Daily cost limit exceeded')
|
||
}
|
||
|
||
if (usage.monthly + estimatedCost > this.costLimits.monthly) {
|
||
throw new CostLimitExceededError('Monthly cost limit exceeded')
|
||
}
|
||
|
||
if (usage.userMonthly + estimatedCost > this.costLimits.perUser) {
|
||
throw new CostLimitExceededError('User monthly limit exceeded')
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
async optimizeTranslationStrategy(
|
||
content: string,
|
||
targetLanguages: string[]
|
||
): Promise<OptimizationStrategy> {
|
||
const contentComplexity = this.analyzeComplexity(content)
|
||
const strategies: OptimizationStrategy = {}
|
||
|
||
for (const lang of targetLanguages) {
|
||
if (contentComplexity.score < 0.3) {
|
||
// 简单内容使用便宜的API
|
||
strategies[lang] = 'google_translate'
|
||
} else if (contentComplexity.score < 0.7) {
|
||
// 中等复杂度内容使用混合策略
|
||
strategies[lang] = 'hybrid'
|
||
} else {
|
||
// 复杂内容使用高质量API
|
||
strategies[lang] = 'gpt4'
|
||
}
|
||
}
|
||
|
||
return strategies
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 智能批处理
|
||
|
||
```typescript
|
||
// batch-processing/intelligent-batch.ts
|
||
export class IntelligentBatchProcessor {
|
||
private batchSize = 10
|
||
private maxWaitTime = 30000 // 30秒
|
||
private pendingItems: BatchItem[] = []
|
||
|
||
async addToBatch(item: BatchItem): Promise<ProcessingResult> {
|
||
return new Promise((resolve, reject) => {
|
||
this.pendingItems.push({
|
||
...item,
|
||
resolve,
|
||
reject,
|
||
addedAt: Date.now()
|
||
})
|
||
|
||
// 如果达到批次大小或等待时间,立即处理
|
||
if (this.pendingItems.length >= this.batchSize) {
|
||
this.processBatch()
|
||
} else if (this.pendingItems.length === 1) {
|
||
// 设置定时器
|
||
setTimeout(() => {
|
||
if (this.pendingItems.length > 0) {
|
||
this.processBatch()
|
||
}
|
||
}, this.maxWaitTime)
|
||
}
|
||
})
|
||
}
|
||
|
||
private async processBatch(): Promise<void> {
|
||
const batch = this.pendingItems.splice(0, this.batchSize)
|
||
|
||
try {
|
||
// 根据类型分组批处理
|
||
const groups = this.groupByType(batch)
|
||
|
||
const results = await Promise.all([
|
||
this.processTranslationBatch(groups.translation || []),
|
||
this.processAnalysisBatch(groups.analysis || []),
|
||
this.processClassificationBatch(groups.classification || [])
|
||
])
|
||
|
||
// 返回结果给各个Promise
|
||
this.resolveResults(batch, results.flat())
|
||
|
||
} catch (error) {
|
||
// 批量处理失败,逐个处理
|
||
await this.processFallback(batch)
|
||
}
|
||
}
|
||
|
||
private async processTranslationBatch(items: BatchItem[]): Promise<any[]> {
|
||
if (items.length === 0) return []
|
||
|
||
// 合并所有文本进行批量翻译
|
||
const texts = items.map(item => item.data.text)
|
||
const targetLang = items[0].data.targetLanguage
|
||
|
||
const results = await this.aiService.batchTranslate(texts, targetLang)
|
||
|
||
return results.map((result, index) => ({
|
||
id: items[index].id,
|
||
result
|
||
}))
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🔮 未来扩展计划
|
||
|
||
### 1. 高级AI功能
|
||
- **多模态内容处理**: 图片、视频、音频的AI分析
|
||
- **实时语音翻译**: 语音内容的实时多语言转换
|
||
- **AI主播**: 虚拟AI主播播报新闻
|
||
- **个性化AI助手**: 每个用户的专属AI助手
|
||
|
||
### 2. 技术架构升级
|
||
- **边缘计算**: CDN边缘节点部署AI推理
|
||
- **联邦学习**: 保护隐私的分布式学习
|
||
- **区块链集成**: 内容溯源和版权保护
|
||
- **Web3集成**: 去中心化内容分发
|
||
|
||
### 3. 商业模式扩展
|
||
- **AI内容生成服务**: 为企业提供AI内容生成
|
||
- **多语言SaaS平台**: AI翻译和本地化服务
|
||
- **数据分析服务**: 全球资讯趋势分析
|
||
- **API服务**: 对外提供AI能力API
|
||
|
||
## 📋 实施计划
|
||
|
||
### 第一阶段 (1-3个月): 基础架构搭建
|
||
- [ ] 数据库设计和实现
|
||
- [ ] AI服务集成
|
||
- [ ] 基础多语言框架扩展
|
||
- [ ] 内容采集和处理管道
|
||
|
||
### 第二阶段 (4-6个月): 核心功能开发
|
||
- [ ] AI翻译服务
|
||
- [ ] 内容分类和标签系统
|
||
- [ ] 基础推荐算法
|
||
- [ ] 前端界面开发
|
||
|
||
### 第三阶段 (7-9个月): 高级功能
|
||
- [ ] AI聊天助手
|
||
- [ ] 个性化推荐优化
|
||
- [ ] 内容质量评估
|
||
- [ ] 性能优化
|
||
|
||
### 第四阶段 (10-12个月): 上线和优化
|
||
- [ ] 系统集成测试
|
||
- [ ] 性能压力测试
|
||
- [ ] 用户体验优化
|
||
- [ ] 正式上线部署
|
||
|
||
## 💰 投资预算估算
|
||
|
||
### 技术成本
|
||
- **AI API费用**: $5,000-15,000/月
|
||
- **云服务费用**: $2,000-5,000/月
|
||
- **第三方服务**: $1,000-3,000/月
|
||
|
||
### 人力成本
|
||
- **技术团队**: 8-12人,年薪总计$800K-1.2M
|
||
- **产品设计**: 2-3人,年薪总计$200K-300K
|
||
- **运营团队**: 3-5人,年薪总计$180K-300K
|
||
|
||
### 总预算估算
|
||
- **第一年总投资**: $1.5M-2.5M
|
||
- **运营成本**: $100K-300K/月
|
||
- **预期回报周期**: 18-24个月
|
||
|
||
---
|
||
|
||
## 📞 联系和支持
|
||
|
||
如需详细的技术实现细节或有任何问题,请联系开发团队。
|
||
|
||
**文档版本**: v1.0
|
||
**最后更新**: 2025年6月18日
|
||
**作者**: AI系统架构师团队
|