Skip to content

Commit 8895f83

Browse files
authored
Merge pull request #201 from sj-distributor/external-system-use-ai-speech-assistant
Support external system use ai speech assistant
2 parents cdbe06b + 56696fd commit 8895f83

File tree

12 files changed

+77
-10
lines changed

12 files changed

+77
-10
lines changed

src/SmartTalk.Api/appsettings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@
7878
},
7979
"Smarties": {
8080
"BaseUrl": "",
81-
"ApiKey": ""
81+
"ApiKey": "",
82+
"AiSpeechAssistantCallBackUrl": ""
8283
},
8384
"TranscriptionCallback": {
8485
"AuthHeaders": "",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
alter table `ai_speech_assistant` add column `custom_record_analyze_prompt` text null;
2+
alter table `agent` add column `source_system` int not null default 0;

src/SmartTalk.Core/Domain/AISpeechAssistant/AiSpeechAssistant.cs

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public class AiSpeechAssistant : IEntity, IHasCreatedFields
3333
[Column("greetings"), StringLength(1024)]
3434
public string Greetings { get; set; }
3535

36+
[Column("custom_record_analyze_prompt")]
37+
public string CustomRecordAnalyzePrompt { get; set; }
38+
3639
[Column("created_date")]
3740
public DateTimeOffset CreatedDate { get; set; }
3841
}

src/SmartTalk.Core/Domain/System/Agent.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using SmartTalk.Messages.Dto.Agent;
22
using System.ComponentModel.DataAnnotations;
33
using System.ComponentModel.DataAnnotations.Schema;
4+
using SmartTalk.Messages.Enums.Agent;
45

56
namespace SmartTalk.Core.Domain.System;
67

@@ -21,6 +22,9 @@ public class Agent : IEntity
2122
[Column("type")]
2223
public AgentType Type { get; set; }
2324

25+
[Column("source_system")]
26+
public AgentSourceSystem SourceSystem { get; set; }
27+
2428
[Column("created_date")]
2529
public DateTimeOffset CreatedDate { get; set; }
2630
}

src/SmartTalk.Core/Services/AiSpeechAssistant/AiSpeechAssistantService.cs

+14-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using OpenAI.Chat;
1616
using SmartTalk.Core.Services.Agents;
1717
using SmartTalk.Core.Services.Http;
18+
using SmartTalk.Core.Services.Http.Clients;
1819
using SmartTalk.Messages.Constants;
1920
using SmartTalk.Core.Services.Jobs;
2021
using SmartTalk.Core.Services.PhoneOrder;
@@ -30,6 +31,7 @@
3031
using SmartTalk.Messages.Commands.AiSpeechAssistant;
3132
using SmartTalk.Messages.Commands.PhoneOrder;
3233
using SmartTalk.Messages.Dto.Agent;
34+
using SmartTalk.Messages.Enums.Agent;
3335
using SmartTalk.Messages.Enums.PhoneOrder;
3436
using JsonSerializer = System.Text.Json.JsonSerializer;
3537
using RecordingResource = Twilio.Rest.Api.V2010.Account.Call.RecordingResource;
@@ -56,8 +58,8 @@ public class AiSpeechAssistantService : IAiSpeechAssistantService
5658
private readonly IMapper _mapper;
5759
private readonly OpenAiSettings _openAiSettings;
5860
private readonly TwilioSettings _twilioSettings;
61+
private readonly ISmartiesClient _smartiesClient;
5962
private readonly ZhiPuAiSettings _zhiPuAiSettings;
60-
private readonly IAgentDataProvider _agentDataProvider;
6163
private readonly IPhoneOrderService _phoneOrderService;
6264
private readonly ISmartTalkHttpClientFactory _httpClientFactory;
6365
private readonly IPhoneOrderDataProvider _phoneOrderDataProvider;
@@ -68,8 +70,8 @@ public AiSpeechAssistantService(
6870
IMapper mapper,
6971
OpenAiSettings openAiSettings,
7072
TwilioSettings twilioSettings,
73+
ISmartiesClient smartiesClient,
7174
ZhiPuAiSettings zhiPuAiSettings,
72-
IAgentDataProvider agentDataProvider,
7375
IPhoneOrderService phoneOrderService,
7476
ISmartTalkHttpClientFactory httpClientFactory,
7577
IPhoneOrderDataProvider phoneOrderDataProvider,
@@ -79,9 +81,9 @@ public AiSpeechAssistantService(
7981
_mapper = mapper;
8082
_openAiSettings = openAiSettings;
8183
_twilioSettings = twilioSettings;
84+
_smartiesClient = smartiesClient;
8285
_zhiPuAiSettings = zhiPuAiSettings;
8386
_phoneOrderService = phoneOrderService;
84-
_agentDataProvider = agentDataProvider;
8587
_httpClientFactory = httpClientFactory;
8688
_backgroundJobClient = backgroundJobClient;
8789
_phoneOrderDataProvider = phoneOrderDataProvider;
@@ -153,21 +155,21 @@ public async Task ReceivePhoneRecordingStatusCallbackAsync(ReceivePhoneRecording
153155
{
154156
Log.Information("Handling receive phone record: {@command}", command);
155157

156-
var record = await _phoneOrderDataProvider.GetPhoneOrderRecordBySessionIdAsync(command.CallSid, cancellationToken).ConfigureAwait(false);
157-
158+
var (record, agent, aiSpeechAssistant) = await _phoneOrderDataProvider.GetRecordWithAgentAndAssistantAsync(command.CallSid, cancellationToken).ConfigureAwait(false);
159+
158160
Log.Information("Get phone order record: {@record}", record);
159161

160162
record.Url = command.RecordingUrl;
161163
record.Status = PhoneOrderRecordStatus.Sent;
162-
163-
var agent = await _agentDataProvider.GetAgentByIdAsync(record.AgentId, cancellationToken: cancellationToken).ConfigureAwait(false);
164-
164+
165165
ChatClient client = new("gpt-4o-audio-preview", _openAiSettings.ApiKey);
166166
var audioFileRawBytes = await _httpClientFactory.GetAsync<byte[]>(record.Url, cancellationToken).ConfigureAwait(false);
167167
var audioData = BinaryData.FromBytes(audioFileRawBytes);
168168
List<ChatMessage> messages =
169169
[
170-
new SystemChatMessage("你是一名電話錄音的分析員,通過聽取錄音內容和語氣情緒作出精確分析,冩出一份分析報告。\n\n分析報告的格式:交談主題:xxx\n\n 內容摘要:xxx \n\n 客人情感與情緒: xxx \n\n 待辦事件: \n1.xxx\n2.xxx \n\n 客人下單內容(如果沒有則忽略):1. 牛肉(1箱)\n2.雞腿肉(1箱)"),
170+
new SystemChatMessage(string.IsNullOrEmpty(aiSpeechAssistant?.CustomRecordAnalyzePrompt)
171+
? "你是一名電話錄音的分析員,通過聽取錄音內容和語氣情緒作出精確分析,冩出一份分析報告。\n\n分析報告的格式:交談主題:xxx\n\n 內容摘要:xxx \n\n 客人情感與情緒: xxx \n\n 待辦事件: \n1.xxx\n2.xxx \n\n 客人下單內容(如果沒有則忽略):1. 牛肉(1箱)\n2.雞腿肉(1箱)"
172+
: aiSpeechAssistant.CustomRecordAnalyzePrompt),
171173
new UserChatMessage(ChatMessageContentPart.CreateInputAudioPart(audioData, ChatInputAudioFormat.Wav)),
172174
new UserChatMessage("幫我根據錄音生成分析報告:")
173175
];
@@ -178,6 +180,9 @@ public async Task ReceivePhoneRecordingStatusCallbackAsync(ReceivePhoneRecording
178180
Log.Information("sales record analyze report:" + completion.Content.FirstOrDefault()?.Text);
179181
record.TranscriptionText = completion.Content.FirstOrDefault()?.Text;
180182

183+
if (agent.SourceSystem == AgentSourceSystem.Smarties)
184+
await _smartiesClient.CallBackSmartiesAiSpeechAssistantRecordAsync(new AiSpeechAssistantCallBackRequestDto { CallSid = command.CallSid, RecordUrl = record.Url, RecordAnalyzeReport = record.TranscriptionText }, cancellationToken).ConfigureAwait(false);
185+
181186
if (!string.IsNullOrEmpty(agent.WechatRobotKey))
182187
await _phoneOrderService.SendWorkWeChatRobotNotifyAsync(audioFileRawBytes, agent.WechatRobotKey, "錄音分析報告:\n" + record.TranscriptionText, cancellationToken).ConfigureAwait(false);
183188

src/SmartTalk.Core/Services/Http/Clients/SmartiesClient.cs

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using SmartTalk.Core.Ioc;
33
using Smarties.Messages.Requests.Ask;
44
using SmartTalk.Core.Settings.Smarties;
5+
using SmartTalk.Messages.Dto.AiSpeechAssistant;
56
using SmartTalk.Messages.Dto.Smarties;
67

78
namespace SmartTalk.Core.Services.Http.Clients;
@@ -11,6 +12,8 @@ public interface ISmartiesClient : IScopedDependency
1112
Task<AskGptResponse> PerformQueryAsync(AskGptRequest request, CancellationToken cancellationToken);
1213

1314
Task<AskGptEmbeddingResponseDto> GetEmbeddingAsync(AskGptEmbeddingRequestDto request, CancellationToken cancellationToken);
15+
16+
Task CallBackSmartiesAiSpeechAssistantRecordAsync(AiSpeechAssistantCallBackRequestDto request, CancellationToken cancellationToken);
1417
}
1518

1619
public class SmartiesClient : ISmartiesClient
@@ -46,4 +49,9 @@ public async Task<AskGptEmbeddingResponseDto> GetEmbeddingAsync(AskGptEmbeddingR
4649

4750
return response;
4851
}
52+
53+
public async Task CallBackSmartiesAiSpeechAssistantRecordAsync(AiSpeechAssistantCallBackRequestDto request, CancellationToken cancellationToken)
54+
{
55+
await _httpClientFactory.PostAsJsonAsync(_smartiesSettings.AiSpeechAssistantCallBackUrl, request, cancellationToken, headers: _headers).ConfigureAwait(false);
56+
}
4957
}

src/SmartTalk.Core/Services/PhoneOrder/PhoneOrderDataProvider.Record.cs

+17
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ Task<List<GetPhoneOrderRecordsWithUserCountDto>> GetPhoneOrderRecordsWithUserCou
3333
Task<PhoneOrderRecord> GetPhoneOrderRecordByIdAsync(int recordId, CancellationToken cancellationToken);
3434

3535
Task<PhoneOrderRecord> GetPhoneOrderRecordBySessionIdAsync(string sessionId, CancellationToken cancellationToken);
36+
37+
Task<(PhoneOrderRecord, Agent, Domain.AISpeechAssistant.AiSpeechAssistant)> GetRecordWithAgentAndAssistantAsync(string sessionId, CancellationToken cancellationToken);
3638
}
3739

3840
public partial class PhoneOrderDataProvider
@@ -177,4 +179,19 @@ public async Task<PhoneOrderRecord> GetPhoneOrderRecordBySessionIdAsync(string s
177179
{
178180
return await _repository.Query<PhoneOrderRecord>().Where(x => x.SessionId == sessionId).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
179181
}
182+
183+
public async Task<(PhoneOrderRecord, Agent, Domain.AISpeechAssistant.AiSpeechAssistant)> GetRecordWithAgentAndAssistantAsync(string sessionId, CancellationToken cancellationToken)
184+
{
185+
var result = await (
186+
from record in _repository.Query<PhoneOrderRecord>()
187+
where record.SessionId == sessionId
188+
join agent in _repository.Query<Agent>() on record.AgentId equals agent.Id into agentGroup
189+
from agent in agentGroup.DefaultIfEmpty()
190+
join assistant in _repository.Query<Domain.AISpeechAssistant.AiSpeechAssistant>() on record.AgentId equals assistant.AgentId into assistantGroup
191+
from assistant in assistantGroup.DefaultIfEmpty()
192+
select new { record, agent, assistant }
193+
).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
194+
195+
return (result?.record, result?.agent, result?.assistant);
196+
}
180197
}

src/SmartTalk.Core/Settings/Smarties/SmartiesSetting.cs

+4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ public SmartiesSetting(IConfiguration configuration)
99
BaseUrl = configuration.GetValue<string>("Smarties:BaseUrl");
1010

1111
ApiKey = configuration.GetValue<string>("Smarties:ApiKey");
12+
13+
AiSpeechAssistantCallBackUrl = configuration.GetValue<string>("Smarties:AiSpeechAssistantCallBackUrl");
1214
}
1315

1416
public string BaseUrl { get; set; }
1517

1618
public string ApiKey { get; set; }
19+
20+
public string AiSpeechAssistantCallBackUrl { get; set; }
1721
}

src/SmartTalk.Messages/Dto/Agent/AgentDto.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using SmartTalk.Messages.Enums.Agent;
2+
13
namespace SmartTalk.Messages.Dto.Agent;
24

35
public class AgentDto
@@ -10,5 +12,7 @@ public class AgentDto
1012

1113
public AgentType Type { get; set; }
1214

15+
public AgentSourceSystem SourceSystem { get; set; }
16+
1317
public DateTimeOffset CreatedDate { get; set; }
1418
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace SmartTalk.Messages.Dto.AiSpeechAssistant;
2+
3+
public class AiSpeechAssistantCallBackRequestDto
4+
{
5+
public string CallSid { get; set; }
6+
7+
public string RecordUrl { get; set; }
8+
9+
public string RecordAnalyzeReport { get; set; }
10+
}

src/SmartTalk.Messages/Dto/AiSpeechAssistant/AiSpeechAssistantDto.cs

+2
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ public class AiSpeechAssistantDto
2020

2121
public string Greetings { get; set; }
2222

23+
public string CustomRecordAnalyzePrompt { get; set; }
24+
2325
public DateTimeOffset CreatedDate { get; set; }
2426
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace SmartTalk.Messages.Enums.Agent;
2+
3+
public enum AgentSourceSystem
4+
{
5+
Self,
6+
Smarties
7+
}

0 commit comments

Comments
 (0)