Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
caiqinghua committed Jul 18, 2023
2 parents 1a7c584 + bd45155 commit 7d274fb
Show file tree
Hide file tree
Showing 20 changed files with 203 additions and 85 deletions.
11 changes: 5 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
DATABASE_URL=sqlite:///./test.db

# LLM
# "OPENAI" or "ANTHROPIC"(optional)
LLM_USE=OPENAI
# "gpt-4" or "gpt-3.5-turbo-16k" or claude-instant-1 or claude-2
LLM_MODEL_USE=gpt-3.5-turbo-16k

# This section for Azure OpenAI API
#OPENAI_API_TYPE=azure
Expand All @@ -13,12 +13,11 @@ LLM_USE=OPENAI
#OPENAI_API_MODEL_DEPLOYMENT_NAME=gpt-35-turbo
#OPENAI_API_EMBEDDING_DEPLOYMENT_NAME=text-embedding-ada-002

# gpt-4 for better character control
# gpt-3.5-turbo-16k for better speed
OPENAI_API_KEY=YOUR_API_KEY
# gpt-4 or gpt-3.5-turbo-16k
OPENAI_MODEL=gpt-3.5-turbo-16k
ANTHROPIC_API_KEY=YOUR_API_KEY
# claude-instant-1 or claude-2
ANTHROPIC_MODEL=claude-2
ANTHROPIC_API_KEY=YOUR_API_KEY

# Speech to text
# "LOCAL_WHISPER" or "OPENAI_WHISPER"(optional) or "GOOGLE"(optional)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ The OpenAIEmbeddings model deployment name for your Azure OpenAI resource.
### 1.1 (Optional) Prepare LLM - Anthropic(Claude 2) API Token
<details><summary>👇click me</summary>

To get your OpenAI API token, follow these steps:
To get your Anthropic API token, follow these steps:

1. Go to the [Anthropic website](https://docs.anthropic.com/claude/docs/getting-started-with-claude) and sign up for an account if you haven't already.
2. Once you're logged in, navigate to the [API keys page](https://console.anthropic.com/account/keys).
Expand Down
26 changes: 26 additions & 0 deletions alembic/versions/9ed6d1431c1d_add_platform_and_action_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""add platform and action types
Revision ID: 9ed6d1431c1d
Revises: 0f355a71adbb
Create Date: 2023-07-18 00:31:05.044828
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '9ed6d1431c1d'
down_revision = '0f355a71adbb'
branch_labels = None
depends_on = None


def upgrade() -> None:
op.add_column('interactions', sa.Column('platform', sa.String(50), nullable=True))
op.add_column('interactions', sa.Column('action_type', sa.String(50), nullable=True))


def downgrade() -> None:
op.drop_column('interactions', 'platform')
op.drop_column('interactions', 'action_type')
20 changes: 18 additions & 2 deletions client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,25 @@ async def receive_message(websocket):
break


def select_model():
llm_model_selection = input(
'1: gpt-3.5-turbo-16k \n'
'2: gpt-4 \n'
'3: claude-2 \n'
'Select llm model:')
if llm_model_selection == '1':
llm_model = 'gpt-3.5-turbo-16k'
elif llm_model_selection == '2':
llm_model = 'gpt-4'
elif llm_model_selection == '3':
llm_model = 'claude-2'
return llm_model


async def start_client(client_id, url):
api_key = os.getenv('AUTH_API_KEY')
uri = f"ws://{url}/ws/{client_id}?api_key={api_key}"
llm_model = select_model()
uri = f"ws://{url}/ws/{client_id}?api_key={api_key}&llm_model={llm_model}"
async with websockets.connect(uri) as websocket:
# send client platform info
await websocket.send('terminal')
Expand All @@ -176,7 +192,7 @@ async def start_client(client_id, url):


async def main(url):
client_id = random.randint(0, 1000)
client_id = random.randint(0, 1000000)
task = asyncio.create_task(start_client(client_id, url))
try:
await task
Expand Down
19 changes: 10 additions & 9 deletions client/mobile/ios/rac/rac/Interactive/InteractiveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct InteractiveView: View {
static let serverError: String = "Disconnected, try again later."
}

let webSocketClient: WebSocketClient
let webSocket: any WebSocket
let character: CharacterOption?
let openMic: Bool
let hapticFeedback: Bool
Expand All @@ -44,7 +44,7 @@ struct InteractiveView: View {
onSendUserMessage: { message in
voiceState = .idle(streamingEnded: false)
messages.append(.init(id: UUID(), role: .user, content: message))
webSocketClient.send(message: message)
webSocket.send(message: message)
complexSuccess()
})
.padding(.horizontal, 48)
Expand All @@ -65,7 +65,7 @@ struct InteractiveView: View {
}
},
onSendUserMessage: { message in
webSocketClient.send(message: message)
webSocket.send(message: message)
simpleSuccess()
},
onTapVoiceButton: {
Expand Down Expand Up @@ -136,10 +136,10 @@ struct InteractiveView: View {
if messages.isEmpty {
// TODO: Allow user to provide first message
messages.append(.init(id: UUID(), role: .user, content: Constants.greeting))
webSocketClient.send(message: Constants.greeting)
webSocket.send(message: Constants.greeting)
}
webSocketClient.isInteractiveMode = true
webSocketClient.onStringReceived = { message in
webSocket.isInteractiveMode = true
webSocket.onStringReceived = { message in
guard !(openMic && voiceState == .listeningToUser) else { return }

if message == "[end]\n" {
Expand Down Expand Up @@ -167,19 +167,20 @@ struct InteractiveView: View {
lightHapticFeedback()
}
}
webSocketClient.onDataReceived = { data in
webSocket.onDataReceived = { data in
if mode == .voice, case .characterSpeaking = voiceState {
audioPlayer.playAudio(data: data)
}
}
webSocketClient.onCharacterOptionsReceived = { _ in
webSocket.onCharacterOptionsReceived = { _ in
if messages.last?.content != Constants.serverError {
messages.append(.init(id: UUID(), role: .assistant, content: Constants.serverError))
simpleError()
}
}
}
.onDisappear {
voiceState = .idle(streamingEnded: true)
audioPlayer.pauseAudio()
}
.onChange(of: voiceState) { newValue in
Expand Down Expand Up @@ -274,7 +275,7 @@ struct InteractiveView: View {

struct InteractiveView_Previews: PreviewProvider {
static var previews: some View {
InteractiveView(webSocketClient: WebSocketClient(),
InteractiveView(webSocket: MockWebSocket(),
character: .init(id: 0, name: "Name", description: "Description", imageUrl: nil),
openMic: false,
hapticFeedback: false,
Expand Down
59 changes: 47 additions & 12 deletions client/mobile/ios/rac/rac/Network/WebSocketClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,27 @@ import SwiftUI
//let serverUrl: URL = URL(string: "http://127.0.0.1:8000/")!
let serverUrl: URL = URL(string: "https://realchar.ai/")!

class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
protocol WebSocket: NSObject, ObservableObject {
var isConnected: Bool { get set }
var isInteractiveMode: Bool { get set }
var onConnectionChanged: ((Bool) -> Void)? { get set }
var onStringReceived: ((String) -> Void)? { get set }
var onCharacterOptionsReceived: (([CharacterOption]) -> Void)? { get set }
var onDataReceived: ((Data) -> Void)? { get set }
func connectSession()
func closeSession()
func send(message: String)
}

class WebSocketClient: NSObject, WebSocket, URLSessionWebSocketDelegate {

private var webSocket: URLSessionWebSocketTask!
@Published var isConnected: Bool = false
@Published var isInteractiveMode: Bool = false
var isConnected: Bool = false
var isInteractiveMode: Bool = false

var onConnectionChanged: ((Bool) -> Void)?

var lastStrMessage: String? = nil
private var lastStrMessage: String? = nil
var onStringReceived: ((String) -> Void)? {
didSet {
if let lastStrMessage, let onStringReceived {
Expand All @@ -29,7 +43,7 @@ class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
}
}

var lastCharacterOptions: [CharacterOption]? = nil
private var lastCharacterOptions: [CharacterOption]? = nil
var onCharacterOptionsReceived: (([CharacterOption]) -> Void)? {
didSet {
if let lastCharacterOptions, let onCharacterOptionsReceived {
Expand All @@ -39,7 +53,7 @@ class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
}
}

var lastData: Data? = nil
private var lastData: Data? = nil
var onDataReceived: ((Data) -> Void)? {
didSet {
if let lastData, let onDataReceived {
Expand Down Expand Up @@ -131,9 +145,8 @@ class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
webSocketTask: URLSessionWebSocketTask,
didOpenWithProtocol protocol: String?) {
print("Connected to server")
DispatchQueue.main.async {
self.isConnected = true
}
isConnected = true
onConnectionChanged?(isConnected)
receive()
send(message: "mobile")
}
Expand All @@ -143,9 +156,8 @@ class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,
reason: Data?) {
print("Disconnect from Server \(String(describing: reason))")
DispatchQueue.main.async {
self.isConnected = false
}
isConnected = false
onConnectionChanged?(isConnected)
}

// MARK: - Private
Expand Down Expand Up @@ -193,3 +205,26 @@ class WebSocketClient: NSObject, URLSessionWebSocketDelegate, ObservableObject {
return firstCharacters.allSatisfy { characterSet.contains(UnicodeScalar(String($0))!) }
}
}

class MockWebSocket: NSObject, WebSocket {
var isConnected: Bool = false

var isInteractiveMode: Bool = false

var onConnectionChanged: ((Bool) -> Void)?

var onStringReceived: ((String) -> Void)?

var onCharacterOptionsReceived: (([CharacterOption]) -> Void)?

var onDataReceived: ((Data) -> Void)?

func connectSession() {
}

func closeSession() {
}

func send(message: String) {
}
}
14 changes: 7 additions & 7 deletions client/mobile/ios/rac/rac/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ struct RootView: View {
@State var openMic: Bool = false
@State var hapticFeedback: Bool = true

let webSocketClient: WebSocketClient
let webSocket: any WebSocket

var body: some View {
NavigationView {
VStack {
if interactive {
InteractiveView(webSocketClient: webSocketClient,
InteractiveView(webSocket: webSocket,
character: character,
openMic: openMic,
hapticFeedback: hapticFeedback,
Expand All @@ -37,7 +37,7 @@ struct RootView: View {
messages: $messages)
.transition(.moveAndFade2)
} else {
WelcomeView(webSocketClient: webSocketClient,
WelcomeView(webSocket: webSocket,
tab: $welcomeTab,
character: $character,
options: $options,
Expand All @@ -46,7 +46,7 @@ struct RootView: View {
onConfirmConfig: { selected in
if shouldSendCharacter {
shouldSendCharacter = false
webSocketClient.send(message: String(selected.id))
webSocket.send(message: String(selected.id))
}
// TODO: figure out why animation does not work well
// withAnimation {
Expand Down Expand Up @@ -91,10 +91,10 @@ struct RootView: View {
}
.navigationViewStyle(StackNavigationViewStyle())
.onAppear {
webSocketClient.connectSession()
webSocket.connectSession()
}
.onDisappear {
webSocketClient.closeSession()
webSocket.closeSession()
}
}
}
Expand Down Expand Up @@ -124,6 +124,6 @@ struct LogoView: View {

struct RootView_Previews: PreviewProvider {
static var previews: some View {
RootView(webSocketClient: WebSocketClient())
RootView(webSocket: MockWebSocket())
}
}
17 changes: 11 additions & 6 deletions client/mobile/ios/rac/rac/SharedUI/CtaButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
import SwiftUI

struct CtaButton: View {
enum Style {
case primary, secondary
}

@Environment(\.colorScheme) var colorScheme

let style: Style
let action: () -> Void
let text: String

Expand All @@ -20,11 +25,11 @@ struct CtaButton: View {
Font.custom("Prompt", size: 18)
.weight(.medium)
)
.foregroundColor(colorScheme == .dark ? .black : .white)
.foregroundColor(style == .primary ? (colorScheme == .dark ? .black : .white) : (colorScheme == .dark ? .white : .black))
.padding(.horizontal, 20)
.padding(.vertical, 9)
.frame(maxWidth: .infinity, minHeight: 52, maxHeight: 52, alignment: .center)
.background(colorScheme == .dark ? .white : Color(red: 0.01, green: 0.03, blue: 0.11))
.background(style == .primary ? (colorScheme == .dark ? .white : Color(red: 0.01, green: 0.03, blue: 0.11)) : (colorScheme == .dark ? Color(red: 0.01, green: 0.03, blue: 0.11) : .white))
.cornerRadius(4)
}
.buttonStyle(CustomButtonStyle())
Expand All @@ -42,18 +47,18 @@ struct CustomButtonStyle: ButtonStyle {

struct CtaButton_Previews: PreviewProvider {
static var previews: some View {
CtaButton(action: { }, text: "Contribute")
CtaButton(style: .primary, action: { }, text: "Contribute")
.padding(20)

CtaButton(action: { }, text: "Contribute")
CtaButton(style: .primary, action: { }, text: "Contribute")
.disabled(true)
.padding(20)

CtaButton(action: { }, text: "Contribute")
CtaButton(style: .primary, action: { }, text: "Contribute")
.preferredColorScheme(.dark)
.padding(20)

CtaButton(action: { }, text: "Contribute")
CtaButton(style: .primary, action: { }, text: "Contribute")
.preferredColorScheme(.dark)
.disabled(true)
.padding(20)
Expand Down

0 comments on commit 7d274fb

Please sign in to comment.