提交 a215af9e authored 作者: 王鹏飞's avatar 王鹏飞

feat: AI一键评分

上级 70de0f02
export const generateCommodityTypePrompt = (data: any) => {
return `请根据选手提交的商品品类信息进行评分(满分5分):
选手提交内容:
${JSON.stringify(data.commodity_types)}
评分标准:
1. 一级品类创建(2分)
检查项:
是否创建"护肤品类"(1分)
是否创建"彩妆品类"(1分)
2. 护肤品类二级分类(1.5分)
检查项:
"面膜系列"(0.5分)
"精华系列"(0.5分)
"水乳系列"(0.5分)
3. 彩妆品类二级分类(1.5分)
检查项:
"口红系列"(0.5分)
"眼影系列"(0.5分)
"腮红系列"(0.5分)
【整体评价】
(请对选手整体表现进行1-2句总结性评价)`
}
export const generateCommodityAttrsPrompt = (data: any) => {
return `
请根据选手提交的商品属性配置进行评分(满分5分):
选手提交内容:
${JSON.stringify(data.commodity_attrs)}
评分标准
1. 护肤品类属性配置(2.5分)
必须创建5个属性,每个0.5分:
属性1:适用肤质(0.5分)
属性名称正确(0.1分)
所属品类:护肤品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性2:核心成分(0.5分)
属性名称正确(0.1分)
所属品类:护肤品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性3:产品规格(0.5分)
属性名称正确(0.1分)
所属品类:护肤品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性4:产品功效(0.5分)
属性名称正确(0.1分)
所属品类:护肤品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性5:使用方法(0.5分)
属性名称正确(0.1分)
所属品类:护肤品类(0.1分)
重要性:非重要(0.1分)
必要性:非必须(0.1分)
状态:有效(0.1分)
2. 彩妆品类属性配置(2.5分)
必须创建5个属性,每个0.5分:
属性1:色号(0.5分)
属性名称正确(0.1分)
所属品类:彩妆品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性2:质地(0.5分)
属性名称正确(0.1分)
所属品类:彩妆品类(0.1分)
重要性:重要(0.1分)
必要性:必须(0.1分)
状态:有效(0.1分)
属性3:持久度(0.5分)
属性名称正确(0.1分)
所属品类:彩妆品类(0.1分)
重要性:重要(0.1分)
必要性:非必须(0.1分)
状态:有效(0.1分)
属性4:适用场景(0.5分)
属性名称正确(0.1分)
所属品类:彩妆品类(0.1分)
重要性:非重要(0.1分)
必要性:非必须(0.1分)
状态:有效(0.1分)
属性5:妆效风格(0.5分)
属性名称正确(0.1分)
所属品类:彩妆品类(0.1分)
重要性:非重要(0.1分)
必要性:非必须(0.1分)
状态:有效(0.1分)
评分细则
━━━━━━━━━━━━━━━━━━━━━━
【扣分规则】
- 属性名称完全匹配可得分
- 重要性、必要性设置错误,该属性扣50%分数(即扣0.2分)
- 关联品类错误,该属性不得分
- 状态未设置为"有效",该属性不得分
【注意事项】
1. 每个品类必须创建完整的5个属性
2. 属性必须正确关联到对应的品类
3. 重要性和必要性的配置必须完全符合要求
4. 所有属性的状态必须设置为"有效"`
}
export const generateCommoditiesPrompt = (data: any) => {
return `
请根据选手提交的商品信息维护内容进行评分(满分15分)
选手提交内容:
${JSON.stringify(data.commodities)}
选手需要完成2个主推商品的完整信息维护:
1. 玻尿酸补水面膜(引流款)
2. 烟酰胺精华液(利润款)
每个商品需完成5个板块的维护:
- 商品类目设置
- 基础信息维护(标题、短标题、商品属性)
- 图文信息维护(主图、3:4主图)
- 价格与库存信息
- 服务与履约
━━━━━━━━━━━━━━━━━━━━━━
评分标准(满分15分)
━━━━━━━━━━━━━━━━━━━━━━
一、商品类目关联(1分)
商品1:玻尿酸补水面膜(0.5分)
类目设置:_______________
正确关联:护肤品类 → 面膜系列(0.5分)
关联错误或未关联(0分)
商品2:烟酰胺精华液(0.5分)
类目设置:_______________
正确关联:护肤品类 → 精华系列(0.5分)
关联错误或未关联(0分)
━━━━━━━━━━━━━━━━━━━━━━
二、商品主图(1:1比例)(2分)
商品1:玻尿酸补水面膜(1分)
主图数量:___张
主图≥3张(1分)
主图2张(0.7分)
主图1张(0.3分)
主图0张(0分)
商品2:烟酰胺精华液(1分)
主图数量:___张
主图≥3张(1分)
主图2张(0.7分)
主图1张(0.3分)
主图0张(0分)
━━━━━━━━━━━━━━━━━━━━━━
三、3:4比例主图(2分)
商品1:玻尿酸补水面膜(1分)
3:4主图数量:___张
3:4主图≥2张(1分)
3:4主图1张(0.5分)
3:4主图0张(0分)
商品2:烟酰胺精华液(1分)
3:4主图数量:___张
3:4主图≥2张(1分)
3:4主图1张(0.5分)
3:4主图0张(0分)
━━━━━━━━━━━━━━━━━━━━━━
四、价格库存配置(6分)
商品1:玻尿酸补水面膜(3分)
1. 发货模式(0.5分)
发货模式:_______________
设置为"现货发货模式"(0.5分)
未设置或设置错误(0分)
2. 商品规格(0.8分)
设置的规格:_______________
设置了至少2个规格(0.8分)
只设置1个规格(0.4分)
未设置规格(0分)
3. 发货时效(0.5分)
发货时效:_______________
设置为"次日发"(0.5分)
未设置或设置错误(0分)
4. 价格设置(0.6分)
价格信息:_______________
设置了价格和参考价(0.6分)
只设置了价格,未设置参考价(0.3分)
未设置价格(0分)
5. 库存设置(0.3分)
库存信息:_______________
已设置库存数量(0.3分)
未设置库存(0分)
6. 订单库存扣减规则(0.3分)
扣减规则:_______________
选择"付款减库存"(0.3分)
未设置或设置错误(0分)
商品2:烟酰胺精华液(3分)
1. 发货模式(0.5分)
发货模式:_______________
设置为"现货发货模式"(0.5分)
未设置或设置错误(0分)
2. 商品规格(0.8分)
设置的规格:_______________
设置了至少2个规格(0.8分)
只设置1个规格(0.4分)
未设置规格(0分)
3. 发货时效(0.5分)
发货时效:_______________
设置为"次日发"(0.5分)
未设置或设置错误(0分)
4. 价格设置(0.6分)
价格信息:_______________
设置了价格和参考价(0.6分)
只设置了价格,未设置参考价(0.3分)
未设置价格(0分)
5. 库存设置(0.3分)
库存信息:_______________
已设置库存数量(0.3分)
未设置库存(0分)
6. 订单库存扣减规则(0.3分)
扣减规则:_______________
选择"付款减库存"(0.3分)
未设置或设置错误(0分)
━━━━━━━━━━━━━━━━━━━━━━
五、服务履约配置(4分)
商品1:玻尿酸补水面膜(2分)
1. 运费模板(1分)
运费模板:_______________
选择"指定条件包邮"模板(1分)
设置了其他运费模板(0.5分)
未设置运费模板(0分)
2. 售后政策(1分)
售后政策:_______________
至少选择了1项售后政策(1分)
未设置售后政策(0分)
━━━━━━━━━━━━━━━━━━━━━━
商品2:烟酰胺精华液(2分)
1. 运费模板(1分)
运费模板:_______________
选择"指定条件包邮"模板(1分)
设置了其他运费模板(0.5分)
未设置运费模板(0分)
2. 售后政策(1分)
售后政策:_______________
至少选择了1项售后政策(1分)
未设置售后政策(0分)
━━━━━━━━━━━━━━━━━━━━━━
【评分说明】
1. 商品类目关联是基础,必须正确关联到指定的二级品类
2. 图片评分以数量为主,质量为辅,数量达标即可得分
3. 价格库存配置是重点(6分),需要逐项检查6个配置项
4. 服务履约配置注重完整性,至少要有1项售后政策
5. 两个商品都必须完整维护,缺少任何一个商品都会大量失分
【整体评价】
(请对选手整体表现进行1-2句总结性评价)`
}
export const generateSpeechPrompt = (data: any) => {
return `
请根据选手提交的直播话术进行评分(满分15分)
选手提交内容内容:
${JSON.stringify(data.speeches)}
选手需要编写完整的直播话术,包括:
- 话术名称设置
- 商品选择
- 商品卖点提炼(至少3个)
- 营销活动设计(至少4个)
- 完整话术脚本(15分钟)
━━━━━━━━━━━━━━━━━━━━━━
评分标准(满分15分)
━━━━━━━━━━━━━━━━━━━━━━
一、话术名称(1分)
话术名称:_______________
评分标准:
字数5-20字(0.5分)
简洁明了(0.3分)
体现直播主题(0.2分)
二、商品选择(1分)
选择的商品:_______________
评分标准:
正确选择(1分)
未选择(0分)
━━━━━━━━━━━━━━━━━━━━━━
三、卖点提炼(3分)
要求:满足以下卖点中三个,每个卖点1分
【参考卖点】
卖点1:5%高浓度烟酰胺,科学配比,淡化细纹效果显著
卖点2:添加传明酸和维C衍生物,多重美白,提亮肤色
卖点3:7天见效,28天肌肤焕然一新(真实用户反馈)
卖点4:清爽质地,不油腻,吸收快,适合所有肤质
卖点5:30ml精华液相当于3瓶普通精华的量,超大容量
━━━━━━━━━━━━━━━━━━━━━━
四、营销活动设计(3分)
要求:至少设计4个营销活动,每个0.75分
【必须包含的活动类型检查】
限时秒杀活动
组合优惠活动
互动抽奖活动
下单福利
━━━━━━━━━━━━━━━━━━━━━━
五、话术结构完整性(2分)
话术脚本必须包含以下7个环节:
①开场白环节(0.3分)
- 热情问候、自我介绍
- 直播主题引入
- 福利活动预告
- 引导关注点赞
②品牌介绍环节(0.25分)
- 品牌故事和理念
- 品牌实力和成就
- 建立品牌信任度
③产品讲解环节(0.4分)
- 产品展示
- 成分讲解(5%烟酰胺、传明酸等)
- 卖点阐述
- 使用方法和效果
- 价格对比和优惠信息
④互动环节(0.3分)
- 回应观众提问
- 互动问答
- 抽奖活动执行
- 调动直播间氛围
⑤促销推动环节(0.3分)
- 强调组合优惠
- 满额包邮等促销政策
- 催单话术
⑥结束语环节(0.25分)
- 总结本场直播要点
- 感谢观众支持
- 最后提醒下单福利
⑦额外加分环节(0.2分)
- 预告下次直播
- 引导加粉丝群
- 其他创意环节
━━━━━━━━━━━━━━━━━━━━━━
六、话术内容质量(3分)
6.1 语言流畅自然(0.8分)
使用口语化表达(0.3分)
语言自然流畅,不生硬(0.3分)
表达亲切易懂(如"宝宝们"、"亲们")(0.2分)
6.2 逻辑清晰(0.7分)
各环节衔接顺畅(0.3分)
逻辑连贯,层次分明(0.2分)
节奏合理(0.2分)
6.3 卖点讲解充分(0.8分)
详细讲解产品卖点(0.3分)
有说服力,有具体案例或数据(0.3分)
突出5%烟酰胺等核心成分和功效(0.2分)
6.4 互动设计合理(0.7分)
互动环节设计合理(0.3分)
能调动氛围(0.2分)
互动方式多样(0.2分)
━━━━━━━━━━━━━━━━━━━━━━
七、时长设置(1分)
话术设置时长:___分钟
评分标准:
设置为15分钟(1分)
━━━━━━━━━━━━━━━━━━━━━━
八、话术规范性(1分)
【违禁词检测】
发现的违禁词:___________
常见违禁词类型:
- 绝对化用语:最、第一、唯一、极致、顶级、完美等
- 夸大宣传:100%、必然、保证、绝对、立即见效等
- 医疗用语:治疗、疗效、药用、治愈、医治等
- 虚假宣传:国家级、世界级、最高级、最低价等
评分标准:
零违禁词(1分)
1-2个违禁词(0.5-0.7分)
3-4个违禁词(0.3-0.4分)
5个以上违禁词(0-0.2分)
其他规范检查:
无夸大宣传
符合平台规范
表述真实可信
【评分说明】
1. 卖点提炼是核心(3分),至少3个卖点,要具体、有说服力
2. 营销活动设计(3分),至少4个活动,类型要多样
3. 话术内容质量(3分),重点看语言、逻辑、卖点讲解、互动
4. 话术结构必须包含7个环节,缺少任何环节都会扣分
5. 零违禁词是基本要求,发现违禁词将严重扣分
【整体评价】
(请对选手话术整体质量进行1-2句总结性评价)`
}
export const generatePracticeRecordPrompt = (data: any) => {
return `请根据选手提交的内容进行评分(满分20分)
选手提交内容:
${JSON.stringify(data.practice_records[0])}
`
}
export const generateImprovementPlanPrompt = (data: any) => {
return `请根据选手提交的改进方案进行评分(满分10分):
选手提交的改进方案:
${JSON.stringify(data.practice_records[0]?.improvement_plan)}
评分标准:
- 必须提出至少5条改进措施
- 每条改进措施2
- 必须包含:问题描述、改进目标、改进方法
`
}
export const generatePracticeRecord2Prompt = (data: any) => {
return `
请根据选手提交的二次直播演练内容进行评分(满分15分)
选手提交内容:
${JSON.stringify(data.practice_records[1])}
`
}
export const generateReportPrompt = (data: any) => {
return `请根据选手提交的直播总结报告进行评分(满分15分)
选手提交内容:
${JSON.stringify(data.reports)}
`
}
export const generatePrompt = (data: any) => {
return `
${generateCommodityTypePrompt(data)}
${generateCommodityAttrsPrompt(data)}
${generateCommoditiesPrompt(data)}
${generateSpeechPrompt(data)}
${generatePracticeRecordPrompt(data)}
${generateImprovementPlanPrompt(data)}
${generateReportPrompt(data)}
EXAMPLE JSON OUTPUT:
{
"commodity_type": {
"score": 5,
"comment": "这是评语"
},
"commodity_attr": {
"score": 5,
"comment": "这是评语"
},
"commodity": {
"score": 5,
"comment": "这是评语"
},
"speech": {
"score": 5,
"comment": "这是评语"
},
"practice_record1": {
"score": 5,
"comment": "这是评语"
},
"improvement_plan": {
"score": 5,
"comment": "这是评语"
},
"practice_record2": {
"score": 5,
"comment": "这是评语"
},
"report": {
"score": 5,
"comment": "这是评语"
},
}
`
}
...@@ -28,6 +28,7 @@ const listOptions = computed(() => { ...@@ -28,6 +28,7 @@ const listOptions = computed(() => {
], ],
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: 'ID', prop: 'id' },
{ label: '姓名', prop: 'student_name' }, { label: '姓名', prop: 'student_name' },
{ label: '专业', prop: 'specialty_name' }, { label: '专业', prop: 'specialty_name' },
{ label: '班级', prop: 'class_name' }, { label: '班级', prop: 'class_name' },
......
...@@ -13,11 +13,15 @@ import { ...@@ -13,11 +13,15 @@ import {
import ScoreCard from '../components/ScoreCard.vue' import ScoreCard from '../components/ScoreCard.vue'
import ScoreCardLive from '../components/ScoreCardLive.vue' import ScoreCardLive from '../components/ScoreCardLive.vue'
import Preview from '@/components/Preview.vue' import Preview from '@/components/Preview.vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { useChat } from '@ezijing/ai-vue'
import { generatePrompt } from '../prompt'
const route = useRoute() const route = useRoute()
const id = route.query.id const id = route.query.id
const { isLoading, generateText } = useChat({ provider: 'volcano' })
const statusList = useMapStore().getMapValuesByKey('system_status') const statusList = useMapStore().getMapValuesByKey('system_status')
const detail = ref(null) const detail = ref(null)
...@@ -100,6 +104,10 @@ const productList = computed(() => { ...@@ -100,6 +104,10 @@ const productList = computed(() => {
return detail.value.live_data?.commodities?.map((item) => { return detail.value.live_data?.commodities?.map((item) => {
try { try {
item.info = JSON.parse(item.info) item.info = JSON.parse(item.info)
item.info.delivery_mode_name = getNameByValue(item.info.delivery_mode, deliveryMode)
item.info.delivery_time_name = getNameByValue(item.info.delivery_time, deliveryTime)
item.info.shipping_template_name = getNameByValue(item.info.shipping_template, shippingTemplate)
item.info.after_sales_policy_name = getNameByValue(item.info.after_sales_policy, afterSalesPolicy)
item.live_commodity_attrs = JSON.parse(item.live_commodity_attrs) item.live_commodity_attrs = JSON.parse(item.live_commodity_attrs)
item.picture_34_addreses = JSON.parse(item.picture_34_addreses) item.picture_34_addreses = JSON.parse(item.picture_34_addreses)
item.picture_addreses = JSON.parse(item.picture_addreses) item.picture_addreses = JSON.parse(item.picture_addreses)
...@@ -120,34 +128,10 @@ const productTableOptions = { ...@@ -120,34 +128,10 @@ const productTableOptions = {
{ label: '商品标题', prop: 'title' }, { label: '商品标题', prop: 'title' },
{ label: '所属商品品类', prop: 'live_commodity_type_full_name' }, { label: '所属商品品类', prop: 'live_commodity_type_full_name' },
{ label: '参考价(¥)', prop: 'info.reference_price' }, { label: '参考价(¥)', prop: 'info.reference_price' },
{ { label: '发货模式', prop: 'info.delivery_mode_name' },
label: '发货模式', { label: '发货时效', prop: 'info.delivery_time_name' },
prop: 'delivery_mode', { label: '运费模板', prop: 'info.shipping_template_name' },
computed({ row }) { { label: '售后政策', prop: 'info.after_sales_policy_name' },
return getNameByValue(row.info.delivery_mode, deliveryMode)
},
},
{
label: '发货时效',
prop: 'delivery_time',
computed({ row }) {
return getNameByValue(row.info.delivery_time, deliveryTime)
},
},
{
label: '运费模板',
prop: 'shipping_template',
computed({ row }) {
return getNameByValue(row.info.shipping_template, shippingTemplate)
},
},
{
label: '售后政策',
prop: 'after_sales_policy',
computed({ row }) {
return getNameByValue(row.info.after_sales_policy, afterSalesPolicy)
},
},
], ],
} }
// 商品规格 // 商品规格
...@@ -197,8 +181,24 @@ const talkTableOptions = { ...@@ -197,8 +181,24 @@ const talkTableOptions = {
} }
const activeTab = ref(1) const activeTab = ref(1)
const handleAIScore = () => { const handleAIScore = async () => {
console.log('AI一键评分') console.log('AI一键评分')
const result = await generateText({
prompt: generatePrompt(detail.value.live_data),
response_format: { type: 'json_object' },
})
try {
const parsed = JSON.parse(result.content)
Object.assign(scoreDetails, parsed)
commitScore(0).then(() => {
ElMessage.success('保存成功')
})
} catch (error) {
console.log(error)
ElMessage.error('评分失败')
return
}
console.log(result.content)
} }
const handleSave = (key, params) => { const handleSave = (key, params) => {
...@@ -207,6 +207,7 @@ const handleSave = (key, params) => { ...@@ -207,6 +207,7 @@ const handleSave = (key, params) => {
ElMessage.success('保存成功') ElMessage.success('保存成功')
}) })
} }
const handleNext = () => { const handleNext = () => {
activeTab.value++ activeTab.value++
} }
...@@ -242,7 +243,9 @@ const handlePublishScore = () => { ...@@ -242,7 +243,9 @@ const handlePublishScore = () => {
<el-form-item label="状态">{{ detail.status_name }}</el-form-item> <el-form-item label="状态">{{ detail.status_name }}</el-form-item>
<el-form-item label="提交时间">{{ detail.commit_time }}</el-form-item> <el-form-item label="提交时间">{{ detail.commit_time }}</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" :disabled="detail.status == '2'" @click="handleAIScore">AI一键评分</el-button> <el-button type="primary" :disabled="detail.status == '2'" :loading="isLoading" @click="handleAIScore"
>AI一键评分</el-button
>
<el-button type="primary" :disabled="detail.status == '2'" @click="handlePublishScore">发布成绩</el-button> <el-button type="primary" :disabled="detail.status == '2'" @click="handlePublishScore">发布成绩</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
...@@ -411,7 +414,7 @@ const handlePublishScore = () => { ...@@ -411,7 +414,7 @@ const handlePublishScore = () => {
@save="handleSave('report', $event)" @save="handleSave('report', $event)"
@next="handleNext"> @next="handleNext">
<template v-if="detail.live_data.reports.length > 0"> <template v-if="detail.live_data.reports.length > 0">
<div v-for="item in detail.live_data.reports" :key="item.report_url"> <div v-for="item in detail.live_data.reports" :key="item.report_url" style="height: 600px">
<Preview :url="item.report_url" /> <Preview :url="item.report_url" />
</div> </div>
</template> </template>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论