中文 | إنجليزي
خط أنابيب لإنشاء دردشة عبر الإنترنت وغير متصل في الوحدة.

مع إصدار Unity.Sentis ، يمكننا استخدام بعض نماذج الشبكات العصبية في وقت التشغيل ، بما في ذلك نموذج تضمين النص لمعالجة اللغة الطبيعية.
على الرغم من أن الدردشة مع الذكاء الاصطناعي ليست شيئًا جديدًا ، في الألعاب ، فإن كيفية تصميم محادثة لا تنحرف عن أفكار المطور ، ولكنها أكثر مرونة هي نقطة صعبة.
يعتمد UniChat على تقنية التضمين Unity.Sentis و Text Text ، والتي تتيح الوضع غير المتصل بالبحث في محتوى النص استنادًا إلى قواعد بيانات المتجهات.
بالطبع ، إذا كنت تستخدم الوضع عبر الإنترنت ، فإن UniChat يتضمن أيضًا مجموعة أدوات سلسلة تعتمد على Langchain لتضمين LLM و Agent بسرعة في اللعبة.
فيما يلي مخطط تدفق Unichat. في مربع Local Inference هي الوظائف التي يمكن استخدامها في وضع عدم الاتصال:

manifest.json : {
"dependencies" : {
"com.cysharp.unitask" : " https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask " ,
"com.huggingface.sharp-transformers" : " https://github.com/huggingface/sharp-transformers.git " ,
"com.unity.addressables" : " 1.21.20 " ,
"com.unity.burst" : " 1.8.13 " ,
"com.unity.collections" : " 2.2.1 " ,
"com.unity.nuget.newtonsoft-json" : " 3.2.1 " ,
"com.unity.sentis" : " 1.3.0-pre.3 " ,
"com.whisper.unity" : " https://github.com/Macoron/whisper.unity.git?path=Packages/com.whisper.unity "
}
}Unity Package Manager باستخدام GIT URL https://github.com/AkiKurisu/UniChat.git public void CreatePipelineCtrl ( )
{
//1. New chat model file (embedding database + text table + config)
ChatPipelineCtrl PipelineCtrl = new ( new ChatModelFile ( ) { fileName = $ "ChatModel_ { Guid . NewGuid ( ) . ToString ( ) [ 0 .. 6 ] } " } ) ;
//2. Load from filePath
PipelineCtrl = new ( JsonConvert . DeserializeObject < ChatModelFile > ( File . ReadAllText ( filePath ) ) )
} public bool RunPipeline ( )
{
string input = "Hello!" ;
var context = await PipelineCtrl . RunPipeline ( "Hello!" ) ;
if ( ( context . flag & ( 1 << 1 ) ) != 0 )
{
//Get pipeline output
string output = context . CastStringValue ( ) ;
//Update history
PipelineCtrl . History . AppendUserMessage ( input ) ;
PipelineCtrl . History . AppendBotMessage ( output ) ;
return true ;
}
} pubic void Save ( )
{
//PC save to {ApplicationPath}//UserData//{ModelName}
//Android save to {Application.persistentDataPath}//UserData//{ModelName}
PipelineCtrl . SaveModel ( ) ;
} يتم استخدام نموذج التضمين BAAI/bge-small-zh-v1.5 افتراضيًا ويحتل أقل ذاكرة الفيديو. يمكن تنزيله في الإصدار ، ولكن يدعم الصينية فقط. يمكنك تنزيل نفس النموذج من HuggingFaceHub وتحويله إلى تنسيق ONNX.
وضع التحميل هو UserDataProvider اختياري ، و StreamingAssetsProvider و ResourcesProvider ، إذا تم تثبيته Unity.Addressables ، اختياري AddressableProvider .
مسار ملف UserDataProvider هو كما يلي:

يضع ResourcesProvider الملفات في مجلد النماذج في مجلد الموارد.
StreamingAssetsProvider بتوضع الملفات في مجلد النماذج في مجلد TreamingAssets.
العنوان AddressablesProvider من IS كما يلي:

يعتمد UniChat على Langchain C# باستخدام بنية سلسلة لتوصيل المكونات في السلسلة.
يمكنك رؤية عينة في مثال Repo.
الاستخدام البسيط هو على النحو التالي:
public class LLM_Chain_Example : MonoBehaviour
{
public LLMSettingsAsset settingsAsset ;
public AudioSource audioSource ;
public async void Start ( )
{
var chatPrompt = @"
You are an AI assistant that greets the world.
User: Hello!
Assistant:" ;
var llm = LLMFactory . Create ( LLMType . ChatGPT , settingsAsset ) ;
//Create chain
var chain =
Chain . Set ( chatPrompt , outputKey : "prompt" )
| Chain . LLM ( llm , inputKey : "prompt" , outputKey : "chatResponse" ) ;
//Run chain
string result = await chain . Run < string > ( "chatResponse" ) ;
Debug . Log ( result ) ;
}
} يستخدم المثال أعلاه Chain للاتصال LLM مباشرة ، ولكن لتبسيط البحث في قاعدة البيانات وتسهيل الهندسة ، يوصى باستخدام ChatPipelineCtrl كبداية للسلسلة.
إذا قمت بتشغيل المثال التالي ، في المرة الأولى التي تتصل فيها LLM والمرة الثانية التي ترد عليها مباشرة من قاعدة البيانات.
public async void Start ( )
{
//Create new chat model file with empty memory and embedding db
var chatModelFile = new ChatModelFile ( ) { fileName = "NewChatFile" , modelProvider = ModelProvider . AddressableProvider } ;
//Create an pipeline ctrl to run it
var pipelineCtrl = new ChatPipelineCtrl ( chatModelFile , settingsAsset ) ;
pipelineCtrl . SwitchGenerator ( ChatGeneratorIds . ChatGPT ) ;
//Init pipeline, set verbose to log status
await pipelineCtrl . InitializePipeline ( new PipelineConfig { verbose = true } ) ;
//Add system prompt
pipelineCtrl . Memory . Context = "You are my personal assistant, you should answer my questions." ;
//Create chain
var chain = pipelineCtrl . ToChain ( ) . Input ( "Hello assistant!" ) . CastStringValue ( outputKey : "text" ) ;
//Run chain
string result = await chain . Run < string > ( "text" ) ;
//Save chat model
pipelineCtrl . SaveModel ( ) ;
} يمكنك تتبع السلسلة باستخدام طريقة Trace() ، أو إضافة رمز البرمجة النصية UNICHAT_ALWAYS_TRACE_CHAIN في إعدادات المشروع.
| اسم الطريقة | نوع العودة | وصف |
|---|---|---|
Trace(stackTrace, applyToContext) | void | سلسلة تتبع |
stackTrace: bool | يتيح تتبع المكدس | |
applyToContext: bool | ينطبق على جميع العناصر الفرعية |

إذا كان لديك حل توليف الكلام ، فيمكنك الرجوع إلى VitsClient بتنفيذ مكون TTS؟.
يمكنك استخدام AudioCache لتخزين الكلام بحيث يمكن تشغيله عند التقاط إجابة من قاعدة البيانات في الوضع غير المتصل بالإنترنت.
public class LLM_TTS_Chain_Example : MonoBehaviour
{
public LLMSettingsAsset settingsAsset ;
public AudioSource audioSource ;
public async void Start ( )
{
//Create new chat model file with empty memory and embedding db
var chatModelFile = new ChatModelFile ( ) { fileName = "NewChatFile" , modelProvider = ModelProvider . AddressableProvider } ;
//Create an pipeline ctrl to run it
var pipelineCtrl = new ChatPipelineCtrl ( chatModelFile , settingsAsset ) ;
pipelineCtrl . SwitchGenerator ( ChatGeneratorIds . ChatGPT , true ) ;
//Init pipeline, set verbose to log status
await pipelineCtrl . InitializePipeline ( new PipelineConfig { verbose = true } ) ;
var vits = new VITSModel ( lang : "ja" ) ;
//Add system prompt
pipelineCtrl . Memory . Context = "You are my personal assistant, you should answer my questions." ;
//Create cache to cache audioClips and translated texts
var audioCache = AudioCache . CreateCache ( chatModelFile . DirectoryPath ) ;
var textCache = TextMemoryCache . CreateCache ( chatModelFile . DirectoryPath ) ;
//Create chain
var chain = pipelineCtrl . ToChain ( ) . Input ( "Hello assistant!" ) . CastStringValue ( outputKey : "text" )
//Translate to japanese
| Chain . Translate ( new GoogleTranslator ( "en" , "ja" ) ) . UseCache ( textCache )
//Split them
| Chain . Split ( new RegexSplitter ( @"(?<=[。!?! ?])" ) , inputKey : "translated_text" )
//Auto batched
| Chain . TTS ( vits , inputKey : "splitted_text" ) . UseCache ( audioCache ) . Verbose ( true ) ;
//Run chain
( IReadOnlyList < string > segments , IReadOnlyList < AudioClip > audioClips )
= await chain . Run < IReadOnlyList < string > , IReadOnlyList < AudioClip > > ( "splitted_text" , "audio" ) ;
//Play audios
for ( int i = 0 ; i < audioClips . Count ; ++ i )
{
Debug . Log ( segments [ i ] ) ;
audioSource . clip = audioClips [ i ] ;
audioSource . Play ( ) ;
await UniTask . WaitUntil ( ( ) => ! audioSource . isPlaying ) ;
}
}
}يمكنك استخدام خدمة الكلام إلى النص مثل Whisper.unity للاستدلال المحلي؟.
public void RunSTTChain ( AudioClip audioClip )
{
WhisperModel whisperModel = await WhisperModel . FromPath ( modelPath ) ;
var chain = Chain . Set ( audioClip , "audio" )
| Chain . STT ( whisperModel , new WhisperSettings ( ) {
language = "en" ,
initialPrompt = "The following is a paragraph in English."
} ) ;
Debug . Log ( await chain . Run ( "text" ) ) ;
}يمكنك تقليل الاعتماد على LLM عن طريق تدريب مصنف المصب على أساس النموذج المدمج لإكمال بعض مهام الاعتراف في اللعبة (مثل مصنف التعبير؟).
يلاحظ
1. تحتاج إلى جعل المكون في بيئة بيثون.
2. حاليًا ، لا يزال سينس يتطلب منك التصدير يدويًا إلى تنسيق ONNX
أفضل الممارسات: استخدم نموذجًا مضمنًا لإنشاء سمات من بيانات التدريب الخاصة بك قبل التدريب. يجب تصدير نموذج المصب فقط بعد ذلك.
فيما يلي shape=(512,768,20) من مصنف Perceptron متعدد الطبقات مع حجم تصدير فقط 1.5 ميجابايت:
class SubClassifier ( nn . Module ):
#input_dim is the output dim of your embedding model
def __init__ ( self , input_dim , hidden_dim , output_dim ):
super ( CustomClassifier , self ). __init__ ()
self . fc1 = nn . Linear ( input_dim , hidden_dim )
self . relu = nn . ReLU ()
self . dropout = nn . Dropout ( p = 0.1 )
self . fc2 = nn . Linear ( hidden_dim , output_dim )
def forward ( self , x ):
x = self . fc1 ( x )
x = self . relu ( x )
x = self . dropout ( x )
x = self . fc2 ( x )
return x مكونات اللعبة هي أدوات مختلفة يتم دمجها مع وظيفة الحوار وفقًا لآلية اللعبة المحددة.
statemachine الذي يغير الولايات وفقًا لمحتوى الدردشة. تعشش Statemachine (Substatemachine) غير مدعوم حاليًا. اعتمادًا على المحادثة ، يمكنك القفز إلى حالات مختلفة وتنفيذ مجموعة السلوكيات المقابلة ، على غرار آلة الحالة المتحركة الخاصة بـ Unity.
public void BuildStateMachine ( )
{
chatStateMachine = new ChatStateMachine ( dim : 512 ) ;
chatStateMachineCtrl = new ChatStateMachineCtrl (
TextEncoder : encoder ,
//Input a host Unity.Object
hostObject : gameObject ,
layer : 1
) ;
chatStateMachine . AddState ( "Stand" ) ;
chatStateMachine . AddState ( "Sit" ) ;
chatStateMachine . states [ 0 ] . AddBehavior < StandBehavior > ( ) ;
chatStateMachine . states [ 0 ] . AddTransition ( new LazyStateReference ( "Sit" ) ) ;
// Add a conversion directive and set scoring thresholds and conditions
chatStateMachine . states [ 0 ] . transitions [ 0 ] . AddCondition ( ChatConditionMode . Greater , 0.6f , "I sit down" ) ;
chatStateMachine . states [ 0 ] . transitions [ 0 ] . AddCondition ( ChatConditionMode . Greater , 0.6f , "I want to have a rest on chair" ) ;
chatStateMachine . states [ 1 ] . AddBehavior < SitBehavior > ( ) ;
chatStateMachine . states [ 1 ] . AddTransition ( new LazyStateReference ( "Stand" ) ) ;
chatStateMachine . states [ 1 ] . transitions [ 0 ] . AddCondition ( ChatConditionMode . Greater , 0.6f , "I'm well rested" ) ;
chatStateMachineCtrl . SetStateMachine ( 0 , chatStateMachine ) ;
}
public void LoadFromBytes ( string bytesFilePath )
{
chatStateMachineCtrl . Load ( bytesFilePath ) ;
} public class CustomChatBehavior : ChatStateMachineBehavior
{
private GameObject hostGameObject ;
public override void OnStateMachineEnter ( UnityEngine . Object hostObject )
{
//Get host Unity.Object
hostGameObject = hostObject as GameObject ;
}
public override void OnStateEnter ( )
{
//Do something
}
public override void OnStateUpdate ( )
{
//Do something
}
public override void OnStateExit ( )
{
//Do something
}
} private void RunStateMachineAfterPipeline ( )
{
var chain = PipelineCtrl . ToChain ( ) . Input ( "Your question." ) . CastStringValue ( "stringValue" )
| new StateMachineChain ( chatStateMachineCtrl , "stringValue" ) ;
await chain . Run ( ) ;
}استدعاء الأدوات القائمة على سير عمل Reactagent.
هنا مثال:
var userCommand = @"I want to watch a dance video." ;
var llm = LLMFactory . Create ( LLMType . ChatGPT , settingsAsset ) as OpenAIClient ;
llm . StopWords = new ( ) { " n Observation:" , " n t Observation:" } ;
//Create agent with muti-tools
var chain =
Chain . Set ( userCommand )
| Chain . ReActAgentExecutor ( llm )
. UseTool ( new AgentLambdaTool (
"Play random dance video" ,
@"A wrapper to select random dance video and play it. Input should be 'None'." ,
( e ) =>
{
PlayRandomDanceVideo ( ) ;
//Notice agent it finished its work
return UniTask . FromResult ( "Dance video 'Queencard' is playing now." ) ;
} ) )
. UseTool ( new AgentLambdaTool (
"Sleep" ,
@"A wrapper to sleep." ,
( e ) =>
{
return UniTask . FromResult ( "You are now sleeping." ) ;
} ) )
. Verbose ( true ) ;
//Run chain
Debug . Log ( await chain . Run ( "text" ) ) ; إليك بعض التطبيقات التي قمت بها. نظرًا لأنها تشمل بعض الإضافات التجارية ، تتوفر إصدارات البناء فقط.
انظر صفحة الإصدار
بناءً على Unichat لتقديم تطبيق مماثل في الوحدة
إصدار المستودع المتزامن هو
V0.0.1-alpha، وينتظر العرض التوضيحي.

انظر صفحة الإصدار

أنه يحتوي على مكونات سلوكية وصوتية وليست متوفرة بعد.
يستخدم Demo TavernAI بنية بيانات الأحرف ، ويمكننا كتابة شخصية الشخصية ، ومحادثات العينة ، وسيناريوهات الدردشة في الصور.

إذا كنت تستخدم بطاقة حرف TavernAI ، فسيتم كتابة كلمة جديلة أعلاه.
https://www.akikurisu.com/blog/posts/create-chatbox-in-unity-2024-03-19/
https://www.akikurisu.com/blog/posts/use-nlp-in-unity-2024-04-03/