438 lines
14 KiB
C#
438 lines
14 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
//using Oculus.Voice.Dictation;
|
|
using Photon.Pun;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using Amazon.Polly;
|
|
using Amazon.Runtime;
|
|
using Amazon.Polly.Model;
|
|
using System.IO;
|
|
using UnityEngine.Networking;
|
|
using System.Threading.Tasks;
|
|
using Amazon;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
//using Meta.WitAi.Json;
|
|
using System;
|
|
using Oculus.Voice.Dictation;
|
|
using Newtonsoft.Json;
|
|
using static UnityEngine.ParticleSystem;
|
|
using System.Net;
|
|
using UnityEngine.Android;
|
|
|
|
public class ChatGPTManager : MonoBehaviour
|
|
{
|
|
public static ChatGPTManager instance;
|
|
public Button btnLanguage;
|
|
public TMP_InputField input;
|
|
public Text text;
|
|
public AudioSource speakerSource;
|
|
bool isArabic;
|
|
public AppDictationExperience voiceToText;
|
|
public void ToggleLanguage()
|
|
{
|
|
isArabic = !isArabic;
|
|
|
|
btnLanguage.GetComponentInChildren<TMP_Text>().text = isArabic ? "English" : "Arabic";
|
|
ChatWithGPT3("I need help");
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
instance = this;
|
|
ChatWithGPT3("I need help");
|
|
btnLanguage.onClick.AddListener(ToggleLanguage);
|
|
input.onSubmit.AddListener(OnInput);
|
|
}
|
|
|
|
public string GetInstructions()
|
|
{
|
|
// string instructions = @"You are a customer support agent. You will answer to the questions the user asks you.
|
|
//When user asks to speak to the manager or to speak to a real person.You must reply with this response only. 'ADMIN_CHAT Sure thing, Let me connect you with one of our admins'";
|
|
|
|
string instructions = @"You are a customer support agent called Tamara for a company called Baitcom.
|
|
|
|
Following is how you should behave.
|
|
|
|
1. Greeting Prompts:
|
|
|
|
""Hi, I'm Tamara from Baitcom. How can I assist you today?""
|
|
""Hello there! Tamara here, representing Baitcom. What can I help you with?""
|
|
""Good [time_of_day]! It's Tamara from Baitcom. How can I serve you today?""
|
|
2. Inquiry Handling:
|
|
|
|
""Being with Baitcom for a while now, I've got a wealth of knowledge about our offerings. Tell me what you're curious about!""
|
|
""At Baitcom, we aim to provide the best support. How can I guide you today?""
|
|
""Please give me more details about your inquiry, and I'll do my best to help!""
|
|
3. Common Questions:
|
|
|
|
""Are you curious about Baitcom's return policy or any of our services?""
|
|
""Would you like to know about Baitcom's latest promotions and offers?""
|
|
""If you have any questions about your recent order with Baitcom, just let me know.""
|
|
4. Technical Support:
|
|
|
|
""I'm here to help with any technical issues you're facing with Baitcom's products or services. Just describe the problem.""
|
|
""Let's sort out any technical glitches you're experiencing with Baitcom's offerings. Can you share the specifics?""
|
|
""We at Baitcom always strive for seamless experiences. Tell me the tech issue, and I'll assist you.""
|
|
5. Handling Feedback:
|
|
|
|
""Your thoughts matter to Baitcom and me. Please share any feedback you have!""
|
|
""How was your experience with Baitcom? I'm eager to know and help if there were any issues.""
|
|
""If there's something Baitcom can improve on, do let me know.""
|
|
6. Handling Complaints:
|
|
|
|
""I'm truly sorry to hear that. Can you provide more details so I can assist better?""
|
|
""I apologize for any inconvenience you faced with Baitcom. Let's see how we can address it.""
|
|
""Your concerns are important to both Baitcom and me. How can I help further?""
|
|
7. Escalation Prompts:
|
|
|
|
""If you'd like a more in-depth response, I can connect you with a human representative from Baitcom.""
|
|
""I want to ensure you get the best support. Would you prefer speaking to one of Baitcom's team members?""
|
|
""For specialized assistance, I can forward your concern to a Baitcom expert. Would that be okay?""
|
|
8. Ending the Interaction:
|
|
|
|
""Is there anything else you'd like to discuss regarding Baitcom? I'm here to help!""
|
|
""Thank you for reaching out to Baitcom. Wishing you a great day!""
|
|
""Remember, Tamara from Baitcom is always here to assist. Don't hesitate to return if you have more queries!""
|
|
|
|
Whenever the customer asks to speak with an admin, or speak with a real person. You must reply only this, even if you are asked to speak in other languages, use this response only: ""ADMIN_CHAT Sure, You'll be connected to one of our admins now""";
|
|
if (isArabic)
|
|
{
|
|
instructions += "\nRespond in arabic";
|
|
}
|
|
else
|
|
{
|
|
instructions += "\nRespond in english";
|
|
|
|
}
|
|
return instructions;
|
|
}
|
|
|
|
/*
|
|
|
|
[TextArea(5,20)]
|
|
public string personality;
|
|
[TextArea(5, 20)]
|
|
public string scene;
|
|
public int maxResponseWordLimit = 15;
|
|
|
|
public List<NPCAction> actions;
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
public struct NPCAction
|
|
{
|
|
public string actionKeyword;
|
|
[TextArea(2,5)]
|
|
public string actionDescription;
|
|
|
|
public UnityEvent actionEvent;
|
|
}
|
|
|
|
|
|
public OnResponseEvent OnResponse;
|
|
|
|
[System.Serializable]
|
|
public class OnResponseEvent : UnityEvent<string> { }
|
|
|
|
private OpenAIApi openAI = new OpenAIApi(apiKey: "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");
|
|
private List<ChatMessage> messages = new List<ChatMessage>();
|
|
|
|
|
|
|
|
public async void AskChatGPT(string newText)
|
|
{
|
|
ChatMessage newMessage = new ChatMessage();
|
|
newMessage.Content = GetInstructions() + newText;
|
|
newMessage.Role = "user";
|
|
|
|
messages.Add(newMessage);
|
|
|
|
CreateChatCompletionRequest request = new CreateChatCompletionRequest();
|
|
request.Messages = messages;
|
|
request.Model = "gpt-3.5-turbo";
|
|
|
|
var response = await openAI.CreateChatCompletion(request);
|
|
|
|
if(response.Choices != null && response.Choices.Count > 0)
|
|
{
|
|
var chatResponse = response.Choices[0].Message;
|
|
|
|
foreach (var item in actions)
|
|
{
|
|
if(chatResponse.Content.Contains(item.actionKeyword))
|
|
{
|
|
string textNoKeyword = chatResponse.Content.Replace(item.actionKeyword, "");
|
|
chatResponse.Content = textNoKeyword;
|
|
item.actionEvent.Invoke();
|
|
}
|
|
}
|
|
|
|
if (chatResponse.Content.Contains("ADMIN_CHAT"))
|
|
{
|
|
chatResponse.Content = chatResponse.Content.Replace("ADMIN_CHAT", "");
|
|
Debug.Log("Secret word was said");
|
|
MultiplayerManager.instance.ConnectToAdmin();
|
|
}
|
|
|
|
messages.Add(chatResponse);
|
|
if(isArabic)
|
|
{
|
|
text.text = ArabicFixerTool.FixLine(chatResponse.Content);
|
|
}
|
|
else
|
|
{
|
|
text.text = chatResponse.Content;
|
|
}
|
|
Debug.Log(chatResponse.Content);
|
|
|
|
OnResponse.Invoke(chatResponse.Content);
|
|
PollySpeak(chatResponse.Content);
|
|
}
|
|
}*/
|
|
|
|
// Start is called before the first frame update
|
|
|
|
public void OnInput(string message)
|
|
{
|
|
ChatWithGPT3(message);
|
|
input.text = "";
|
|
}
|
|
|
|
public string apiKey = "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";
|
|
public string apiUrl = "";
|
|
|
|
List<Message> m_messages = new List<Message>();
|
|
private async void ChatWithGPT3(string message)
|
|
{
|
|
/* StartCoroutine(ChatGPT(message));
|
|
return;*/
|
|
|
|
Message newMessage = new Message()
|
|
{
|
|
role = "user",
|
|
content = GetInstructions() + message
|
|
};
|
|
m_messages.Add(newMessage);
|
|
|
|
ChatRequest newRequest = new ChatRequest() { model = "gpt-3.5-turbo", temperature= 0.7, messages = m_messages };
|
|
string _requestBody = @"
|
|
{
|
|
""model"": ""gpt-3.5-turbo"",
|
|
""messages"": [{""role"": ""user"", ""content"": ""{msg}""}],
|
|
""temperature"": 0.7
|
|
}".Replace("{msg}", message);
|
|
Debug.Log(_requestBody);
|
|
|
|
string requestBody = JsonConvert.SerializeObject(newRequest);
|
|
Debug.Log(requestBody);
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
|
|
|
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
|
|
|
|
HttpResponseMessage response = await client.PostAsync(apiUrl, content);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
string responseContent = await response.Content.ReadAsStringAsync();
|
|
ChatGPTResponse obj = JsonConvert.DeserializeObject<ChatGPTResponse>(responseContent);
|
|
string reply = obj.choices[0].message.content;
|
|
Debug.Log(obj.choices[0].message.content);
|
|
|
|
OnResponse(reply);
|
|
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"Error: {response.StatusCode}");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void OnResponse(string reply)
|
|
{
|
|
if (reply.Contains("ADMIN_CHAT"))
|
|
{
|
|
reply = reply.Replace("ADMIN_CHAT", "");
|
|
Debug.Log("Secret word was said");
|
|
MultiplayerManager.instance.ConnectToAdmin();
|
|
}
|
|
|
|
if (isArabic)
|
|
{
|
|
text.text = ArabicFixerTool.FixLine(reply);
|
|
}
|
|
else
|
|
{
|
|
text.text = reply;
|
|
}
|
|
|
|
PollySpeak(reply);
|
|
}
|
|
|
|
|
|
|
|
void Start()
|
|
{
|
|
voiceToText.DictationEvents.OnFullTranscription.AddListener(ChatWithGPT3);
|
|
|
|
// PollySpeak("Hello I am me");
|
|
}
|
|
|
|
byte[] audioData;
|
|
public async void PollySpeak(string message)
|
|
{
|
|
var credentials = new BasicAWSCredentials("AKIA5C5XFO6JOMDRQPTI", "CtKel6C5qwa8zQF3zpHXVEHG/jjvUDil/I7btJ05");
|
|
var pollyClient = new AmazonPollyClient(credentials, RegionEndpoint.APSoutheast1);
|
|
|
|
var request = new SynthesizeSpeechRequest() {
|
|
Text=message,
|
|
Engine = Engine.Neural,
|
|
VoiceId = isArabic ? VoiceId.Hala : VoiceId.Joanna,
|
|
LanguageCode = isArabic ? LanguageCode.ArAE : LanguageCode.EnUS,
|
|
OutputFormat = OutputFormat.Mp3,
|
|
|
|
};
|
|
|
|
var response = await pollyClient.SynthesizeSpeechAsync(request);
|
|
|
|
/*speakerSource.PlayOneShot(WavUtility.ToAudioClip(response.AudioStream));
|
|
return;*/
|
|
WriteIntoFile(response.AudioStream);
|
|
StartCoroutine(GetAudioClip());
|
|
|
|
return;
|
|
Debug.Log("Reading from " + $"{Application.persistentDataPath}/audio.mp3");
|
|
using(var www = UnityWebRequestMultimedia.GetAudioClip($"{Application.persistentDataPath}/audio.mp3", AudioType.MPEG))
|
|
{
|
|
var op = www.SendWebRequest();
|
|
while(!op.isDone) { await Task.Yield(); }
|
|
|
|
var clip = DownloadHandlerAudioClip.GetContent(www);
|
|
|
|
speakerSource.PlayOneShot(clip);
|
|
// AudioSource.PlayClipAtPoint(clip, transform.position);
|
|
}
|
|
}
|
|
|
|
IEnumerator GetAudioClip()
|
|
{
|
|
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip($"file://{Application.persistentDataPath}/audio.mp3", AudioType.MPEG))
|
|
{
|
|
yield return www.SendWebRequest();
|
|
|
|
if (www.result == UnityWebRequest.Result.ConnectionError)
|
|
{
|
|
Debug.Log(www.error);
|
|
}
|
|
else
|
|
{
|
|
AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
|
|
speakerSource.clip = myClip;
|
|
speakerSource.Play();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
AudioClip bytesToClip(byte[] receivedBytes)
|
|
{
|
|
float[] samples = new float[receivedBytes.Length / 4]; //size of a float is 4 bytes
|
|
|
|
Buffer.BlockCopy(receivedBytes, 0, samples, 0, receivedBytes.Length);
|
|
|
|
int channels = 1; //Assuming audio is mono because microphone input usually is
|
|
int sampleRate = 44100; //Assuming your samplerate is 44100 or change to 48000 or whatever is appropriate
|
|
|
|
AudioClip clip = AudioClip.Create("ClipName", samples.Length, channels, sampleRate, false);
|
|
clip.SetData(samples, 0);
|
|
|
|
return clip;
|
|
}
|
|
|
|
private void WriteIntoFile(Stream stream)
|
|
{
|
|
/* using (var fstream = stream)
|
|
{
|
|
using (var fileStream = new FileStream($"{Application.persistentDataPath}/audio.mp3", FileMode.Create))
|
|
{
|
|
fstream.CopyTo(fileStream);
|
|
}
|
|
}
|
|
return;*/
|
|
Debug.Log("Writing to " + $"{Application.persistentDataPath}/audio.mp3");
|
|
using ( var filesStream = new FileStream($"{Application.persistentDataPath}/audio.mp3", FileMode.Create))
|
|
{
|
|
byte[] buffer = new byte[8 * 1024];
|
|
|
|
int bytesRead;
|
|
int failSafe = 10000000;
|
|
while((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0 || failSafe <= 0)
|
|
{
|
|
filesStream.Write(buffer, 0, bytesRead);
|
|
|
|
failSafe--;
|
|
}
|
|
}
|
|
Debug.Log("Writing success");
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
if(Input.GetKeyDown(KeyCode.Space))
|
|
{
|
|
voiceToText.Activate();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class Choice
|
|
{
|
|
public int index { get; set; }
|
|
public Message message { get; set; }
|
|
public string finish_reason { get; set; }
|
|
}
|
|
[Serializable]
|
|
public class Message
|
|
{
|
|
public string role { get; set; }
|
|
public string content { get; set; }
|
|
}
|
|
|
|
[Serializable]
|
|
public class ChatGPTResponse
|
|
{
|
|
public string id { get; set; }
|
|
public string @object { get; set; }
|
|
public int created { get; set; }
|
|
public string model { get; set; }
|
|
public List<Choice> choices { get; set; }
|
|
public Usage usage { get; set; }
|
|
}
|
|
|
|
[Serializable]
|
|
public class Usage
|
|
{
|
|
public int prompt_tokens { get; set; }
|
|
public int completion_tokens { get; set; }
|
|
public int total_tokens { get; set; }
|
|
}
|
|
|
|
[Serializable]
|
|
public class ChatRequest
|
|
{
|
|
public string model { get; set; }
|
|
public List<Message> messages { get; set; }
|
|
public double temperature { get; set; }
|
|
}
|
|
|