fix: 更新API基础路径并优化SOP分析功能
- 将API基础路径从192.168.15.54更新为192.168.15.60 - 优化CustomerDetail组件中的SOP分析按钮状态控制 - 在SalesTimelineWithTaskList组件中添加直播发言展示功能 - 重构RawDataCards组件的查看原文逻辑,触发SOP分析并显示通话记录
This commit is contained in:
@@ -5,7 +5,7 @@ import { useUserStore } from '@/stores/user'
|
|||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: 'http://192.168.15.54:8890' || '', // API基础路径,支持完整URL
|
baseURL: 'http://192.168.15.60:8890' || '', // API基础路径,支持完整URL
|
||||||
timeout: 100000, // 请求超时时间
|
timeout: 100000, // 请求超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<button
|
<button
|
||||||
@click="startSopAnalysis"
|
@click="startSopAnalysis"
|
||||||
class="analysis-button sop-button"
|
class="analysis-button sop-button"
|
||||||
:disabled="true"
|
:disabled="isSopAnalysisLoading"
|
||||||
>
|
>
|
||||||
{{ isSopAnalysisLoading ? 'SOP分析中...' : 'SOP通话分析' }}
|
{{ isSopAnalysisLoading ? 'SOP分析中...' : 'SOP通话分析' }}
|
||||||
</button>
|
</button>
|
||||||
@@ -280,23 +280,15 @@ ${callInfoText}
|
|||||||
};
|
};
|
||||||
|
|
||||||
// SOP通话分析
|
// SOP通话分析
|
||||||
const startSopAnalysis = async () => {
|
const startSopAnalysis = async (recordContext) => {
|
||||||
if (!props.selectedContact) return;
|
if (!props.selectedContact) return;
|
||||||
|
|
||||||
isSopAnalysisLoading.value = true;
|
isSopAnalysisLoading.value = true;
|
||||||
sopAnalysisResult.value = '';
|
sopAnalysisResult.value = '';
|
||||||
|
|
||||||
const query = `请对客户 ${props.selectedContact.name} 进行SOP通话分析:
|
const query = callData.value
|
||||||
|
|
||||||
基于标准销售流程(SOP),分析以下方面:
|
console.log(888888, recordContext);
|
||||||
1. 通话质量评估
|
|
||||||
2. 销售流程执行情况
|
|
||||||
3. 客户响应度分析
|
|
||||||
4. 沟通效果评价
|
|
||||||
5. 改进建议
|
|
||||||
|
|
||||||
客户当前状态:${props.selectedContact.salesStage || '未知'}
|
|
||||||
健康度:${props.selectedContact.health || '未知'}%`;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await chatService.sendMessage(
|
await chatService.sendMessage(
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -137,6 +138,9 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Emits
|
||||||
|
const emit = defineEmits(['analyze-sop'])
|
||||||
|
|
||||||
// 当前激活的tab
|
// 当前激活的tab
|
||||||
const activeTab = ref('chat')
|
const activeTab = ref('chat')
|
||||||
|
|
||||||
@@ -272,44 +276,18 @@ const downloadRecording = (call) => {
|
|||||||
|
|
||||||
// 查看原文方法
|
// 查看原文方法
|
||||||
const viewTranscript = async (call) => {
|
const viewTranscript = async (call) => {
|
||||||
console.log('查看原文:', call)
|
// 触发SOP分析
|
||||||
|
emit('analyze-sop', {
|
||||||
|
type: 'call',
|
||||||
|
data: call,
|
||||||
|
content: call.record_context || ''
|
||||||
|
})
|
||||||
|
|
||||||
// 检查是否有录音文件地址
|
// 显示通话记录内容
|
||||||
if (call.record_file_addr_list && call.record_file_addr_list.length > 0) {
|
if (call.record_context) {
|
||||||
const audioFileUrl = call.record_file_addr_list[0]
|
alert(call.record_context)
|
||||||
|
|
||||||
try {
|
|
||||||
// 创建FormData对象
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('audio_file', audioFileUrl)
|
|
||||||
|
|
||||||
// 发送POST请求到ASR API
|
|
||||||
const response = await fetch('http://192.168.3.104:8000/api/asr/sync?priority=10', {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const result = await response.json()
|
|
||||||
console.log('ASR转录结果:', result)
|
|
||||||
|
|
||||||
// 显示转录结果
|
|
||||||
if (result.text || result.transcript) {
|
|
||||||
const transcriptText = result.text || result.transcript
|
|
||||||
alert(`通话原文:\n\n${transcriptText}`)
|
|
||||||
} else {
|
|
||||||
alert('转录完成,但未获取到文字内容')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.error('ASR请求失败:', response.status, response.statusText)
|
|
||||||
alert('获取通话原文失败,请稍后重试')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('ASR请求错误:', error)
|
|
||||||
alert('网络错误,无法获取通话原文')
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
alert('该通话记录暂无录音文件')
|
alert('该通话记录暂无原文内容')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -106,6 +106,10 @@
|
|||||||
<div class="detail-item" v-if="lessonData.playback_maximum_length_time">
|
<div class="detail-item" v-if="lessonData.playback_maximum_length_time">
|
||||||
<span class="detail-label">回放时长:</span>
|
<span class="detail-label">回放时长:</span>
|
||||||
<span class="detail-value">{{ Math.round((lessonData.playback_maximum_length_time || 0) / 60) }}分钟</span>
|
<span class="detail-value">{{ Math.round((lessonData.playback_maximum_length_time || 0) / 60) }}分钟</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item" v-if="lessonData.speak_message">
|
||||||
|
<span class="detail-label">直播发言:</span>
|
||||||
|
<span class="detail-value clickable" @click="showSpeakMessages(lessonData.speak_message)">{{ lessonData.speak_message.length || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -297,6 +301,22 @@ const getHealthIndicator = (score) => {
|
|||||||
return { class: 'health-risk', text: '高风险', textColor: 'text-red' };
|
return { class: 'health-risk', text: '高风险', textColor: 'text-red' };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 显示发言内容弹框
|
||||||
|
const showSpeakMessages = (speakMessages) => {
|
||||||
|
if (!speakMessages || speakMessages.length === 0) {
|
||||||
|
alert('暂无发言内容');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化发言内容
|
||||||
|
let content = '直播发言内容:\n\n';
|
||||||
|
speakMessages.forEach((message, index) => {
|
||||||
|
content += `${index + 1}. ${message}\n\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
alert(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const getAttendedLessons = (classSituation, classNum) => {
|
const getAttendedLessons = (classSituation, classNum) => {
|
||||||
// 优先使用 class_num 字段
|
// 优先使用 class_num 字段
|
||||||
@@ -998,5 +1018,18 @@ $indigo: #4f46e5;
|
|||||||
.health-ok { border-color: $warning; }
|
.health-ok { border-color: $warning; }
|
||||||
.health-risk { border-color: $danger; }
|
.health-risk { border-color: $danger; }
|
||||||
|
|
||||||
|
// Clickable styles
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #1976d2;
|
||||||
|
text-decoration: underline;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1565c0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user