Created
October 22, 2023 16:35
-
-
Save idvorkin/cfa7b482f04aceb040d8822ad95fcabe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ContentView.swift | |
// PlayAVFoundation | |
// | |
// Created by Igor Dvorkin on 10/22/23. | |
// | |
import SwiftUI | |
import AVFoundation | |
import Swifter | |
import Foundation | |
class PersonalSynth{ | |
var invocation=0 | |
let synth = AVSpeechSynthesizer() | |
var personalVoice = AVSpeechSynthesisVoice() | |
public func speak(text:String){ | |
print("\(invocation)> \(text)") | |
let utterance = AVSpeechUtterance(string: text) | |
utterance.voice = personalVoice | |
synth.speak(utterance) | |
print("\(invocation)> done") | |
invocation += 1 | |
} | |
init() | |
{ | |
AVSpeechSynthesizer.requestPersonalVoiceAuthorization(completionHandler: { (result) in | |
print("Complete \(result)") | |
}) | |
for voice in AVSpeechSynthesisVoice.speechVoices() | |
{ | |
if voice.identifier.contains("personalvoice") | |
{ | |
print(voice.identifier) | |
personalVoice = voice | |
return | |
} | |
} | |
print ("Personal Voice not Found") | |
} | |
} | |
let synth = PersonalSynth() | |
class TalkingWebResponder{ | |
init() | |
{ | |
let port:in_port_t = 9007 | |
let server = HttpServer() | |
server["/speak"] = { request in | |
print ("R \(request)") | |
print ("R.QP \(request.queryParams)") | |
print ("R.P \(request.params)") | |
// Do URL decoding, including '+' to ' ' | |
let text_to_speak = String(request.queryParams.first?.1.replacingOccurrences(of:"+",with:" ").removingPercentEncoding ?? "") | |
synth.speak(text:text_to_speak) | |
return HttpResponse.ok(.text(text_to_speak)) | |
} | |
server.listenAddressIPv4="127.0.0.1" // Only listen on locahost | |
do { | |
print ("Starting Server: \(port)") | |
try server.start(port, forceIPv4: true) | |
print ("Ending Server") | |
// without the sleep, the server never runs. | |
sleep(1) | |
} | |
catch | |
{ | |
print("Server Error \(error)") | |
} | |
} | |
public func forceAlive() | |
{ | |
print("Force Alive") | |
} | |
} | |
let webServer = TalkingWebResponder() | |
struct ContentView: View { | |
@State var textInTextBox:String = "Hey, the computer is talking for me" | |
var body: some View { | |
VStack { | |
TextField("Igor in Text Feild", text:$textInTextBox, onEditingChanged: {starting in | |
if !starting { | |
speakText() | |
} | |
}) | |
.frame(maxWidth: .infinity) | |
.font(Font.system(size: 20, design: .default)) | |
Button("Ugly"){ | |
speakText() | |
}.frame(maxWidth: .infinity) | |
} | |
.padding() | |
} | |
func speakText(){ | |
synth.speak(text:textInTextBox) | |
} | |
init() | |
{ | |
webServer.forceAlive() | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment