Problem after updating VS2022 viewing the watches. After an answer with proposal to post the code, I do so to exclude the problem is caused by my code prior to reporting a bug.
The original question: Watch window at debugging: CS0103: The name '' does not exists in the current context. Version and solution specifics are stated there.
The code is merely to get something on screen.
Things I tried afterwards:
Creating a new solution, adding a windows form app and windows controll library. Created a class with values.
No problem here,
Doing the same but, also a new solution, pasted the code of StringParser into the library and the relevant code of the constructor of Form1,
Again a new solution where the StringParser is part of only a windows forms app,
Both the same problem.
The image contains a screenshot of the watch window. Also from the code file to show debugging state. (The code is as formatted text below).
All projects are 'out-of-the-box'
Library - StrangParser.cs
namespace html
{
public enum Pin
{
Start,
End,
Both,
}
public class StringParser
{
private string content = "";
public string Content { get { return content; } set { if (content != value) content = value; if (content.Length > 0) { position = start = 0; end = 0; } } }
private int position = -1;
private int start = -1;
private int end = -1;
public bool Next()
{
++position;
if (position > content.Length)
position = content.Length;
if (position > end)
end = position;
return (position >= content.Length);
}
public bool Next(char to_char, bool include = true)
{
while (position < content.Length && content[position] != to_char)
{
++position;
if (position > end)
end = position;
}
if (include) ++position;
if (position > content.Length)
position = content.Length;
if (position > end)
end = position;
return (position >= content.Length);
}
public bool Previous()
{
--position;
if (position < 0)
position = 0;
if (position < start)
start = position;
return (position ==0);
}
public string Token
{
get
{
return start >= 0 && end <= content.Length && end > start
? content.Substring(start, end - start)
: "";
}
}
public void Pin(Pin pin)
{
if (pin == html.Pin.Start || pin == html.Pin.Both)
start = position;
if (pin == html.Pin.End || pin == html.Pin.Both)
end = position;
}
public override string ToString()
{
if (content == null || content == "")
return "";
string s = content.Substring(0, start);
string t = Token;
string e = content.Substring(end, content.Length - end);
if (s.Length > 15) s = "..." + s.Substring(s.Length - 15);
if (e.Length > 15) e = e.Substring(0, 15) + "...";
return string.Format("[{0}-{1}-{2}] {3} |--> '{4}' <--| {5}", start, position, end, s, t, e);
}
}
}
Form App - Form1.cs - code
using System.Windows.Forms;
using html;
namespace contentdownloader
{
public partial class Form1 : Form
{
string filecontent = "<html><head></head><body></body></html>";
StringParser watch_parser = null;
string watch_token = null;
public Form1()
{
InitializeComponent();
StringParser parser = new StringParser();
watch_parser = parser;
parser.Content = filecontent;
string token = "";
while (!parser.Next('<'))
{
//parser.Pin(html.Pin.Both);
parser.Next('>');
token = watch_token = parser.Token;
parser.Pin(html.Pin.Both);
}
}
}
}
You can change your code like this, define parser and token before the function InitializeComponent() of Form1:
public partial class Form1 : Form
{
string filecontent = "<html><head></head><body></body></html>";
StringParser parser = new StringParser();
string token = "";
public Form1()
{
InitializeComponent();
parser.Content = filecontent;
while (!parser.Next('<'))
{
parser.Next('>');
token = parser.Token;
}
}
}
Here is my test result:
Related
No matter what I do, I can NOT set the cursor to position 1 in this string (___) ___-____ position 1 is the position immediately following the opening (. I'm doing this in the EditingStarted method of the delegate, As a guide, I'm following the code here. currently my code is:
public override void EditingStarted(UITextField textField)
{
if (MyParent.EditMask != "")
{
textField.Text = MyParent.EditMask.Replace("#", "_");
// Set cursor position
NSRange therange = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Length - 1);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
}
The cursor ALWAYS appears immediately following the closing ), nothing I do changes that. I have no idea why. I've tried getting the position of the first underscore:
int position = textField.Text.IndexOf("_");
NSRange therange = new NSRange(position, 0);
But again, that results in the cursor being positioned immediately after the closing ). Anyone see what I'm doing wrong?
**** Update ****
Just so folks understand the context, The code above is part of a class called UIMaskedTextFieldthat I created to handle all of my mask/text input formating in the user interface. That class is:
class UIMaskedTextField : UITextField
{
public string EditMask { get; set; }
public UIMaskedTextField()
{
this.Delegate = new MaskTextViewDelegate(this);
}
}
class MaskTextViewDelegate : UITextFieldDelegate
{
private UIMaskedTextField MyParent;
int index = 0;
public MaskTextViewDelegate(UIMaskedTextField parent)
{
MyParent = parent;
}
public override void EditingStarted(UITextField textField)
{
if (MyParent.EditMask != "")
{
textField.Text = MyParent.EditMask.Replace("#", "_");
// Set cursor position
int position = textField.Text.IndexOf("_");
NSRange therange = new NSRange(position, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
}
public override bool ShouldChangeCharacters(UITextField textField, NSRange range, string replacementString)
{
int fieldlength = 10; // MyParent.EditMask.Length;
string text = textField.Text;
int NeedASpace = MyParent.EditMask.IndexOf(" ");
string newText = "";
if (text == "")
{
newText = MyParent.EditMask.Replace("#", "_");
} else
{
newText = text;
}
string totalChar = newText.Replace(" ", "");
totalChar = totalChar.Replace("(", "");
totalChar = totalChar.Replace(")", "");
totalChar = totalChar.Replace("-", "");
totalChar = totalChar.Replace("_", "");
int val;
if ((totalChar + replacementString).Length <= fieldlength) {
if (replacementString != "")
{
index = newText.IndexOf("_");
StringBuilder sb = new StringBuilder(newText);
char character = char.Parse(replacementString);
sb[index] = character;
newText = sb.ToString();
textField.Text = newText;
// Set cursor to next position, this works flawlessly
NSRange therange = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location + 1);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
newText = "";
}
else
{ // Still working the backspace key, so not done here yet.
if (text.Length > 1)
{
newText = text.Substring(0, text.Length - 1);
}
else
{
newText = "";
}
}
}
return Int32.TryParse(newText, out val);
}
}
To position cursor in UITextField in position 1:
public partial class ViewController : UIViewController
{
public ViewController (IntPtr handle) : base (handle)
{
}
UITextField textfield1 { get; set; }
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
var frame = new CGRect(10, 10, 300, 40);
textfield1 = new UITextField(frame);
textfield1.Text = "(___) ___-____";
textfield1.Delegate = new myDelegate();
View.Add(textfield1);
textfield1.BecomeFirstResponder();
}
}
public class myDelegate : UITextFieldDelegate {
public override void EditingStarted(UITextField textField)
{
var arbitraryValue = 1;
var newPosition = textField.GetPosition(textField.BeginningOfDocument, arbitraryValue);
textField.SelectedTextRange = textField.GetTextRange(newPosition, newPosition);
}
}
Update:
public override void DidChangeSelection(UITextField textField)
{
var arbitraryValue = 1;
var newPosition = textField.GetPosition(textField.BeginningOfDocument, arbitraryValue);
textField.SelectedTextRange = textField.GetTextRange(newPosition, newPosition);
}
Ok, finally got it to work. #Jack Hua's solution won't work for me because I cannot set the textfield as the FirstResponder because there are a number of UIMaskedTextField's on the scrollview, the masked text fields are not the first sub-views on the scrollview, BUT it did give me some ideas! I was beginning to suspect that the initialization of the textfield when the text property was being set was somehow screwing up the cursor position, I believe that is what's happening, just can't prove it as the initialization of the view is happening behind the scenes. BUT I suspect that the setting of the view's mask via the EditMask property made the initialization happen sooner and made it possible to set the cursor position. This also sets the mask from the outset, removing any doubt from the users mind as to what the format of the field is supposed to be. Here's my "final" code:
class UIMaskedTextField : UITextField
{
private string editmask = "";
public String EditMask
{
get => editmask;
set
{
if ((value != ""))
{
editmask = value;
this.Text = editmask.Replace("#", "_"); ;
}
}
}
public UIMaskedTextField()
{
this.Delegate = new PhoneMaskTextViewDelegate(this);
}
}
class PhoneMaskTextViewDelegate : UITextFieldDelegate
{
private UIMaskedTextField MyParent;
int index = 0;
public PhoneMaskTextViewDelegate(UIMaskedTextField parent)
{
MyParent = parent;
}
public override void DidChangeSelection(UITextField textField)
{
// place the cursor in the first fill podition
int y = textField.Text.IndexOf("_");
if (y > -1)
{
var newPosition = textField.GetPosition(textField.BeginningOfDocument, y);
textField.SelectedTextRange = textField.GetTextRange(newPosition, newPosition);
}
}
public override bool ShouldChangeCharacters(UITextField textField, NSRange range, string replacementString)
{
const string maskCharacters = "()-/ ";
string newText = "";
int val;
if (replacementString != "")
{
int fieldlength = 10; // MyParent.EditMask.Length;
string text = textField.Text;
if (text == "")
{
newText = MyParent.EditMask.Replace("#", "_");
}
else
{
newText = text;
}
string totalChar = newText.Replace(" ", "");
totalChar = totalChar.Replace("(", "");
totalChar = totalChar.Replace(")", "");
totalChar = totalChar.Replace("-", "");
totalChar = totalChar.Replace("_", "");
if (Utils.IsNumeric(replacementString))
{
if ((totalChar + replacementString).Length <= fieldlength)
{
if (replacementString != "")
{
index = newText.IndexOf("_");
if (index > -1)
{
StringBuilder sb = new StringBuilder(newText);
char character = char.Parse(replacementString);
sb[index] = character;
newText = sb.ToString();
textField.Text = newText;
// Set cursor to next position
NSRange therange = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location + 1);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
newText = "";
}
}
}
} else
{ // Backspace/Delete pressed
UITextRange position = textField.SelectedTextRange;
string x = position.ToString();
int positionofcursor = Convert.ToInt32(x.Substring(x.IndexOf("(") + 1, x.IndexOf(",") - x.IndexOf("(") - 1));
string characterInPosition = "";
// make sure we're not deleting a mask character
do {
positionofcursor -= 1;
if (positionofcursor > -1)
{
characterInPosition = textField.Text.Substring(positionofcursor, 1);
int j = maskCharacters.IndexOf(characterInPosition);
}else
{
break;
}
} while (maskCharacters.IndexOf(characterInPosition) > -1);
if (positionofcursor > -1)
{
StringBuilder sb = new StringBuilder(textField.Text);
sb[positionofcursor] = char.Parse("_");
textField.Text = sb.ToString();
NSRange therange = new NSRange(positionofcursor, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
}
return Int32.TryParse(newText, out val);
}
}
I have made an application, with Watson Assistant, speech-to-text and text to speech in Unity, where the user can say different cities to find available air plane tickets between said cities. The conversation and interactions are working great, but sometimes I have the problem that some cities aren't recognised when the user says them. For example Berlin, sometimes it understands Berlin and another time burning. The same goes for other cities like Paris, London and Jakarta.
So the detection of city names isn't always as accurate as I had hoped. But I saw in some posts that you can make your own custom model to improve the detection of those words. But I have no idea how to set that up, make an own custom model and how to add those cities to the model and train it. Is it possible to do that in Unity C# scripting and how would i start with it? Are there some C# examples that I can look at? Any help would be appreciated.
These are some links and information that I found, but have no idea of how to implement it in C# and for my own purpose in relation of improving the accuracy of city detection.
DwAnswers1 DwAnswers2 StackOverflow IBM clouds docs Medium cURL tutorial
This is the C# script I have for my interaction between the Watson API and Unity. I think i have to add the custom model in here too, but I don't know if i should create the custom model in it too, or if it needs to be in a seperate script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.TextToSpeech.v1;
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;
using IBM.Watson.DeveloperCloud.Services.ToneAnalyzer.v3;
using IBM.Watson.DeveloperCloud.Services.SpeechToText.v1;
using IBM.Watson.DeveloperCloud.Logging;
using IBM.Watson.DeveloperCloud.Utilities;
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.DataTypes;
using MiniJSON;
using UnityEngine.UI;
using FullSerializer;
public class WatsonAgent : MonoBehaviour
{
public string literalEntityCity;
public string destinationCity;
public string departureCity;
public string dateBegin;
public string dateEnd;
public WeatherJSON weather;
public GameObject FlightInfo;
[SerializeField]
private fsSerializer _serializer = new fsSerializer();
[System.Serializable]
public class CredentialInformation
{
public string username, password, url;
}
[System.Serializable]
public class Services
{
public CredentialInformation
textToSpeech,
conversation,
speechToText;
}
[Header("Credentials")]
[Space]
public Services
serviceCredentials;
[Space]
[Header("Agent voice settings")]
[Space]
public AudioSource
voiceSource;
public VoiceType
voiceType;
[Space]
[Header("Conversation settings")]
[Space]
public string
workspaceId;
[Space]
[Header("Feedback fields")]
[Space]
public Text
speechToTextField;
public Text
conversationInputField;
public Text
conversationOutputField;
public string
saying;
// services
SpeechToText
speechToText;
private int
recordingRoutine = 0,
recordingBufferSize = 1,
recordingHZ = 22050;
private string
microphoneID = null;
private AudioClip
recording = null;
TextToSpeech
textToSpeech;
Conversation
conversation;
private Dictionary<string, object>
conversationContext = null;
private void Start()
{
PrepareCredentials();
Initialize();
}
void PrepareCredentials()
{
speechToText = new SpeechToText(GetCredentials(serviceCredentials.speechToText));
textToSpeech = new TextToSpeech(GetCredentials(serviceCredentials.textToSpeech));
conversation = new Conversation(GetCredentials(serviceCredentials.conversation));
}
Credentials GetCredentials(CredentialInformation credentialInformation)
{
return new Credentials(credentialInformation.username, credentialInformation.password, credentialInformation.url);
}
void Initialize()
{
conversation.VersionDate = "2017-05-26";
Active = true;
StartRecording();
}
// speech to text
public bool Active
{
get { return speechToText.IsListening; }
set
{
if (value && !speechToText.IsListening)
{
speechToText.DetectSilence = true;
speechToText.EnableWordConfidence = true;
speechToText.EnableTimestamps = true;
speechToText.SilenceThreshold = 0.01f;
speechToText.MaxAlternatives = 0;
speechToText.EnableInterimResults = true;
speechToText.OnError = OnSpeechError;
speechToText.InactivityTimeout = -1;
speechToText.ProfanityFilter = false;
speechToText.SmartFormatting = true;
speechToText.SpeakerLabels = false;
speechToText.WordAlternativesThreshold = null;
speechToText.StartListening(OnSpeechRecognize);
//speechToText.CustomizationId = "customID"; // I guess i have to add the custom training model here with the customID
//speechToText.CustomizationWeight(0.2); //
}
else if (!value && speechToText.IsListening)
{
speechToText.StopListening();
}
}
}
private void StartRecording()
{
if (recordingRoutine == 0)
{
UnityObjectUtil.StartDestroyQueue();
recordingRoutine = Runnable.Run(RecordingHandler());
}
}
private void StopRecording()
{
if (recordingRoutine != 0)
{
Microphone.End(microphoneID);
Runnable.Stop(recordingRoutine);
recordingRoutine = 0;
}
}
private void OnSpeechError(string error)
{
Active = false;
Log.Debug("ExampleStreaming.OnError()", "Error! {0}", error);
}
private IEnumerator RecordingHandler()
{
recording = Microphone.Start(microphoneID, true, recordingBufferSize, recordingHZ);
yield return null; // let _recordingRoutine get set..
if (recording == null)
{
StopRecording();
yield break;
}
bool bFirstBlock = true;
int midPoint = recording.samples / 2;
float[] samples = null;
while (recordingRoutine != 0 && recording != null)
{
int writePos = Microphone.GetPosition(microphoneID);
if (writePos > recording.samples || !Microphone.IsRecording(microphoneID))
{
Debug.Log("Microphone disconnected.");
StopRecording();
yield break;
}
if ((bFirstBlock && writePos >= midPoint) || (!bFirstBlock && writePos < midPoint))
{
// front block is recorded, make a RecordClip and pass it onto our callback.
samples = new float[midPoint];
recording.GetData(samples, bFirstBlock ? 0 : midPoint);
AudioData record = new AudioData();
record.MaxLevel = Mathf.Max(Mathf.Abs(Mathf.Min(samples)), Mathf.Max(samples));
record.Clip = AudioClip.Create("Recording", midPoint, recording.channels, recordingHZ, false);
record.Clip.SetData(samples, 0);
speechToText.OnListen(record);
bFirstBlock = !bFirstBlock;
}
else
{
// calculate the number of samples remaining until we ready for a block of audio,
// and wait that amount of time it will take to record.
int remaining = bFirstBlock ? (midPoint - writePos) : (recording.samples - writePos);
float timeRemaining = (float)remaining / (float)recordingHZ;
yield return new WaitForSeconds(timeRemaining);
}
}
yield break;
}
private void OnSpeechRecognize(SpeechRecognitionEvent result, Dictionary<string, object> customData)
{
if (result != null && result.results.Length > 0)
{
foreach (var res in result.results)
{
foreach (var alt in res.alternatives)
{
string text = string.Format("{0} ({1}, {2:0.00})\n", alt.transcript, res.final ? "Final" : "Interim", alt.confidence);
if (speechToTextField != null)
{
speechToTextField.text = text;
}
if (res.final)
{
if (characterState == SocialState.listening)
{
Debug.Log("WATSON | Speech to text recorded: \n" + alt.transcript);
StartCoroutine(Message(alt.transcript));
}
}
else
{
if (characterState == SocialState.idle)
{
characterState = SocialState.listening;
}
}
}
}
}
}
// text to speech
private IEnumerator Synthesize(string text)
{
Debug.Log("WATSON CALL | Synthesize input: \n" + text);
textToSpeech.Voice = voiceType;
bool doSynthesize = textToSpeech.ToSpeech(HandleSynthesizeCallback, OnFail, text, true);
if (doSynthesize)
{
StartCoroutine(Analyze(text));
saying = text;
characterState = SocialState.talking;
}
yield return null;
}
void HandleSynthesizeCallback(AudioClip clip, Dictionary<string, object> customData = null)
{
if (Application.isPlaying && clip != null)
{
voiceSource.clip = clip;
voiceSource.Play();
}
}
// conversation
private IEnumerator Message(string text)
{
Debug.Log("WATSON | Conversation input: \n" + text);
MessageRequest messageRequest = new MessageRequest()
{
input = new Dictionary<string, object>()
{
{ "text", text }
},
context = conversationContext
};
bool doMessage = conversation.Message(HandleMessageCallback, OnFail, workspaceId, messageRequest);
if (doMessage)
{
characterState = SocialState.thinking;
if (conversationInputField != null)
{
conversationInputField.text = text;
}
}
yield return null;
}
void HandleMessageCallback(object resp, Dictionary<string, object> customData)
{
object _tempContext = null;
(resp as Dictionary<string, object>).TryGetValue("context", out _tempContext);
if (_tempContext != null)
conversationContext = _tempContext as Dictionary<string, object>;
string contextList = conversationContext.ToString();
Dictionary<string, object> dict = Json.Deserialize(customData["json"].ToString()) as Dictionary<string, object>;
Dictionary<string, object> output = dict["output"] as Dictionary<string, object>;
Debug.Log("JSON INFO: " + customData["json"].ToString());
// Send new/update context variables to the Watson Conversation Service
if (weather.temperatureCity != null && !conversationContext.ContainsKey("temperature"))
{
string currentTemperature = weather.temperatureNumber.ToString();
conversationContext.Add("temperature", currentTemperature);
}
else if (conversationContext.ContainsKey("temperature"))
{
string currentTemperature = weather.temperatureNumber.ToString();
conversationContext.Remove("temperature");
conversationContext.Add("temperature", currentTemperature);
//Debug.Log("Current Temperature: " + currentTemperature);
}
// $ call context variables
var context = dict["context"] as Dictionary<string, object>;
if (context["destination_city"] != null)
{
destinationCity = context["destination_city"].ToString();
Debug.Log("Destination city: " + destinationCity);
}
if (context["departure_city"] != null)
{
departureCity = context["departure_city"].ToString();
}
List<object> text = output["text"] as List<object>;
string answer = text[0].ToString(); //Geeft alleen de eerste response terug
Debug.Log("WATSON | Conversation output: \n" + answer);
if (conversationOutputField != null)
{
conversationOutputField.text = answer;
}
fsData fsdata = null;
fsResult r = _serializer.TrySerialize(resp.GetType(), resp, out fsdata);
if (!r.Succeeded)
{
throw new WatsonException(r.FormattedMessages);
}
//convert fsdata to MessageResponse
MessageResponse messageResponse = new MessageResponse();
object obj = messageResponse;
r = _serializer.TryDeserialize(fsdata, obj.GetType(), ref obj);
if (!r.Succeeded)
{
throw new WatsonException(r.FormattedMessages);
}
if (resp != null)
{
//Recognize intents & entities
if (messageResponse.intents.Length > 0 && messageResponse.entities.Length > 0)
{
string intent = messageResponse.intents[0].intent;
string entity = messageResponse.entities[0].entity;
string literalEntity = messageResponse.entities[0].value;
if (entity == "city")
{
literalEntityCity = literalEntity;
}
if (intent == "weather" && entity == "city")
{
literalEntityCity = literalEntity;
}
}
if (messageResponse.intents.Length > 0)
{
string intent = messageResponse.intents[0].intent;
//Debug.Log("Intent: " + intent); //intent name
}
if (messageResponse.entities.Length > 0)
{
string entity = messageResponse.entities[0].entity;
//Debug.Log("Entity: " + entity); //entity name
string literalEntity = messageResponse.entities[0].value;
//Debug.Log("Entity Literal: " + literalEntity); //literal spoken entity
if (entity == "city")
{
literalEntityCity = literalEntity;
}
}
}
StartCoroutine(Synthesize(answer));
}
}
The question you are asked is rather complex. I believe if you train a model, it should be using tools from Watson and nothing related with Unity.
But, what you can do in Unity is correcting the return word. That is, if you are expecting to get just names of cities, you can download a list of all the cities, let's say with more than 100.000 inhabitants (you can find this on Internet already), then you check if the returned word is in this list. For example:
http://download.geonames.org/export/dump/
In case it is not, you can consider it was poorly detected by Watson, so you can use something like Levenshtein distance to correct your returned word. Check this
Basically this algorithm tries to find how different two words are. It is possible to use other algorithms to check a given word, which is the most similar to it in a list. You may get some ideas from here or this other one
I have an ExampleSstreaming class which actually I got from GitHub of IBM Watson SDK (speech to text service demo). Here it is
public class ExampleStreaming : MonoBehaviour
{
private int m_RecordingRoutine = 0;
private string m_MicrophoneID = null;
private AudioClip m_Recording = null;
private int m_RecordingBufferSize = 5;
private int m_RecordingHZ = 22050;
private SpeechToText m_SpeechToText = new SpeechToText();
void Start()
{
LogSystem.InstallDefaultReactors();
Log.Debug("ExampleStreaming", "Start();");
Active = true;
Debug.Log("start");
StartRecording();
}
public void Update() {
Debug.Log(m_SpeechToText.IsListening);
}
public bool Active
{
get { return m_SpeechToText.IsListening; }
set
{
if (value && !m_SpeechToText.IsListening)
{
m_SpeechToText.DetectSilence = true;
m_SpeechToText.EnableWordConfidence = false;
m_SpeechToText.EnableTimestamps = false;
m_SpeechToText.SilenceThreshold = 0.03f;
m_SpeechToText.MaxAlternatives = 1;
m_SpeechToText.EnableContinousRecognition = true;
m_SpeechToText.EnableInterimResults = true;
m_SpeechToText.OnError = OnError;
m_SpeechToText.StartListening(OnRecognize);
}
else if (!value && m_SpeechToText.IsListening)
{
m_SpeechToText.StopListening();
}
}
}
private void StartRecording()
{
if (m_RecordingRoutine == 0)
{
Debug.Log("m_RecordingRoutine");
UnityObjectUtil.StartDestroyQueue();
m_RecordingRoutine = Runnable.Run(RecordingHandler());
}
}
private void StopRecording()
{
if (m_RecordingRoutine != 0)
{
Microphone.End(m_MicrophoneID);
Runnable.Stop(m_RecordingRoutine);
m_RecordingRoutine = 0;
}
}
private void OnError(string error)
{
Active = false;
Log.Debug("ExampleStreaming", "Error! {0}", error);
}
private IEnumerator RecordingHandler()
{
Log.Debug("ExampleStreaming", "devices: {0}", Microphone.devices);
m_MicrophoneID = Microphone.devices[0];
Debug.Log("m_MicrophoneID : " + m_MicrophoneID);
m_Recording = Microphone.Start(m_MicrophoneID, true, m_RecordingBufferSize, m_RecordingHZ);
yield return null; // let m_RecordingRoutine get set..
Debug.Log("m_Recording : " + m_Recording.length);
if (m_Recording == null)
{
Debug.Log("m_Recording is null");
StopRecording();
yield break;
}
bool bFirstBlock = true;
int midPoint = m_Recording.samples / 2;
float[] samples = null;
while (m_RecordingRoutine != 0 && m_Recording != null)
{
int writePos = Microphone.GetPosition(m_MicrophoneID);
if (writePos > m_Recording.samples || !Microphone.IsRecording(m_MicrophoneID))
{
Log.Error("MicrophoneWidget", "Microphone disconnected.");
StopRecording();
yield break;
}
if ((bFirstBlock && writePos >= midPoint)
|| (!bFirstBlock && writePos < midPoint))
{
// front block is recorded, make a RecordClip and pass it onto our callback.
samples = new float[midPoint];
m_Recording.GetData(samples, bFirstBlock ? 0 : midPoint);
AudioData record = new AudioData();
record.MaxLevel = Mathf.Max(samples);
record.Clip = AudioClip.Create("Recording", midPoint, m_Recording.channels, m_RecordingHZ, false);
record.Clip.SetData(samples, 0);
m_SpeechToText.OnListen(record);
bFirstBlock = !bFirstBlock;
}
else
{
// calculate the number of samples remaining until we ready for a block of audio,
// and wait that amount of time it will take to record.
int remaining = bFirstBlock ? (midPoint - writePos) : (m_Recording.samples - writePos);
float timeRemaining = (float)remaining / (float)m_RecordingHZ;
yield return new WaitForSeconds(timeRemaining);
}
}
yield break;
}
private void OnRecognize(SpeechRecognitionEvent result)
{
Debug.Log("OnRecognize");
if (result != null && result.results.Length > 0)
{
foreach (var res in result.results)
{
foreach (var alt in res.alternatives)
{
string text = alt.transcript;
Debug.Log(text);
Log.Debug("ExampleStreaming", string.Format("{0} ({1}, {2:0.00})\n", text, res.final ? "Final" : "Interim", alt.confidence));
}
}
}
}
}
and this is the line i add to get microphone. I just edit it to provide Microphone Device at zero index which was actually null (I don't know why, is this intentionally left or an error), in the function RecordingHandler .
m_MicrophoneID = Microphone.devices[0];
but unfortunately it is not showing any output log in EventOnRecognize which i think that it should execute.
Wile it displaying these logs, after some seconds (as i given length 5 of the audio). What i am doing wrong, i am unable to understand that how speech to text.
[DEBUG] OnListenClosed(), State = DISCONNECTED
[DEBUG] KeepAlive exited.
I have also tried IBM Watson Speech To text Scene it is also not showing anything.
I am not able to stream real-time output yet but become able to convert audio clip into text through watson service and here is the simple code (which took three days).
using UnityEngine;
using System.Collections;
using IBM.Watson.DeveloperCloud.Services.SpeechToText.v1;
public class AudioClipToTextWatson : MonoBehaviour {
// Non-streaming
SpeechToText m_SpeechToText = new SpeechToText();
public AudioClip m_AudioClip = new AudioClip();
public bool on = false;
void Start () {
m_AudioClip = Microphone.Start(Microphone.devices[0], false, 4, 44100);
m_SpeechToText.Recognize(m_AudioClip, OnRecognize);
// Streaming
m_SpeechToText.StartListening(OnRecognize);
// Stop listening
m_SpeechToText.StopListening();
}
private void OnRecognize(SpeechRecognitionEvent result)
{
Debug.Log("result : " + result);
if (result != null && result.results.Length > 0)
{
foreach (var res in result.results)
{
foreach (var alt in res.alternatives)
{
string text = alt.transcript;
Debug.Log(text);
Debug.Log(res.final);
}
}
}
}
}
Note :You can record and an audio clip using your microphone and convert it to text. If you already have an audio then drop it to inspector and comment out the first line in Start Event.
I solved Error
I encounter the same issue with Unity 2018.3.14f1.
I just change player settings and then works fine
file -> build settings - > player settings -> Other Settings
Configuration
Scripting runtime version : .Net 4x equivalent
API Compatibility level: .Net 4x
I'm trying to use Uri.IsWellFormedUriString but it doesn't work, and question is - why:
class Program
{
static void Main()
{
Console.WriteLine(IsWellFormed(#"C:\Windows"));
Console.WriteLine(IsWellFormed(#"C:\\:\\//Windows32"));
}
public static bool IsWellFormed(string path)
{
string uriString = "file:///" + path;
string wellFormed = uriString.Replace('\\', '/');
return Uri.IsWellFormedUriString(wellFormed, UriKind.Absolute);
}
}
expected true false output but it returns true in both cases. And I'm really confused a bit.
Here is an approach without try/catch, though it may not be optimal:
public static bool IsWellFormed(string path)
{
string path = "C:\\windows\\:ppz";
var isRooted = Path.IsPathRooted(path);
var root = Path.GetPathRoot(path);
var list = path.Split(new char[] {Path.DirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < list.Length; i ++)
{
if(i == 0 && isRooted && s[i]+"\\" == root) continue;
if (s[i].Intersect(Path.GetInvalidPathChars()).Count() != 0)
return false;
if (s[i].Intersect(Path.GetInvalidFileNameChars()).Count() != 0)
return false;
}
return true;
}
You can play with your values and see if this fits your task. You can also customize your own lists for invalid chars.
Question:
I'm writing a custom session provider.
So far it works excellently.
I decided I wanted to add a customized ISessionIDManager, to control the session id.
It already works fine for cookie sessions.
But when I swich to cookieless, like this:
<sessionState mode="Custom" customProvider="custom_provider" cookieless="true" timeout="1"
sessionIDManagerType="Samples.AspNet.Session.MySessionIDManager"
sqlConnectionString="Data Source=localhost;Initial Catalog=TestDB;User Id=SomeUser;Password=SomePassword;"
sqlCommandTimeout="10"
>
<!-- timeout in minutes-->
<providers>
<add name="custom_provider" type="Test.WebSession.CustomSessionStoreProvider" />
</providers>
</sessionState>
Then it redirects to:
http://localhost:52897/(77bb065f-d2e9-4cfc-8117-8b89a40e00d8)/default.aspx
and this throws HTTP 404.
I understand why, as there is no such folder.
But when you use the default session manager (the one that ships with asp.net), and switch to cookieless, the URL looks like this:
http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx
and there is no HTTP 404...
I tried adding the (S and ) to my session-id in brackets in the url, but that didn't help.
What am I missing ?
using System;
using System.Configuration;
using System.Web.Configuration;
using System.Web;
using System.Web.SessionState;
// http://allantech.blogspot.com/2011/04/cookieless-session-state-in-aspnet.html
// http://forums.asp.net/t/1082784.aspx/1
// http://stackoverflow.com/questions/4612310/implementing-a-custom-sessionidmanager
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager.aspx
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager(v=vs.80).aspx
namespace Samples.AspNet.Session
{
// Samples.AspNet.Session.MySessionIDManager
public class MySessionIDManager : IHttpModule, ISessionIDManager
{
protected SessionStateSection pConfig = null;
internal const string HeaderName = "AspFilterSessionId";
protected void InitializeModule()
{
// Obtain session-state configuration settings.
if (pConfig == null)
{
Configuration cfg =
WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");
} // End if (pConfig == null)
}
//
// IHttpModule Members
//
//
// IHttpModule.Init
//
public void Init(HttpApplication app)
{
//InitializeModule();
} // End Sub Init
//
// IHttpModule.Dispose
//
public void Dispose()
{
} // End Sub Dispose
//
// ISessionIDManager Members
//
//
// ISessionIDManager.Initialize
//
public void Initialize()
{
InitializeModule();
} // End Sub Initialize
//
// ISessionIDManager.InitializeRequest
//
public bool InitializeRequest(
HttpContext context,
bool suppressAutoDetectRedirect,
out bool supportSessionIDReissue
)
{
if (pConfig.Cookieless == HttpCookieMode.UseCookies)
{
supportSessionIDReissue = false;
return false;
}
else
{
supportSessionIDReissue = true;
return context.Response.IsRequestBeingRedirected;
}
} // End Function InitializeRequest
//
// ISessionIDManager.GetSessionID
//
public string GetSessionID(HttpContext context)
{
string id = null;
if (pConfig.Cookieless == HttpCookieMode.UseUri)
{
string tmp = context.Request.Headers[HeaderName];
if (tmp != null)
id = HttpUtility.UrlDecode(id);
// Retrieve the SessionID from the URI.
}
else
{
if (context.Request.Cookies.Count > 0)
{
id = context.Request.Cookies[pConfig.CookieName].Value;
id = HttpUtility.UrlDecode(id);
}
}
// Verify that the retrieved SessionID is valid. If not, return null.
if (!Validate(id))
id = null;
return id;
} // End Function GetSessionID
//
// ISessionIDManager.CreateSessionID
//
public string CreateSessionID(HttpContext context)
{
return System.Guid.NewGuid().ToString();
} // End Function CreateSessionID
//
// ISessionIDManager.RemoveSessionID
//
public void RemoveSessionID(HttpContext context)
{
context.Response.Cookies.Remove(pConfig.CookieName);
} // End Sub RemoveSessionID
public static string InsertSessionId(string id, string path)
{
string dir = GetDirectory(path);
if (!dir.EndsWith("/"))
dir += "/";
string appvpath = HttpRuntime.AppDomainAppVirtualPath;
if (!appvpath.EndsWith("/"))
appvpath += "/";
if (path.StartsWith(appvpath))
path = path.Substring(appvpath.Length);
if (path[0] == '/')
path = path.Length > 1 ? path.Substring(1) : "";
// //http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx
return Canonic(appvpath + "(" + id + ")/" + path);
//return Canonic(appvpath + "(S(" + id + "))/" + path);
}
public static bool IsRooted(string path)
{
if (path == null || path.Length == 0)
return true;
char c = path[0];
if (c == '/' || c == '\\')
return true;
return false;
}
public static string Canonic(string path)
{
char[] path_sep = { '\\', '/' };
bool isRooted = IsRooted(path);
bool endsWithSlash = path.EndsWith("/");
string[] parts = path.Split(path_sep);
int end = parts.Length;
int dest = 0;
for (int i = 0; i < end; i++)
{
string current = parts[i];
if (current.Length == 0)
continue;
if (current == ".")
continue;
if (current == "..")
{
dest--;
continue;
}
if (dest < 0)
if (!isRooted)
throw new HttpException("Invalid path.");
else
dest = 0;
parts[dest++] = current;
}
if (dest < 0)
throw new HttpException("Invalid path.");
if (dest == 0)
return "/";
string str = String.Join("/", parts, 0, dest);
str = RemoveDoubleSlashes(str);
if (isRooted)
str = "/" + str;
if (endsWithSlash)
str = str + "/";
return str;
}
public static string GetDirectory(string url)
{
url = url.Replace('\\', '/');
int last = url.LastIndexOf('/');
if (last > 0)
{
if (last < url.Length)
last++;
return RemoveDoubleSlashes(url.Substring(0, last));
}
return "/";
}
public static string RemoveDoubleSlashes (string input)
{
// MS VirtualPathUtility removes duplicate '/'
int index = -1;
for (int i = 1; i < input.Length; i++)
if (input [i] == '/' && input [i - 1] == '/') {
index = i - 1;
break;
}
if (index == -1) // common case optimization
return input;
System.Text.StringBuilder sb = new System.Text.StringBuilder(input.Length);
sb.Append (input, 0, index);
for (int i = index; i < input.Length; i++) {
if (input [i] == '/') {
int next = i + 1;
if (next < input.Length && input [next] == '/')
continue;
sb.Append ('/');
}
else {
sb.Append (input [i]);
}
}
return sb.ToString ();
}
// http://www.dotnetfunda.com/articles/article1531-how-to-add-custom-headers-into-readonly-httprequest-object-using-httpmodule-.aspx
public void SetHeader(string strHeaderName, string strValue)
{
//get a reference
System.Collections.Specialized.NameValueCollection headers = HttpContext.Current.Request.Headers;
//get a type
Type t = headers.GetType();
//get the property
System.Reflection.PropertyInfo prop = t.GetProperty(
"IsReadOnly",
System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.IgnoreCase
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.FlattenHierarchy
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.FlattenHierarchy
);
//unset readonly
prop.SetValue(headers, false, null); // Set Read-Only to false
//add a header
//HttpContext.Current.Request.Headers.Add(strHeaderName, strValue);
//headers.Add(strHeaderName, strValue);
t.InvokeMember("BaseAdd",
System.Reflection.BindingFlags.InvokeMethod
| System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance,
null,
headers,
new object[] { strHeaderName, new System.Collections.ArrayList { strValue } }
);
prop.SetValue(headers, true, null); // Reset Read-Only to true
// Victory !
//string strCheckHeaders = string.Join(Environment.NewLine, HttpContext.Current.Request.Headers.AllKeys);
}
//
// ISessionIDManager.SaveSessionID
//
public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
if (!Validate(id))
throw new HttpException("Invalid session ID");
Type t = base.GetType();
redirected = false;
cookieAdded = false;
if (pConfig.Cookieless == HttpCookieMode.UseUri)
{
// Add the SessionID to the URI. Set the redirected variable as appropriate.
//context.Request.Headers.Add(HeaderName, id);
//context.Request.Headers.Set(HeaderName, id);
SetHeader(HeaderName, id);
cookieAdded = false;
redirected = true;
UriBuilder newUri = new UriBuilder(context.Request.Url);
newUri.Path = InsertSessionId(id, context.Request.FilePath);
//http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx
context.Response.Redirect(newUri.Uri.PathAndQuery, false);
context.ApplicationInstance.CompleteRequest(); // Important !
return;
}
else
{
context.Response.Cookies.Add(new HttpCookie(pConfig.CookieName, id));
cookieAdded = true;
}
} // End Sub SaveSessionID
//
// ISessionIDManager.Validate
//
public bool Validate(string id)
{
try
{
Guid testGuid = new Guid(id);
if (id == testGuid.ToString())
return true;
}
catch
{
}
return false;
} // End Function Validate
} // End Class MySessionIDManager : IHttpModule, ISessionIDManager
} // End Namespace Samples.AspNet.Session
Creating a custom session id manager from scratch seems like a lot of work. What about inheriting from System.Web.SessionState.SessionIDManager class and overriding the CreateSessionID method?
public class MySessionIDManager : SessionIDManager, ISessionIDManager
{
public override string CreateSessionID(HttpContext context)
{
return System.Guid.NewGuid().ToString("N");
}
}
When all else fails, crack open the .NET implementation with Reflector or ILSpy and see what they are doing different.