PHP项目实现“点评本场观众氛围”方案
要在PHP项目中实现观众氛围点评功能,核心是收集数据 → 分析/生成评价 → 展示,下面给你一套完整可落地的思路。

整体架构
观众行为数据采集 → 数据存储 → 氛围评分算法 → 生成点评文案 → 前端展示
数据采集维度
需要先定义哪些行为能反映“氛围”:
| 维度 | 数据来源 | 权重示例 |
|---|---|---|
| 弹幕/评论数量 | 实时消息表 | 30% |
| 点赞/礼物数 | 互动记录 | 25% |
| 在线人数峰值 | 会话统计 | 20% |
| 互动频次(人均) | 计算得出 | 15% |
| 情绪倾向(关键词) | 弹幕情感分析 | 10% |
数据库设计
-- 互动事件表
CREATE TABLE audience_events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
room_id INT NOT NULL,
user_id INT NOT NULL,
event_type ENUM('danmaku','like','gift','enter','share') NOT NULL,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_room_time (room_id, created_at)
);
-- 氛围点评结果表
CREATE TABLE atmosphere_reports (
id INT PRIMARY KEY AUTO_INCREMENT,
room_id INT NOT NULL,
session_id VARCHAR(64) NOT NULL,
score TINYINT, -- 0-100
level VARCHAR(20), -- 冷清/一般/活跃/火爆
comment TEXT, -- 点评文案
metrics JSON, -- 原始指标快照
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
核心评分算法(PHP)
<?php
class AtmosphereAnalyzer
{
public function analyze(int $roomId, string $sessionStart, string $sessionEnd): array
{
$db = Database::getInstance();
// 1. 拉取本场数据
$sql = "SELECT event_type, COUNT(*) AS cnt, COUNT(DISTINCT user_id) AS users
FROM audience_events
WHERE room_id = ? AND created_at BETWEEN ? AND ?
GROUP BY event_type";
$rows = $db->query($sql, [$roomId, $sessionStart, $sessionEnd]);
$stats = ['danmaku'=>0,'like'=>0,'gift'=>0,'enter'=>0,'share'=>0,
'unique_users'=>0];
foreach ($rows as $r) {
$stats[$r['event_type']] = (int)$r['cnt'];
}
// 2. 计算人均互动
$uniqueUsers = $db->queryScalar(
"SELECT COUNT(DISTINCT user_id) FROM audience_events
WHERE room_id=? AND created_at BETWEEN ? AND ?",
[$roomId, $sessionStart, $sessionEnd]
) ?: 1;
$stats['unique_users'] = $uniqueUsers;
$totalInteractions = $stats['danmaku'] + $stats['like'] + $stats['gift'];
$perUser = $totalInteractions / $uniqueUsers;
// 3. 分项打分(每项满分100)
$scoreDanmaku = $this->normalize($stats['danmaku'], 500, 5000);
$scoreLike = $this->normalize($stats['like'], 200, 3000);
$scorePerUser = $this->normalize($perUser, 1, 10);
$scoreGift = $this->normalize($stats['gift'], 10, 200);
// 4. 加权总分
$score = (int) round(
$scoreDanmaku * 0.35 +
$scoreLike * 0.25 +
$scorePerUser * 0.20 +
$scoreGift * 0.20
);
// 5. 定级 + 生成点评
$level = $this->level($score);
$comment = $this->generateComment($level, $stats, $perUser);
// 6. 落库
$db->insert('atmosphere_reports', [
'room_id' => $roomId,
'session_id' => md5($sessionStart.$sessionEnd),
'score' => $score,
'level' => $level,
'comment' => $comment,
'metrics' => json_encode($stats),
]);
return compact('score','level','comment','stats');
}
// 归一化:把任意区间映射到 0-100
private function normalize(float $value, float $min, float $max): float
{
if ($value <= $min) return 0;
if ($value >= $max) return 100;
return ($value - $min) / ($max - $min) * 100;
}
private function level(int $score): string
{
return match(true) {
$score >= 85 => '火爆',
$score >= 65 => '活跃',
$score >= 40 => '一般',
default => '冷清',
};
}
private function generateComment(string $level, array $stats, float $perUser): string
{
$templates = [
'火爆' => "全场气氛炸裂!弹幕和礼物刷不停,人均互动 %.1f 次,这是本场的高光时刻 🔥",
'活跃' => "观众参与度很高,评论区热闹非凡,整体氛围非常不错 👍",
'一般' => "气氛尚可,部分观众积极互动,整体表现中规中矩。",
'冷清' => "本场较为安静,互动较少,建议主播多引导观众参与~",
];
$tpl = $templates[$level];
return str_contains($tpl, '%')
? sprintf($tpl, $perUser)
: $tpl;
}
}
进阶:接入 AI 生成更自然的点评
如果想点评更“像人话”,可接入大模型:
class AiCommentGenerator
{
public function generate(array $stats, int $score): string
{
$prompt = "根据以下直播间数据,用一句话点评本场观众氛围(活泼口语化,30字内):
弹幕数:{$stats['danmaku']}
点赞数:{$stats['like']}
礼物数:{$stats['gift']}
在线人数:{$stats['unique_users']}
综合评分:{$score}/100";
$resp = $this->callLLM($prompt); // 调用 OpenAI/通义等
return trim($resp);
}
private function callLLM(string $prompt): string
{
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . getenv('OPENAI_KEY'),
],
CURLOPT_POSTFIELDS => json_encode([
'model' => 'gpt-4o-mini',
'messages' => [['role'=>'user','content'=>$prompt]],
'temperature' => 0.8,
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return $result['choices'][0]['message']['content'] ?? '氛围不错~';
}
}
触发时机
- 实时点评:WebSocket / Swoole 每隔 30 秒统计一次,前端实时展示。
- 场次结束点评:直播结束后触发一次完整分析,生成“本场氛围报告”。
- 定时任务:用
crontab或 Laravel Scheduler 批量跑。
// Laravel 示例
Schedule::call(fn() => (new AtmosphereAnalyzer())->analyze(
$roomId, now()->subHour(), now()
))->everyThirtySeconds();
优化建议
- 防刷:同一用户短时间大量弹幕要降权,避免刷屏拉高评分。
- 情感分析:对弹幕做正向/负向关键词匹配,负向多时不只看数量。
- 动态阈值:不同房间基数不同,
normalize的 min/max 可按房间历史均值动态调整。 - 缓存:Redis 缓存 5 分钟统计结果,减轻数据库压力。
- 可视化:用 ECharts 画氛围曲线,比文字点评更直观。
最小可用版本(MVP)
如果只是先跑通流程,可以直接用一个函数:
function commentAtmosphere(int $danmaku, int $likes, int $users): string {
$perUser = $users > 0 ? ($danmaku + $likes) / $users : 0;
$score = min(100, ($danmaku/50) + ($likes/30) + ($perUser*5));
return match(true) {
$score >= 80 => "🔥 氛围火爆,观众超活跃!",
$score >= 50 => "👍 氛围不错,互动积极。",
$score >= 20 => "🙂 氛围一般,还有提升空间。",
default => "😴 氛围较冷清,需要引导互动。",
};
}
如果你告诉我你用的是原生PHP / ThinkPHP / Laravel,以及是直播场景还是视频播放场景,我可以给出更贴合的完整代码。